As you can see in the image, scrollDismissesKeyboard(.interactively) has a bug while scrolling down. I want my textfield to follow keyboard just like in iMessage or WhatsApp or Instagram.
scrollDismissesKeyboard(.interactively) BUG with TextField
Thank you for your post.
Is this issue still occurring with the latest version of Xcode? Are you utilizing the simulator or a physical device? Are you employing the safeAreaInset?
Do you get the same results with just the relevant code in a small test project? If so, please share a link to your test project. That'll help us better understand what's going on. If you're not familiar with preparing a test project, take a look at Creating a test project.
Albert Pascual Worldwide Developer Relations.
@DTS Engineer Hello thanks for answer, My Xcode is up to date. I just noticed, this bug doesnt happen on latest iOS version (26.0), but it happens in previous iOS version either on simulator or physical device.
var body: some View {
VStack(spacing: 0) {
ChatAppBar(
id: id,
name: user?.name ?? "",
lastSeen:(user?.isOnline ?? false) ? "online" : "Last seen \(user?.lastOnlineAt?.formattedMessageTimestamp() ?? "---")",
avatarURL: user?.getProfilePicture(),
onBack: { dismiss() },
onAvatarTap: { }
)
ZStack {
ScrollView(showsIndicators: false) {
LazyVStack(spacing: 4) {
ForEach(Array(chatManager.messages.enumerated()), id: \.element.id!) { i, pair in
let msg: MMessage = pair
let preIsMine = (i > 0) ? chatManager.messages[i - 1].isMineDirectly() : false
MessageRow(
msg: msg,
preIsMine: preIsMine,
isLast: msg.id == chatManager.messages.last!.id,
bunnyToken: chatManager.bunnytoken,
onImageTapped: { url in
tappedImageUrl = IdentifiableURL(url: url)
}
)
.id(msg.id!)
.onAppear {
if i == 0 && !isLoadingMessages && canLoadMoreMessages {
Task {
let anchorId = msg.id!
canLoadMoreMessages = false
try? await Task.sleep(for: .milliseconds(300))
isLoadingMessages=true
try? await Task.sleep(for: .milliseconds(1000))
canLoadMoreMessages = await chatManager.loadMessages(uid: id.uuidString, after: msg.created_at_original)
scrollTargetID = anchorId
try? await Task.sleep(for: .milliseconds(300))
isLoadingMessages=false
}
}
}
}
}
.padding(.top, 8)
}
.scrollDisabled(isLoadingMessages)
.scrollPosition(id: $scrollTargetID, anchor: .top)
if isLoadingMessages{
Color.black.opacity(0.3)
.ignoresSafeArea()
.frame(maxWidth: .infinity, maxHeight: .infinity)
.contentShape(Rectangle()) // makes the whole overlay block taps
.allowsHitTesting(true)
ProgressView()
.padding(.bottom,26)
Text("Loading older messages..")
.padding(.top, 26)
}
}
}
.task {
if user == nil{
await loadUser()
let canLoadMore = await chatManager.loadMessages(uid: id.uuidString, after: nil)
let anchorMessageID = chatManager.messages.last?.id
if let anchorMessageID {
DispatchQueue.main.async {
scrollTargetID = anchorMessageID
}
}
try? await Task.sleep(for: .milliseconds(300))
canLoadMoreMessages = canLoadMore
}
}
.safeAreaInset(edge: .bottom){
TextFieldBar()
}
.scrollDismissesKeyboard(.interactively)
.toolbar(.hidden, for: .navigationBar)
.zIndex(999)
.overlay {
if let u = tappedImageUrl {
SpotlightSheet(material: .ultraThickMaterial, onClose: {
tappedImageUrl = nil
}) {
ZoomableImageSaver(urlString: u.url,onClose: { tappedImageUrl = nil })
}
.transition(.identity)
}
}
}