Disable Scrolling in Swiftui List/Form

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



Leave a reply



Submit