SwiftUI: ScrollView
ScrollView,
içine yerleştirdiğimiz içeriğe uyacak şekilde kendisini otomatik olarak boyutlandıran görünümler oluşturmamızı sağlar.
Bir SwiftUI uygulamasında ScrollView
, yatay ve dikey hizada kaydırılabilen elemanlar oluşturmamızı sağlayan bir arayüz elemanıdır. ScrollView
elemanını UIKit “framework”ündeki UIScrollView
elemanının SwiftUI versiyonu gibi düşünebilirsiniz.
Hadi o zaman ScrollView
elemanını öğrenmeye başlayalım!
ScrollView Objesini Oluşturma
İlk olarak yeni bir Xcode projesi oluşturalım. Projemizi bir SwiftUI projesi olarak kaydetmeyi unutmayalım. Projemizi oluşturduktan sonra Xcode’un bizim için varsayılan olarak verdiği kodlardan Text
elemanını ve padding
“modifier”ını silelim. Sonrasında body
içerisine ScrollView
elemanını oluşturalım.
ScrollView {
VStack(spacing: 20) {
ForEach(0..<10) {
Text("Box \($0)")
.foregroundColor(.white)
.font(.largeTitle)
.frame(width: 200, height: 200)
.background(Color.blue)
}
}
}
Bu kodu yazdıktan sonra elde ettiğimiz görüntü dikey yani “vertical” bir görüntü olarak karşımıza çıkacak. Bunun sebebi ise ScrollView
objemizin eğer belirtmezsek başlangıç değeri “vertical” olarak karşımıza çıkacaktır.
Projemizde oluşturduğumuz “200x200” kutuları aşağıya doğru kaydırabildiğimizi görüyoruz. Bunun yanında sayfamızı aşağıya doğru kaydırırken bir şey dikkatinizi çekebilir, kutularımızın yanında kaydırma çubuğu olarak adlandırabileceğimiz gösterge bulunmakta, gelin bu göstergeyi görünmez hale getirelim ve bu sayede daha hızlı bir sayfa akışı görelim.
Göstergeyi silmemiz için şu kodu ScrollView
objesinin showIndicators
parametresini false
değerine eşitleyelim.
ScrollView(showsIndicators: false) {
....
“Preview” sayfasından projemizin anlık durumuna baktığımızda sonuç aşağıdaki gibi olacaktır.
ScrollView
yapımızın dikey bir şekilde kullanımını gördük, gelin bir de yatay görünüm elde edebilmek için kodumuzu küçük bir dokunuşla değiştirelim.
ScrollView(.horizontal, showIndicators: false) {
HStack(spacing: 20) {
ForEach(0..<10) {
Text("Box \($0)")
.foregroundColor(.white)
.font(.largeTitle)
.frame(width: 200, height: 200)
.background(Color.blue)
}
}
}
Bir önceki kodumuzu revize ettiğimizde bu sefer de yatayda kaydırabileceğimiz bir yapı oluşturmuş olduk.
Kaydırma çubuğumuzun görünmemesini sağlamak için showIndicators
parametresini false
olarak tekrar girdik.
Şimdiye kadar ScrollView
objesini basitçe ele aldık. Şimdi ise Apple’ın WWDC20'de tanıttığı ScrollViewReader
objesini öğreneceğiz.
ScrollViewReader
Belirli bir konumdaki objeye doğru ScrollView
objesini kaydırmak için ScrollViewReader
objesini kullanırız. ScrollViewReader
objesi, içerisinde id
“modifier”ı ile tanımlanmış objelerin “id” bilgisinden yararlanarak istenilen bir objeye kaydırma işlemi yapmamızı sağlar.
Aşağıdaki kod bloğundaki gibi belli bir “id” bilgisine sahip objeleri -aşağıdaki örnekte bu Text
oluyor- otomatik olarak kaydırarak kullanıcının görebileceği şekilde ekranda gösterebiliyoruz.
ScrollViewReader { scrollView in
ScrollView(showsIndicators: false) {
VStack(spacing: 20) {
Button("Aşağıya Kaydır") {
withAnimation {
scrollView.scrollTo(3, anchor: .center)
}
}
ForEach(0..<10) { index in
Text("Box \(index)")
.id(index)
.foregroundColor(.white)
.font(.largeTitle)
.frame(width: 200, height: 200)
.background(Color.blue)
}
}
}
}
Burada ne yaptık? Belirli bir konuma kaydırmamızı sağlayan ScrollViewReader
yapımızın içerisine ScrollView
oluşturduk. Başlangıç özelliği “vertical” olan yapımızın hizalamasını değiştirdik. İstediğimiz konuma gitmesini sağlamak için Button
ekledik. scrollTo
metodunu butonun içerisinde çağırarak üçüncü indeksteki elemana gidilmesi için ilk parametreye “3” yazdık ve anchor
parametresini .center
olarak ayarladık.
Artık kaydırma görünümü içeriğini belirli bir konuma taşıyabileceğimizi öğrendik, ancak arayüz elemanlarımızın konum bilgilerine nasıl erişebiliriz? Kullanıcı içeriği kaydırırken görünümü nasıl güncel tutabiliriz? Gelin bu soruların cevaplarını öğrenelim.
İlk önce ScrollView
objemizin içerisindeki elemanların konum bilgilerini anlık olarak bilmek için PreferenceKey
protokolü ile bir yapı oluşturalım. Burada CGPoint
türünden alacağımız bilgileri derleyeceğiz.
struct ScrollOffsetPreferenceKey: PreferenceKey {
static var defaultValue: CGPoint = .zero
static func reduce(value: inout CGPoint, nextValue: () -> CGPoint) {}
}
Bu ScrollOffsetPreferenceKey
yapısını kullanabilmek için kendi özel ScrollView
objemizi oluşturalım. Burada ekstra View
objeleri ekleyebilmek için de generic bir View
yapısı tanımlıyoruz: “Content”. init
metodunda kendisini @ViewBuilder
“property wrapper”ı ile tanımlıyoruz, bu sayede birden fazla View
objesini içerisinde barındırabilecek.
struct OffsetScrollView<Content: View>: View {
let axes: Axis.Set
let showsIndicators: Bool
let offsetChanged: (CGPoint) -> Void
let content: Content
init(
axes: Axis.Set = .vertical,
showsIndicators: Bool = true,
offsetChanged: @escaping (CGPoint) -> Void = { _ in },
@ViewBuilder content: () -> Content
) {
self.axes = axes
self.showsIndicators = showsIndicators
self.offsetChanged = offsetChanged
self.content = content()
}
}
Artık OffsetScrollView
objesini alınan özellikler ile oluşturabiliriz. Görebileceğiniz üzere, onPreferenceChange
“modifier”ında oluşturmuş olduğumuz SrollOffsetPreferenceKey
elemanını kullanıyoruz.
struct OffsetScrollView<Content: View>: View {
/ ... var body: some View {
OffsetScrollView(axes, showsIndicators: showsIndicators) {
GeometryReader { geometry in
Color.clear.preference(
key: ScrollOffsetPreferenceKey.self,
value: geometry.frame(in: .named("scrollView")).origin
)
}.frame(width: 0, height: 0)
content
}
.coordinateSpace(name: "scrollView")
.onPreferenceChange(ScrollOffsetPreferenceKey.self, perform: offsetChanged)
}
}
Şimdi sıra bu oluşturduğumuz ` objesini ana View objemizde kullanmaya geldi.
ScrollView
objesine benzer şekilde bir OffsetScrollView
objesi tanımlayabiliyoruz, sadece tanımlamamız gereken üç tane parametremiz var.
struct ContentView: View {
var body: some View {
OffsetScrollView(
axes: [.horizontal, .vertical],
showsIndicators: false,
offsetChanged: { print($0) }
) {
ForEach(0..<100) { i in
Text("Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book.")
}
}
}
}
Sonuç olarak, parametre değerlerimizi de ContentView
içerisine ekledik ve döngümüzü yazmış olduk. Uygulamamızın son hali aşağıdaki gibidir. 👇🏻
Bu yazımızda ScrollView
objesini nasıl kullanabileceğimizi öğrendik. Umarım sizler için yararlı bir yazı olmuştur, bir sonraki yazımızda görüşmek üzere! 🤙🏻
Bu yazımızda yapmış olduğumuz projemize aşağıdaki linkten ulaşabilirsiniz: