- Published on
SwiftUI-da ScrollViewReader yordamida avtomatik scroll qilish
- Authors
- Name
- ShoxruxC
- @iOSdasturchi
Oddiy ScrollViewda biz qo'lda tepaga-pastga aylantirib ko'rishimiz mumkin, ammo uni avtomatik ravishda muayyan elementga scroll qila olmaymiz. Aynan shuning uchun ScrollViewReader kerak bo'ladi.
Buning eng keng tarqalgan amaliy misoli β chat ilovasi. Barcha xabarlar scroll view ichida bo'ladi, va ekran ochilganda siz so'nggi xabarga (pastga) avtomatik scroll bo'lishini xohlaysiz β aks holda foydalanuvchi eng qadimgi xabardan boshlab ko'radi, bu esa yomon tajriba hisoblanadi.
Boshlang'ich: oddiy ScrollView
Avval yangi fayl yaratamiz: ScrollViewReaderBootcamp. Asosiy tuzilmani quramiz β 50 ta kartochkadan iborat scroll view:
ScrollView {
ForEach(0..<50) { index in
Text("This is item number \(index)")
.font(.headline)
.frame(height: 200)
.frame(maxWidth: .infinity)
.background(Color.white)
.cornerRadius(10)
.shadow(radius: 10)
.padding()
}
}
Canvas'da "Resume" qilsak, kartochkalarni ko'rib, qo'lda aylantirib ko'rish mumkin. Ammo ekran ochilganda avtomatik ravishda, masalan, 49-elementga o'tish imkoni yo'q β buning uchun ScrollViewReader kerak.
ScrollViewReader qo'shish
ForEachni ScrollViewReader ichiga joylaymiz. Closure parametrini proxy deb ataymiz:
ScrollView {
ScrollViewReader { proxy in
ForEach(0..<50) { index in
Text("This is item number \(index)")
.font(.headline)
.frame(height: 200)
.frame(maxWidth: .infinity)
.background(Color.white)
.cornerRadius(10)
.shadow(radius: 10)
.padding()
.id(index) // <-- muhim!
}
}
}
.id(index) β bu juda muhim: proxy har bir elementning qayerda turganini bilishi uchun, har bir elementga aniq id berish shart. Holbuki bermasak, proxy.scrollTo ishlamaydi.
proxy.scrollTo bilan muayyan elementga scroll qilish
ForEachdan oldin, ScrollViewReader ichiga tugma qo'shamiz:
Button("Click here to go to #49") {
proxy.scrollTo(49, anchor: nil)
}
Tugmani bosganimizda, u bizni 49-elementga olib boradi. Anchor β ekranda shu element qaysi joyda ko'rsatilishi:
proxy.scrollTo(30, anchor: .top) // element tepada ko'rinadi
proxy.scrollTo(30, anchor: .center) // element markazda ko'rinadi
proxy.scrollTo(30, anchor: .bottom) // element pastda ko'rinadi
proxy.scrollTo(30, anchor: nil) // standart
withAnimation bilan silliq scroll
Hozircha element "sakrab" chiqadi. Silliq animatsiya uchun withAnimation ichiga olamiz:
Button("Click here to go to #30") {
withAnimation(.spring()) {
proxy.scrollTo(30, anchor: .center)
}
}
Endi tugmani bosganimizda, ekran silliq tarzda 30-elementga scroll qiladi.
ScrollViewReader tashqarisidan boshqarish
Ko'p holatlarda tugma scroll view'dan tashqarida joylashgan bo'ladi. Bu holda proxyga bevosita murojaat qila olmaymiz. Buning uchun quyidagi yondashuv ishlatiladi:
@State var textFieldText: String = ""
@State var scrollToIndex: Int = 0
VStack qo'shib, tepaga TextField va tugma, pastga esa ScrollView joylashtiramiz:
VStack {
HStack {
TextField("Enter a number...", text: $textFieldText)
.frame(height: 55)
.border(Color.gray)
.padding(.horizontal)
.keyboardType(.numberPad)
Button("Scroll") {
if let index = Int(textFieldText) {
scrollToIndex = index
}
}
}
ScrollView {
ScrollViewReader { proxy in
ForEach(0..<50) { index in
Text("This is item number \(index)")
.font(.headline)
.frame(height: 200)
.frame(maxWidth: .infinity)
.background(Color.white)
.cornerRadius(10)
.shadow(radius: 10)
.padding()
.id(index)
}
.onChange(of: scrollToIndex) { newValue in
withAnimation(.spring()) {
proxy.scrollTo(newValue, anchor: .top)
}
}
}
}
}
Mantiqning tahlili:
- Foydalanuvchi
TextFieldga son kiritadi va "Scroll" tugmasini bosadi. - Tugma
textFieldTextniIntga aylantiradi (if letorqali xavfsiz). Agar son bo'lmagan matn kiritilsa β crash bo'lmaydi, shunchaki scroll qilinmaydi. scrollToIndexyangilanadi..onChange(of: scrollToIndex)shu o'zgarishni sezib,proxy.scrollTo(newValue, anchor: .top)ni chaqiradi.
.keyboardType(.numberPad) β foydalanuvchi faqat raqam kiritishi uchun.
Xavfsizlik haqida
proxy.scrollTo aqlli: agar berilgan id scroll view ichida mavjud bo'lmasa (masalan, 4000 berilsa, ammo faqat 0-49 bor), u hech narsa qilmaydi, crash bermaydi. Bu xatti-harakatni esda tuting.
Eng keng tarqalgan ishlatish holati
Haqiqiy ilovalarda ForEach ko'pincha 0..<50 emas, balki ma'lumotlar massivi bo'ladi. Shu holda har bir elementning indexini id sifatida berib, scroll view'ni so'nggi elementga yo'naltirish mumkin:
.onAppear {
withAnimation(.spring()) {
proxy.scrollTo(dataArray.indices.last, anchor: .bottom)
}
}
Bu β chat ilovalarida ekran ochilishi bilan eng so'nggi xabarga avtomatik o'tishning klassik usuli.