I am at present creating some replace in our views and we have now a view which is completely made in SwiftUI. This view has ScrollView
, which earlier than we nested a UIViewRepresentable
, it used to scroll to the TextField
, when this area was centered.
struct PinDetailViewSwiftUI {
var physique: some View {
ScrollView {
VStack(spacing: 0) {
GeometryReader { proxy in
let offset = proxy.body(in: .named("scroll")).minY
Shade(GrayColors.gray10.getColor()).desire(key: ViewOffsetKey.self, worth: offset)
}
if pinViewModel.isLoadingData {
PinDetailLoadingViewSwiftUI()
} else {
PinSectionHeaderView(title: DTTaskListTranslate.splitViewTasks.translation)
if !pinViewModel.duties.isEmpty || pinViewModel.tasksHasChanged {
NavigationLink(vacation spot: PinTaskDetailSwiftUI(duties: .fixed(pinViewModel.duties), selectedTask: pinViewModel.preSelectedTask, pin: pinViewModel.pinModel, userRole: challenge.roleType ?? .SubContractor, viewMode: .view, reassign: false), isActive: $pinViewModel.openPreSelectedTask) {
EmptyView()
}.buttonStyle(PlainButtonStyle())
SwiftUI.Group {
TaskPreviewRepresentable(process: pinViewModel.duties[0], userImage: .fixed(nil), userRole: challenge.roleType ?? .SubContractor, viewModel: viewModel)
.body(peak: viewModel.getHeightOfTaskPreview(process: process, userRole: challenge.roleType ?? .SubContractor), alignment: .middle)
}
.animation(.easeInOut)
}
if pinViewModel.pinModel != nil && pinViewModel.userCanCreateTasks() {
NavigationLink(isActive: $pinViewModel.showTaskCreationView) {
PinTaskDetailSwiftUI(duties: $pinViewModel.duties, selectedTask: DTMediaPost.getDefaultTask(pin: pinViewModel.pinModel), pin: pinViewModel.pinModel, userRole: challenge.roleType ?? .SubContractor, viewMode: .create, reassign: false)
} label: {
Button(motion: {
if !pin.isPinClosedOrInactive {
pinViewModel.showTaskCreationView.toggle()
} else {
pinViewModel.showPinClosedAlert.toggle()
}
}, label: {
PinCreateNewTask()
})
}
.body(peak: 50)
}
PinSectionHeaderView(title: DTPinTranslate.pinFieldsHeader.translation)
if !pinViewModel.datasets.isEmpty {
PinDatasetView(linkedDatasets: $pinViewModel.linkedRecords, information: $pinViewModel.datasets, datasetChanged: $pinViewModel.datasetChanged, showPinClosedAlert: $pinViewModel.showPinClosedAlert, pin: pinViewModel.pinModel)
Rectangle()
.body(maxWidth: .infinity)
.body(peak: 1)
.foregroundColor(.grey.opacity(0.2))
.padding([.bottom, .top], 8)
}
if !pinViewModel.pinFields.isEmpty {
SwiftUI.Group {
ForEach(pinViewModel.pinFields, id: .id!) { worth in
swap worth.sort! {
case .quantity:
PinTextFieldView(pinModel: $pinViewModel.pinModel, numberPinField: worth as! DTNumberPinField, canEdit: pinViewModel.pinModel.canPinBeChanged)
case .date:
PinDateView(pin: $pinViewModel.pinModel, dtPinDateField: worth as! DTPinDateField, canEdit: pinViewModel.pinModel.canPinBeChanged)
case .slider:
PinSliderView(pinSliderScale: worth as! DTPinSliderField, pinModel: $pinViewModel.pinModel, categoryColor: $pinViewModel.pinCategoryColor, canEdit: pinViewModel.pinModel.canPinBeChanged)
case .textual content:
PinTextAreaView(textPinField: worth as! DTTextPinField, canEdit: pinViewModel.pinModel.canPinBeChanged, pinModel: $pinViewModel.pinModel)
case .tags:
VStack {
if showTagSuggestions {
PinTagSuggestionView(suggestedTags: $pinViewModel.suggestedTags, recentTags: $pinViewModel.filteredRecentTags, searchedTag: $pinViewModel.currentTagBeingAdded)
.body(peak: pinViewModel.getRecentTagsHeight())
}
PinTagsView(showTagSuggestions: $showTagSuggestions, currentTagBeingAdded: $pinViewModel.currentTagBeingAdded, canBeEdited: pinViewModel.pinModel.canPinBeChanged, tagField: worth, pin: $pinViewModel.pinModel)
}
case .time:
PinTimeFieldView(pinModel: $pinViewModel.pinModel, timePinField: worth as! DTPinTimeField)
}
Rectangle()
.body(maxWidth: .infinity)
.body(peak: 1)
.foregroundColor(.grey.opacity(0.2))
.padding([.bottom, .top], 8)
}
}
}
if !pinViewModel.visualMediaPosts.isEmpty, !isCameraOpened {
PinMediaView(medias: $pinViewModel.visualMediaPosts, pin: pinViewModel.pinModel, numberOfMedias: pinViewModel.numberOfElementsInPin())
.body(peak: pinViewModel.getTotalHeightForMediaSection())
}
if !pinViewModel.mediaPosts.isEmpty,
!isCameraOpened {
PinSectionHeaderView(title: DTSharedTranslate.exercise.translation)
if #obtainable(iOS 16.0, *) {
PinActivityViewList(mediaPosts: pinViewModel.mediaPosts, pin: pinViewModel.pinModel, isLastPage: pinViewModel.isLastPage, pinDetailViewModel: .fixed(pinViewModel), isLoading: pinViewModel.isLoadingMedia, loadNextPage: $pinViewModel.loadNextPage)
.body(peak: pinViewModel.getTotalHeightForActivitySection())
.animation(.easeInOut)
.scrollContentBackground(.hidden)
} else {
PinActivityViewList(mediaPosts: pinViewModel.mediaPosts, pin: pinViewModel.pinModel, isLastPage: pinViewModel.isLastPage, pinDetailViewModel: .fixed(pinViewModel), isLoading: pinViewModel.isLoadingMedia, loadNextPage: $pinViewModel.loadNextPage)
.body(peak: pinViewModel.getTotalHeightForActivitySection())
.animation(.easeInOut)
}
}
}
}
.background(Shade.white)
.navigationBarHidden(true)
}
.background(Shade(GrayColors.gray10.getColor()))
.coordinateSpace(identify: "scroll")
.onPreferenceChange(ViewOffsetKey.self) { worth in
if pinViewModel.galleryViewHeight >= 0.0 && pinViewModel.galleryViewHeight <= pinViewModel.kGalleryHeightConst {
let previousValue = pinViewModel.galleryViewHeight + worth
if previousValue <= 0.0 {
pinViewModel.galleryViewHeight = 0
} else if previousValue >= pinViewModel.kGalleryHeightConst {
pinViewModel.galleryViewHeight = pinViewModel.kGalleryHeightConst
} else {
pinViewModel.galleryViewHeight = previousValue
}
}
}
}
}
As you’ll be able to see within the code above, the: PinTextFieldView
, PinDateView
, PinTextAreaView
are all textual content fields, which once we faucet on it, strikes the scroll view and focus them.
This behaviour used to work tremendous, till the second we added a brand new class: TaskPreviewRepresentable
, which is only a XIB executed in UIKit, which renders one other object that we fetch from the backend.
On this view we have now only some buttons and labels, all of the constraints are arrange accurately, however for some purpose, I nonetheless cannot get the ScrollView, to scroll to the sphere when it is centered.
Has anybody ever confronted this subject, which the ScrollView stops to give attention to a textual content area, solely since you added a UIViewRepresentable to it?
That is the code for the TaskPreviewRepresentable
struct TaskPreviewRepresentable: View, UIViewRepresentable {
@Binding var process: DTMediaPost
@Binding var userImage: UIImage?
var userRole: RoleType
@SwiftUI.State var viewModel: CardTaskViewModel
func makeUIView(context: Context) -> DTTaskPreview {
let taskPreview = DTTaskPreview(body: .init(x: 0, y: 0, width: UIDevice.isiPad ? viewModel.pinDetailiPadWidth - 32 : UIScreen.foremost.bounds.width - 32, peak: self.viewModel.getHeightOfTaskPreview(process: process, userRole: userRole)))
taskPreview.setupTaskStatus(taskStatus: NewTaskStatus(dtMediaPost: process))
taskPreview.setTaskStatusLabel(worth: NewTaskStatus(dtMediaPost: process).getName().lowercased())
taskPreview.setTaskNumber(worth: DTTaskListTranslate.taskListNumber.translation+" "+(process.quantity.unwrapped == 0 ? "-" : String(process.quantity.unwrapped)))
taskPreview.setTaskDescription(worth: process.title.unwrapped)
taskPreview.setTaskCreatedOrLastModified(worth: viewModel.getLastModifiedString(process: process))
taskPreview.setAssigneeImage(picture: viewModel.userImage, placeholder: process.getAssigneePlaceholder)
var mainAction: TaskQuickAction?
var secondaryAction: TaskQuickAction?
(secondaryAction, mainAction) = viewModel.getMainAndSecondaryAction(userRole: userRole, process: process)
if let leftAction = secondaryAction {
taskPreview.setLeftButton(buttonSize: .medium, buttonStyle: .tertiary)
taskPreview.setActionForLeftButton(actionName: leftAction.getOptionTranslation(), quickAction: leftAction)
} else {
taskPreview.hideLeftButton(hidden: true)
}
if let mainAction = mainAction {
taskPreview.setRightButton(buttonSize: .medium, buttonStyle: .callToAction)
taskPreview.setActionForRightButton(actionName: mainAction.getOptionTranslation(), quickAction: mainAction)
} else {
taskPreview.hideRightButton(hidden: true)
}
taskPreview.hideButtonView(hidden: (mainAction == nil && secondaryAction == nil))
taskPreview.setAssigneeName(worth: process.task?.identify ?? "")
taskPreview.setAssigneeSecondLine(worth: viewModel.getAssigneeSecondLineString(process: process))
taskPreview.setDueDateLabel(worth: process.due)
taskPreview.delegate = viewModel
return taskPreview
}
func updateUIView(_ uiView: DTTaskPreview, context: Context) {
uiView.setAssigneeImage(picture: viewModel.userImage, placeholder: process.getAssigneePlaceholder)
}
}