SwfitUI List Make Scrolling disabled
Instead of using List
which is scrollable, use ForEach
.
ForEach
is not scrollable by default.
Here is an example using ForEach
struct ContentView: View {
let colors: [Color] = [.red, .green, .blue]
var body: some View {
VStack {
ForEach(colors, id: \.self) { color in
Text(color.description.capitalized)
.padding()
.background(color)
}
}
}
}
A good resource for ForEach
can be found here similarly one for List
can be found here.
Update
There are currently two ways to stop a List
from scrolling:
- Using
UITableView.appearance().isScrollEnabled = false
(but this can unintended side-effects) - Using the 3rd party dependency Introspect
Caveats
List
contained in a NavigationView
If your List
is contained in a NavigationView
then it will still scroll. Neither of the above methods stop it from scrolling.
Here is an example view:
import SwiftUI
import Introspect
struct ContentView: View {
var body: some View {
NavigationView {
List {
ForEach(0..<10, id: \.self) { _ in
NavigationLink("Tap") {
Text("Hello").onTapGesture {
print("hello")
}
}
}
}
// .onAppear {
// UIScrollView.appearance().isScrollEnabled = false
// }
// .introspectTableView { tableView in
// tableView.isScrollEnabled = false
// }
}
}
}
Uncommenting the onAppear
or the introspectTableView
does not stop the List
from scrolling.
List
not contained in a NavigationView
If the List
is not contained in a NavigationView
then we can be possible to stop the List
from scrolling.
If we remove the NavigationView
from the above example, we can see that by uncommenting the onAppear
or the introspectTableView
the List
does stop scrolling.
Here is a video of the above situations.
Disable scrolling from bottom to top in swiftUI scroll view
Use LazyVGrid
and DragGesture
when changed, you only allow scroll to bottom.
struct ContentView: View {
@State private var offset: CGFloat = .zero
var columns: [GridItem] = Array(repeating: .init(.flexible()), count: 2)
var body: some View {
LazyVGrid(columns: columns) {
ForEach((0...79), id: \.self) {
let codepoint = $0 + 0x1f600
let codepointString = String(format: "%02X", codepoint)
Text("\(codepointString)")
let emoji = String(Character(UnicodeScalar(codepoint)!))
Text("\(emoji)")
}
}
.font(.largeTitle)
.offset(y: offset)
.gesture(DragGesture().onChanged {value in
let translation = value.translation.height
if translation < 1 {
offset = translation
}
})
}
}
Update
You need to track the last offset when scrolling and reset it to zero each time you stop scrolling. This fixes the issue you have addressed in your comment.
struct ContentView: View {
@State private var offset: CGFloat = .zero
@State private var lastOffset: CGFloat = .zero
var columns: [GridItem] = Array(repeating: .init(.flexible()), count: 2)
var body: some View {
LazyVGrid(columns: columns) {
ForEach((0...79), id: \.self) {
let codepoint = $0 + 0x1f600
let codepointString = String(format: "%02X", codepoint)
Text("\(codepointString)")
let emoji = String(Character(UnicodeScalar(codepoint)!))
Text("\(emoji)")
}
}
.font(.largeTitle)
.offset(y: offset)
.gesture(DragGesture().onChanged {value in
let translation = value.translation.height
if translation <= lastOffset {
offset = translation
lastOffset = translation
}
}.onEnded { value in
lastOffset = .zero
})
}
}
You do not need to use LazyVGrid
if you your Views are not too many.
SwiftUI: Disable ScrollView scrolling to top if top of screen is touched
This is not a SwiftUI
or Xcode
or ScrollView
problem.
This is a built-in feature of iPhone.
When you tap the top-center edge of the screen, displayed contents will be scrolled up.
Try opening apps like Facebook, WhatsApp, then scroll and tap at the same position, you will see the displayed contents scroll up.
How to only disable scroll in ScrollView but not content view?
Only pass .horizontal
as the scroll axis if you want the view to scroll. Otherwise, pass the empty set.
struct TestView: View {
@Binding var shouldScroll: Bool
var body: some View {
ScrollView(axes, showsIndicators: false) {
Text("Your content here")
}
}
private var axes: Axis.Set {
return shouldScroll ? .horizontal : []
}
}
How to prevent TextEditor from scrolling in SwiftUI?
To solve this problem, I ended up using the .fixedSize(horizontal: false, vertical: true)
modifier to fix the TextEditor
to its full size, which then allowed the solution in Dynamic row hight containing TextEditor inside a List in SwiftUI to work as expected within the list.
Related Topics
Swift Access to Variable Length Array
Function That Takes a Protocol and a Conforming Class (!) Instance as Parameters
How to Convert Uint16 to Uint8 in Swift 3
In Swift, Does Int Have a Hidden Initializer That Takes a String
Injecting a New Stylesheet into a Website via Uiwebview Using iOS8 Swift Xcode 6
Multiple Enum Types List All Cases
How to Access a Swift Enum Associated Value Outside of a Switch Statement
Swift: How to Get Everything After a Certain Set of Characters
Why Swift Closure Not Capture Self
How Are Int and String Accepted as Anyhashable
Swift Task Continuation Misuse: Leaked Its Continuation - for Delegate
Swift UI MACos Background Transparent Textfield
Nsurlerrordomain with Code=-1100
In Swift,There's No Way to Get the Returned Function's Argument Names