Reputation: 71
I am creating a chat app and I want the content of the ScrollView to go beneath the input field (while scrolling up). I already put the ScrollView and the input field in a ZStack. Bottom padding on the ScrollView puts the content up, but I also want the scroll indicator to move up with the content.
Is there any way to change the insets of the scroll indicator to match the padding, or any other workaround to achieve what I'm looking for?
Here's the current code:
ZStack(alignment: .bottom) {
ScrollView {
ScrollViewReader { value in
VStack(spacing: 5) {
ForEach(MOCK_MESSAGES) {
mMessage in
MessageView(mMessage: mMessage)
}
.onAppear {
value.scrollTo(MOCK_MESSAGES.count - 1)
}
}
.padding(.top, 10)
.padding(.bottom, 40)
}
}
MessageInputView(messageText: $messageText)
}
Summing up: The idea is to have the ScrollView to be above the input view, but move the content underneath input view when scrolling up.
Upvotes: 5
Views: 7395
Reputation: 299
since iOS 17 there is a modifier for ScrollViews to address this issue:
ScrollView {
}.contentMargins(.top, 100.0, for: .scrollIndicators)
See contentMargins - Documentation
Upvotes: 5
Reputation: 9784
iOS 15 / Swift 3
You could do this with .safeAreaInset
instead of padding, then it handles the scroll indicator insets for you as well.
ScrollView {
ScrollViewReader { value in
VStack(spacing: 5) {
// stuff
}
}
}
.safeAreaInset(edge: .bottom) {
MessageInputView(messageText: $messageText)
}
Note: .safeAreaInsets
doesn't seem to be working on List
as of Xcode 13.1.
UPDATE: As of iOS 15.2, safeAreaInsets()
works with List and Form as well.
iOS 14 / Swift 2 or with List
Like many things in SwiftUI, there doesn't seem to be a to do it without tinkering with the underlying UIKit components. There's an easy solution for this one though, using the Introspect library:
ZStack(alignment: .bottom) {
ScrollView {
ScrollViewReader { value in
VStack(spacing: 5) {
// stuff
}
.padding(.top, 10)
.padding(.bottom, 40)
}
}
.introspectScrollView { sv in
sv.verticalScrollIndicatorInsets.top = 10
sv.verticalScrollIndicatorInsets.bottom = 40
}
MessageInputView(messageText: $messageText)
}
You could also do it with a List
with introspectTableView
.
Upvotes: 11