Published on

SwiftUI-da GeometryReader yordamida view o'lchami va joylashuvini aniqlash

Authors

GeometryReader β€” SwiftUI'da view'larning aniq o'lchami va ekrandagi joylashuvini olish uchun ishlatiladigan kuchli vosita. Ammo uni haddan ziyod ko'p joyda ishlatish ilovangizni sekinlashtirishi mumkin β€” shuning uchun birinchi navbatda uni ishlatmasdan yechim topishga harakat qiling, va faqat haqiqatan ham kerak bo'lganda qo'llang.


UIScreen.main.bounds.width ning cheklovi

Ikki to'rtburchakni HStack ichiga joylashtirib, ulardan biri ekranning 2/3 qismini egallashini xohlaymiz:

HStack(spacing: 0) {
    Rectangle()
        .fill(Color.red)
        .frame(width: UIScreen.main.bounds.width * 0.666)

    Rectangle()
        .fill(Color.blue)
}
.ignoresSafeArea()

Bu portret rejimda yaxshi ishlaydi β€” qizil 2/3, ko'k 1/3 ni egallaydi. Ammo qurilmani landscape rejimga o'zgartirganingizda muammo paydo bo'ladi: UIScreen.main.bounds.width qurilmaning fizik enini qaytaradi va qurilma aylanganida yangilanmaydi β€” shuning uchun qizil to'rtburchak landscape rejimda ham portretdagi pixel kengligini saqlab qoladi.


GeometryReader bilan yechim

GeometryReader esa joriy content maydonining haqiqiy o'lchamini qaytaradi va orientatsiya o'zgarganda avtomatik yangilanadi:

GeometryReader { geometry in
    HStack(spacing: 0) {
        Rectangle()
            .fill(Color.red)
            .frame(width: geometry.size.width * 0.666)

        Rectangle()
            .fill(Color.blue)
    }
    .ignoresSafeArea()
}

Endi simulyatorda qurilmani aylantirsak, qizil to'rtburchak har doim ekranning aynan 2/3 qismini egallaydi β€” portret va landscape rejimda ham.


Qachon GeometryReader ishlatmaslik kerak

GeometryReader qimmat vosita: bir ekranda ko'p ishlatilsa, UI biroz sekinlashishi mumkin. Shuning uchun:

  • Avval Spacer, HStack, VStack, frame(maxWidth: .infinity) kabi standart SwiftUI vositalar bilan yechim topishga harakat qiling.
  • Faqat ulardan biri ham yetarli bo'lmaganda GeometryReader qo'llang.
  • Ayniqsa boshlang'ich dasturchilar uni kerak bo'lmagan joylarda ham ishlatib qo'yishadi β€” bundan saqlaning.

2-misol: Gorizontal ScrollView ichida 3D aylanish animatsiyasi

Endi qiziqroq misol β€” gorizontal scroll view ichida har bir element ekranning markazidan qanchalik uzoqda ekaniga qarab 3D burilish (rotation3DEffect) qo'shamiz.

ScrollView(.horizontal, showsIndicators: false) {
    HStack {
        ForEach(0..<20) { index in
            GeometryReader { geometry in
                RoundedRectangle(cornerRadius: 20)
                    .rotation3DEffect(
                        .degrees(getPercentage(geo: geometry) * 40),
                        axis: (x: 0, y: 1, z: 0)
                    )
            }
            .frame(width: 300, height: 250)
            .padding()
        }
    }
}

frame va paddingni GeometryReaderga qo'llamiz, ichidagi RoundedRectanglega emas β€” chunki GeometryReader elementning aniq o'lchamini bilishi uchun o'lchami uning o'zida belgilanishi kerak.


getPercentage funksiyasi

func getPercentage(geo: GeometryProxy) -> Double {
    let maxDistance = UIScreen.main.bounds.width / 2
    let currentX = geo.frame(in: .global).midX
    return Double(1 - (currentX / maxDistance))
}
  • maxDistance β€” ekranning yarmi (markazga masofa)
  • geo.frame(in: .global).midX β€” shu elementning global koordinatalardagi markaziy x-nuqtasi
  • 1 - (currentX / maxDistance) β€” elementning markazdan qanchalik chetda ekanining foizi

Element ekran markazida bo'lganda currentX β‰ˆ maxDistance, natija β‰ˆ 0 daraja (to'g'ri). Element chetga siljigan sari foiz ortib, burilish kuchayadi (* 40 β€” maksimal burchak 40 daraja).


To'liq natija

struct GeometryReaderBootcamp: View {

    var body: some View {
        ScrollView(.horizontal, showsIndicators: false) {
            HStack {
                ForEach(0..<20) { index in
                    GeometryReader { geometry in
                        RoundedRectangle(cornerRadius: 20)
                            .rotation3DEffect(
                                .degrees(getPercentage(geo: geometry) * 40),
                                axis: (x: 0, y: 1, z: 0)
                            )
                    }
                    .frame(width: 300, height: 250)
                    .padding()
                }
            }
        }
    }

    func getPercentage(geo: GeometryProxy) -> Double {
        let maxDistance = UIScreen.main.bounds.width / 2
        let currentX = geo.frame(in: .global).midX
        return Double(1 - (currentX / maxDistance))
    }
}

Simulyatorda sinab ko'rsak: kartochkalar aylantirib ko'rilganda, markazdagi element to'g'ri turadi, chetga siljigan elementlar esa go'yo "burilib kelayotgandek" ko'rinadi β€” bu juda chiroyli effekt, va buning uchun faqat bir necha qator kod yetarli bo'ldi.


Xulosa

GeometryReader bilan xuddi shu mantiqni vertikal ScrollViewda ham ishlatish mumkin β€” elementlar yuqoridan pastga scroll qilinayotganda ularning opacity yoki scale'ini o'zgartirish, va hokazo. Konsepsiya bir xil: geo.frame(in: .global)dan kerakli koordinatani olib, animatsiya modifikatoriga uzatish.

GeometryReaderni kelajakdagi loyihalarda ko'proq ishlatamiz β€” shuning uchun asoslarni yaxshi tushuning, ammo uni faqat haqiqatan ham zarur bo'lganda qo'llang.

Buy mea coffee