iOS14의 SwiftUI에서는 리스트의 스크롤 처리를 코드로 제어할 수 있게 되었다
소개
iOS13의 SwiftUI에서는 할 수 없었던 코드에 의한 리스트의 스크롤 처리가, iOS14에서는 할 수 있게 되었습니다.
본 기사에서 그 구현 방법을 정리하고 있습니다.
iOS13에서 스크롤 처리
iOS 앱을 개발하고 있다고 자주 있는 「○번째의 셀에 자동으로 스크롤 한다」라고 하는 처리입니다만,
이것을 iOS13의 SwiftUI에서는 실현할 방법이 없었습니다.
struct ContentView: View {
var body: some View {
List(0..<100) {
Text("\($0)")
}
}
}
UIKit에서는 다음과 같은 형태로 scrollToRow
, scrollToItem
등의 메소드를 호출하는 형태로 해당 요건을 쉽게 구현할 수 있으므로,
이 기능을 위해서만 UIViewRepresentable
, UIViewControllerRepresentable
등을 이용하는 일도 자주 있었습니다.
// UITableView
tableView.scrollToRow(at: IndexPath(row: 10, section: 0),
at: .top,
animated: true)
// UICollectionView
collectionView.scrollToItem(at: .init(item: 10, section: 0),
at: .top,
animated: true)
iOS14에서 스크롤 처리
iOS14에서는 ScrollViewReader
라는 스크롤 상태를 제어할 수 있는 새로운 View가 추가되어 있으며,
이것을 이용하면 임의의 지점에 자동으로 스크롤 시키는 처리의 구현이 가능하게 됩니다.
다음은 샘플 코드입니다.
준비
먼저 준비로 스크롤 지점을 지정하는 TextField를 설치합니다.
struct ContentView: View {
@State private var text: String = ""
var body: some View {
VStack {
HStack {
TextField("input row number", text: $text)
Button("Scroll") {
guard let row = Int(text) else { return }
print(row)
}
}.padding()
List(0..<100) {
Text("\($0)")
}
}
}
}
이렇게 하면 버튼을 탭하면 사용자가 TextField에 입력한 값을 얻을 수 있습니다.
스크롤 제어
그러면 실제로 스크롤시키는 처리의 구현 부분입니다.
우선은 스크롤 제어를 하고 싶은 부분을 ScrollViewReader
로 둘러쌉니다.
이렇게하면 스크롤 제어가 가능한 ScrollViewProxy
인스턴스를 얻을 수 있습니다.
struct ContentView: View {
@State private var text: String = ""
var body: some View {
VStack {
+ ScrollViewReader { (proxy: ScrollViewProxy) in
HStack {
TextField("input row number", text: $text)
Button("Scroll") {
guard let row = Int(text) else { return }
}
}.padding()
List(0..<100) {
Text("\($0)")
}
+ }
}
}
}
또한 스크롤 위치를 식별하기위한 ID를 대상 View에 부여하고,
제어를 개시하고 싶은 부분에서 ScrollViewProxy
의 scrollTo
메소드에 그 ID를 지정하는 것만으로 스크롤 처리를 실현할 수가 있습니다.
struct ContentView: View {
@State private var text: String = ""
var body: some View {
VStack {
ScrollViewReader { (proxy: ScrollViewProxy) in
HStack {
TextField("input row number", text: $text)
Button("Scroll") {
guard let row = Int(text) else { return }
+ withAnimation {
+ proxy.scrollTo(row, anchor: .top)
+ }
}
}.padding()
List(0..<100) {
Text("\($0)")
+ .id($0)
}
}
}
}
}
이것으로 하고 싶은 것을 실현할 수 있게 되었습니다.
덧붙여서 withAnimation
를 부여하지 않으면, 스크롤의 애니메이션은 행해지지 않습니다.
또, 제 2 인수의 anchor
로 스크롤 후의 위치를 세세하게 지정할 수 있습니다.
덤
그리드에 대해서도 문제없이 작동했습니다.
struct ContentView: View {
@State private var text: String = ""
var body: some View {
VStack {
ScrollViewReader { (proxy: ScrollViewProxy) in
HStack {
TextField("input row number", text: $text)
Button("Scroll") {
guard let row = Int(text) else { return }
withAnimation {
proxy.scrollTo(row, anchor: .top)
}
}
}.padding()
ScrollView {
LazyVGrid(
columns: [
GridItem(.flexible(minimum: 0, maximum: .infinity)),
GridItem(.flexible(minimum: 0, maximum: .infinity)),
],
alignment: .center,
spacing: nil
) {
ForEach(0..<100) {
Text("\($0)")
.frame(height: 100)
}
}
}
}
}
}
}
Reference
이 문제에 관하여(iOS14의 SwiftUI에서는 리스트의 스크롤 처리를 코드로 제어할 수 있게 되었다), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다
https://qiita.com/chocoyama/items/b775e80e445d81d33814
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념
(Collection and Share based on the CC Protocol.)
struct ContentView: View {
var body: some View {
List(0..<100) {
Text("\($0)")
}
}
}
// UITableView
tableView.scrollToRow(at: IndexPath(row: 10, section: 0),
at: .top,
animated: true)
// UICollectionView
collectionView.scrollToItem(at: .init(item: 10, section: 0),
at: .top,
animated: true)
struct ContentView: View {
@State private var text: String = ""
var body: some View {
VStack {
HStack {
TextField("input row number", text: $text)
Button("Scroll") {
guard let row = Int(text) else { return }
print(row)
}
}.padding()
List(0..<100) {
Text("\($0)")
}
}
}
}
struct ContentView: View {
@State private var text: String = ""
var body: some View {
VStack {
+ ScrollViewReader { (proxy: ScrollViewProxy) in
HStack {
TextField("input row number", text: $text)
Button("Scroll") {
guard let row = Int(text) else { return }
}
}.padding()
List(0..<100) {
Text("\($0)")
}
+ }
}
}
}
struct ContentView: View {
@State private var text: String = ""
var body: some View {
VStack {
ScrollViewReader { (proxy: ScrollViewProxy) in
HStack {
TextField("input row number", text: $text)
Button("Scroll") {
guard let row = Int(text) else { return }
+ withAnimation {
+ proxy.scrollTo(row, anchor: .top)
+ }
}
}.padding()
List(0..<100) {
Text("\($0)")
+ .id($0)
}
}
}
}
}
그리드에 대해서도 문제없이 작동했습니다.
struct ContentView: View {
@State private var text: String = ""
var body: some View {
VStack {
ScrollViewReader { (proxy: ScrollViewProxy) in
HStack {
TextField("input row number", text: $text)
Button("Scroll") {
guard let row = Int(text) else { return }
withAnimation {
proxy.scrollTo(row, anchor: .top)
}
}
}.padding()
ScrollView {
LazyVGrid(
columns: [
GridItem(.flexible(minimum: 0, maximum: .infinity)),
GridItem(.flexible(minimum: 0, maximum: .infinity)),
],
alignment: .center,
spacing: nil
) {
ForEach(0..<100) {
Text("\($0)")
.frame(height: 100)
}
}
}
}
}
}
}
Reference
이 문제에 관하여(iOS14의 SwiftUI에서는 리스트의 스크롤 처리를 코드로 제어할 수 있게 되었다), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://qiita.com/chocoyama/items/b775e80e445d81d33814텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)