SwiftUI ile Device Orientation

SwiftUI’da ekran döndürme (orientation) işlemlerini 2 şekilde yönetebiliriz. Birincisi UIKit bileşenleri ve Combine Framework ile ekranın durumunu izleyerek ve buna uygun aksiyonları anlık olarak işleyerek. İkincisi ise SwiftUI’nın bize sunduğu verticalSizeClass Instance Property ile.

Github Linki:

Aşağıda 2 yöntemi de kodlarıyla bilikte inceleyelim.

İlk Yöntem (Combine Framework ve UIKit yardımıyla)

Öncelikle sınıfımızı oluşturalım. Sınıfımız, ekran değişikliklerini bize bildirmek için Combine Framework’unu kullanacak. Bu sınıf, cihazın mevcut yönlendirmesini @Published property sayesinde takip edecek ve herhangi bir değişiklik olduğunda bu değişiklikleri bildirecek.

final class DeviceOrientation: ObservableObject {
    // Cihazın dikey (portrait) veya yatay (landscape) konumunu temsil eden bir enum tanımlıyoruz.
    enum Orientation {
        case portrait
        case landscape
    }
    
    // Cihazın mevcut konumunu depolamak için bir @Published property tanımlıyoruz.
    @Published var orientation: Orientation
    
    // NotificationCenter tarafından gönderilen cihazın yönlendirme değişikliği bildirimlerini dinlemek için kullanılacak olan bir yayıncı (publisher) ve yayıncıyı dinlemek için bir dinleyici (listener) tanımlıyoruz.
    private var listener: AnyCancellable?
    
    // Sınıfın başlatıcı metodu (init).
    init() {
        // Başlangıçta, cihazın konumunu belirlemek için UIDevice.current.orientation kullanılır.
        orientation = UIDevice.current.orientation.isLandscape ? .landscape : .portrait
        
        // NotificationCenter, cihazın yönlendirme değişikliği bildirimlerini dinleyen bir yayıncı oluşturur.
        listener = NotificationCenter.default.publisher(for: UIDevice.orientationDidChangeNotification)
        // Bildirimi işleyen ve cihazın mevcut konumunu belirleyen bir operatör zinciri tanımlıyoruz.
            .compactMap { notification in
                // Bildirim nesnesinden cihaz alınır.
                guard let device = notification.object as? UIDevice else {
                    return nil
                }
                
                // Cihazın konumuna göre uygun Orientation enum değeri geriye döndürülür.
                if device.orientation.isPortrait {
                    return .portrait
                } else if device.orientation.isLandscape {
                    return .landscape
                } else {
                    return nil
                }
            }
        // Elde edilen konumu sınıfın `orientation` property'sine atayan ve yayınlayan bir operatör kullanılır.
            .assign(to: \.orientation, on: self)
    }
    
    // Sınıf nesnesi bellekten kaldırıldığında dinleyiciyi iptal eder.
    deinit {
        listener?.cancel()
    }
}

DeviceOrientation Sınıfının Kullanımı

import SwiftUI

struct ContentView: View {
    @ObservedObject var orientation = DeviceOrientation()
    
    var body: some View {
        Text("Ekran Şu Anda: \(orientation.orientation == .portrait ? "Dikey" : "Yatay") Durumda")
            .padding()
    }
}

İkinci Yöntem (verticalSizeClass) SwiftUI Instance Property

verticalSizeClass, SwiftUI içinde kullanılan bir çevresel (environment) değişkendir ve cihazın yatay konumunu belirler. Bu özellik, .compact ve .regular olmak üzere iki durumu temsil eder. .compact, cihaz yatay konumdayken, .regular ise cihaz dikey konumdayken kullanılır. verticalSizeClass, kullanıcı arayüzünü cihazın konumuna göre dinamik olarak uyarlamak için kullanılır.

struct ContentView: View {
    @Environment(\.verticalSizeClass) var verticalSizeClass

    var body: some View {
        Text("Ekran Şu Anda: \(verticalSizeClass == .compact ? "Yatay" : "Dikey") Durumda")
            .bold()
            .padding()
    }
}

İlk yöntemde ekranın durumundaki değişiklikler anlık olarak Combine ile takip edilip yayın yapan tüm alıcılara iletilir. Böylece değişiklikler sürekli bildirimler halinde gelir. onReceive modifier ile bu sınıfın orientation property’si izlenerek aynlık olarak değişiklikler alınabilir.

İkinci yöntemde ise onReceive modifier tanımlanırken bunu bir NotificationCenter ile sarmalayıp değişikleri bunun aracılığıyla izlemeniz gereklidir.

Combine Framework ve UIKit Kullanımı

struct ContentView: View {
    @ObservedObject var deviceOrientation = DeviceOrientation()
    @State private var selectedTabItem = 0
    @State private var visibility : Visibility = .visible
    
    var body: some View {
        TabBar(selection: $selectedTabItem, visibility:  $visibility) {
            MovieListView()
                .tabItem(0) {
                    Text("Movies")
                }
            TVSeriesListView()
                .tabItem(1) {
                    Text("TV Series")
                }
            SearchView()
                .tabItem(2) {
                    Text("Search")
                }
        }
        .onReceive(deviceOrientation.$orientation){ newOrientation in
            switch newOrientation {
            case .portrait:
                visibility = .visible // cihaz dikey konumda tabbar göster
            case .landscape:
                visibility = .hidden // // cihaz yatay konumda tabbar gizle
            }
        }
        
    }
}

verticalSizeClass Kullanımı

struct ContentView: View {
    
    @Environment(\.verticalSizeClass) var verticalSizeClass
    
    var body: some View {
        NavigationStack {
            VStack {
                Image(systemName: verticalSizeClass == .regular ? "arrowshape.up" : "arrowshape.left.arrowshape.right")
                    .font(.largeTitle)
                    .foregroundColor(.red)
                Divider()
                Text("Ekran \(verticalSizeClass == .compact ? "Dikey" : "Yatay") Konumda" )
                    .bold()
            }
            .navigationBarTitle("Device Orientation")

        }
        
    }
}

Yorum yapın