Published on

SwiftUI-da VisualEffect ViewModifier'dan qanday foydalanish kerak

Authors

VisualEffect modifikatori iOS 17'da qo'shilgan β€” u GeometryReaderga muqobil, ammo faqat vizual effektlar uchun mo'ljallangan. GeometryReader ishlatsiz elementning o'lchami va ekrandagi joylashuviga qarab effektlar qo'llash imkonini beradi, va ko'p hollarda undan ham samaraliroq ishlaydi.

Talab: iOS 17+


Muammo: GeometryReader bilan

Aytaylik, matnning kengligi 200 pikseldan katta bo'lsa, grayscale qo'llashni xohlaymiz. GeometryReader bilan:

GeometryReader { geometry in
    Text("Hello, World!")
        .background(Color.red)
        .padding()
        .grayscale(geometry.size.width >= 200 ? 1 : 0)
}
.background(Color.green)

Muammo 1: GeometryReader standart bo'yicha ekranning to'liq kengligini egallaydi β€” green fon butun kenglikni qoplaydi, va geometry.size.width matnning emas, GeometryReaderning kengligi bo'ladi (masalan, 361 piksel).

Muammo 2: Har bir elementga GeometryReader qo'yish ilovani sekinlashtirishi mumkin.


Yechim: VisualEffect modifikatori

@available(iOS 17, *)
struct VisualEffectBootcamp: View {
    var body: some View {
        Text("Hello, World!")
            .background(Color.red)
            .padding()
            .frame(width: 200)
            .visualEffect { content, geometry in
                content
                    .grayscale(geometry.size.width >= 200 ? 1 : 0)
            }
    }
}

visualEffect closure ikki parametr beradi:

  • content β€” shu elementning visual effect turi (oddiy View emas, EmptyVisualEffect)
  • geometry β€” elementning o'zi haqidagi GeometryProxy (xuddi GeometryReaderdakidek)

Muhim nuance: content β€” bu EmptyVisualEffect turi, shuning uchun unga barcha modifikatorlarni qo'llab bo'lmaydi. Faqat quyidagilar ishlaydi:

blur, brightness, colorEffect, contrast, distortionEffect,
grayscale, hueRotation, offset, opacity, rotation3DEffect,
scaleEffect, saturation, transform va boshqalar

frame, foregroundColor kabi modifikatorlar ishlamaydi β€” ular uchun hamon GeometryReader ishlatish kerak.


Elementning koordinatasiga qarab effekt

geometry.frame(in: .global) orqali elementning ekrandagi joylashuvini olish mumkin:

Text("Hello, World!")
    .padding()
    .background(Color.red)
    .visualEffect { content, geometry in
        content
            .grayscale(geometry.frame(in: .global).minY < 300 ? 1 : 0)
    }

Element ekranning yuqorisida (minY < 300) bo'lsa β€” grayscale, pastda bo'lsa β€” rangli.


Animatsiya qo'shish

visualEffect ichida animatsiya o'z-o'zidan ishlamaydi β€” uni tashqaridan qo'shish kerak:

@State private var showSpacer: Bool = false

VStack {
    if showSpacer { Spacer() }

    Text("Hello, World!")
        .padding()
        .background(Color.red)
        .visualEffect { content, geometry in
            content
                .grayscale(geometry.frame(in: .global).minY < 300 ? 1 : 0)
        }
        .onTapGesture {
            showSpacer.toggle()
        }
}
.animation(.easeIn, value: showSpacer)  // tashqarida

.animation modifikatori visualEffect tashqarisida β€” VStack darajasida qo'llanilganda animatsiya ishlaydi.


Scroll view ichida parallax effekti

Bu β€” visualEffectning eng qulay ishlatish holati:

@available(iOS 17, *)
struct VisualEffectBootcamp: View {
    var body: some View {
        ScrollView {
            VStack(spacing: 30) {
                ForEach(0..<100) { index in
                    Rectangle()
                        .frame(width: 300, height: 200)
                        .frame(maxWidth: .infinity)
                        .background(Color.orange)
                        .visualEffect { content, geometry in
                            content
                                .offset(x: geometry.frame(in: .global).minY * 0.05)
                        }
                }
            }
        }
    }
}

Mantiq: Har bir to'rtburchakning minY qiymati β€” ekrandagi vertikal pozitsiyasi. * 0.05 koeffitsienti bilan bu qiymatni gorizontal offset'ga aylantiramiz. Yuqoridagi elementlar past qiymatga (kichik offset), pastdagi elementlar esa katta qiymatga (katta offset) ega bo'ladi β€” natijada aylantirib ko'rilganda chiroyli parallax effekti hosil bo'ladi.

Koeffitsiyentni 0.5ga oshirib kuchaytirish mumkin:

.offset(x: geometry.frame(in: .global).minY * 0.5)

Bu effekt GeometryReader bilan ham qilinishi mumkin edi, ammo visualEffect ancha silliqroq ishlaydi.


Qachon VisualEffect, qachon GeometryReader

HolatTavsiya
Grayscale, blur, opacity, offset, scale asosida effektVisualEffect
Frame, foregroundColor o'zgartirish kerakGeometryReader
ScrollView ichida silliq animatsiyaVisualEffect
iOS 16 va pastni qo'llab-quvvatlash kerakGeometryReader

Xulosa

visualEffect β€” GeometryReaderga engil, samaraliroq muqobil, ammo cheklangan:

  • Faqat vizual modifikatorlar (blur, scale, offset va h.) ishlaydi
  • frame, foregroundColor kabi modifikatorlar ishlamaydi
  • iOS 17+ talab qiladi

Agar GeometryReader ishlatib, faqat vizual effektlar qo'llayotgan bo'lsangiz β€” visualEffectga o'ting. Aks holda GeometryReaderni saqlang.

Buy mea coffee