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.
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")
}
}
}