İOS 8'de yön değişikliklerini işlemenin "doğru" yolu nedir?


104

Birisi bana iOS 8'de dikey ve yatay arayüz yönlendirmeleriyle çalışmaya "doğru" veya "en iyi" yaklaşımı söyleyebilir mi? Görünüşe göre bu amaçla kullanmak istediğim tüm işlevler iOS 8'de kullanımdan kaldırılmış ve araştırmam net ve zarif bir alternatif bulamadı. Dikey veya yatay modda olup olmadığımızı kendim belirlemek için gerçekten genişliğe ve yüksekliğe bakmam mı gerekiyor?

Örneğin, görünüm denetleyicimde aşağıdaki sözde kodu nasıl uygulamalıyım?

if we are rotating from portrait to landscape then
  do portrait things
else if we are rotating from landscape to portrait then
  do landscape things

3
İçin belgeleri okuyun UIViewController. "Görünüm Rotasyonlarını İşleme" başlıklı bölüme bakın. Ne yapmanız gerektiğini açıklıyor.
rmaddy

Kullanımdan kaldırılmaları bir ipucudur. Başka bir şey kullanmalısın .... başka bir şey Otomatik Yerleşim ve Boyut Sınıfları olmalı :-)
Aaron

Yanıtlar:


263

Apple, kullanıcı arayüzünüzün düzenini ve görünümünü önemli ölçüde değiştirebilmesi için, ne kadar ekran alanı olduğunun kaba bir ölçüsü olarak boyut sınıflarının kullanılmasını önerir. Dikeydeki bir iPad'in yatay modda olduğu gibi aynı boyut sınıflarına sahip olduğunu düşünün (Normal genişlik, Normal yükseklik). Bu, kullanıcı arayüzünüzün iki yön arasında aşağı yukarı benzer olması gerektiği anlamına gelir.

Bununla birlikte, iPad'de dikeyden manzaraya geçiş, boyut sınıfları değişmemiş olsa bile, kullanıcı arayüzünde daha küçük ayarlamalar yapmanız gerekebilecek kadar önemlidir. Arayüz oryantasyonuyla ilgili yöntemler UIViewControllerkullanımdan kaldırıldığından, Apple artık UIViewControlleryerine geçmek için aşağıdaki yeni yöntemin uygulanmasını öneriyor :

- (void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id <UIViewControllerTransitionCoordinator>)coordinator
{
    [super viewWillTransitionToSize:size withTransitionCoordinator:coordinator];

    // Code here will execute before the rotation begins.
    // Equivalent to placing it in the deprecated method -[willRotateToInterfaceOrientation:duration:]

    [coordinator animateAlongsideTransition:^(id<UIViewControllerTransitionCoordinatorContext> context) {

        // Place code here to perform animations during the rotation.
        // You can pass nil or leave this block empty if not necessary.

    } completion:^(id<UIViewControllerTransitionCoordinatorContext> context) {

        // Code here will execute after the rotation has finished.
        // Equivalent to placing it in the deprecated method -[didRotateFromInterfaceOrientation:]

    }];
}

Harika! Artık rotasyon başlamadan hemen önce ve bittikten sonra geri aramalar alıyorsunuz. Peki ya rotasyonun portre mi yoksa manzara mı olduğunu bilmeye ne dersiniz?

Apple, dönüşü yalnızca üst görünümün boyutundaki bir değişiklik olarak düşünmenizi önerir. Başka bir deyişle, dikey konumdan yatay konuma bir iPad dönüşü sırasında, kök seviyesinde görünüm sadece kendi değiştirme gibi düşünebiliriz bounds.sizegelen {768, 1024}etmek {1024, 768}. Sonra Bunu bilerek, kullanmalısınız sizegeçirilen viewWillTransitionToSize:withTransitionCoordinator:dikey veya yatay dönen olup olmadığını şekil dışarı için yukarıdaki yöntemle.

Eski kodu yeni iOS 8 iş yapma yöntemine taşımanın daha da sorunsuz bir yolunu istiyorsanız , UIView'deki bu basit kategoriyi kullanmayı düşünün . boyut.

Özetlemek için:

  1. Temelde farklı kullanıcı arayüzlerinin ne zaman gösterileceğini belirlemek için boyut sınıflarını kullanmalısınız (ör. "İPhone benzeri" kullanıcı arayüzü ile "iPad benzeri" kullanıcı arayüzü)
  2. Eğer kullanıcı arayüzüne küçük ayarlamalar yapmak gerekirse boyut sınıfları zaman yok değiştirmek ancak konteyner (üst görünüm) boyutu böyle bir iPad döndüğü, kullandığınızda gibi yapar viewWillTransitionToSize:withTransitionCoordinator:UIViewController geri arama.
  3. Uygulamanızdaki her görünüm, yalnızca yerleşim düzenine verildiği alana dayalı olarak düzen kararları almalıdır. Doğal görünüm hiyerarşisinin bu bilgileri basamaklandırmasına izin verin.
  4. Benzer şekilde, statusBarOrientationtemelde cihaz düzeyinde bir özellik olan "dikey" ve "yatay" görünüm için bir görünüm düzenleyip düzenlemeyeceğinizi belirlemek için kullanmayın. Durum çubuğu yönlendirmesi, yalnızca UIWindowuygulamanın kök düzeyinde gerçekte yaşayan gibi şeylerle ilgilenen kod tarafından kullanılmalıdır .

5
Mükemmel cevap! BTW, AL'deki youtube videonuz inanılmaz derecede bilgilendiriciydi. Paylaşmak için teşekkürler. Bunu kontrol et! youtube.com/watch?v=taWaW2GzfCI
smileBot

2
Bulduğum tek sorun, bazen cihaz yönünü bilmek istemenizdir ve bu size bunu bildirmez. İPad'de durum çubuğu veya aygıt yön değeri değişmeden önce çağrılır. Kullanıcının cihazı dikey konumda mı yoksa baş aşağı dikey konumda mı tuttuğunu bilemezsiniz. UIViewControllerTransitionCoordinator
Alay etmek

@Darrarski bu sorunlarla başa çıkmak için zarif bir çözüm buldunuz mu?
Xvolks

viewdidlayoutsubviewspeki o zaman nerede ? viewdidlayoutsubviewsDönme nedeniyle sınırlı değişiklikleri yakalamak için kullanıldığını sanıyordum . Bunu biraz detaylandırır mısın?
Tatlım

1
Durum barizasyonu kullanmazsak, soldan yatay ile sağdaki yatay manzara arasında nasıl ayrım yapılır? Bu ayrıma ihtiyacım var. Ayrıca, burada açıklanan başka sorunlar da var - stackoverflow.com/questions/53364498/…
Deepak Sharma

17

Smileyborg'un çok iyi ayrıntılı (ve kabul edilmiş) cevabına dayanarak, işte hızlı 3'ü kullanan bir uyarlama:

override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
    super.viewWillTransition(to: size, with: coordinator)
    coordinator.animate(alongsideTransition: nil, completion: {
        _ in
        self.collectionView.collectionViewLayout.invalidateLayout()
    })        
}

Ve UICollectionViewDelegateFlowLayoutuygulamada,

public func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
    // retrieve the updated bounds
    let itemWidth = collectionView.bounds.width
    let itemHeight = collectionView.bounds.height
    // do whatever you need to do to adapt to the new size
}

11

Ben sadece bildirim merkezini kullanıyorum:

Bir yönelim değişkeni ekleyin (sonunda açıklanacaktır)

//Above viewdidload
var orientations:UIInterfaceOrientation = UIApplication.sharedApplication().statusBarOrientation

Görünüm göründüğünde Bildirim ekle

override func viewDidAppear(animated: Bool) {
    NSNotificationCenter.defaultCenter().addObserver(self, selector: "orientationChanged:", name: UIDeviceOrientationDidChangeNotification, object: nil)
}

Görünüm kaybolduğunda Bildirimi Kaldır

override func viewWillDisappear(animated: Bool) {
        NSNotificationCenter.defaultCenter().removeObserver(self, name: UIDeviceOrientationDidChangeNotification, object: nil) 
}

Bildirim tetiklendiğinde mevcut yönlendirmeyi alır

func orientationChanged (notification: NSNotification) {
    adjustViewsForOrientation(UIApplication.sharedApplication().statusBarOrientation)
}

Yönü kontrol eder (dikey / yatay) ve olayları yönetir

func adjustViewsForOrientation(orientation: UIInterfaceOrientation) {
    if (orientation == UIInterfaceOrientation.Portrait || orientation == UIInterfaceOrientation.PortraitUpsideDown)
    {
        if(orientation != orientations) {
            println("Portrait")
            //Do Rotation stuff here
            orientations = orientation
        }
    }
    else if (orientation == UIInterfaceOrientation.LandscapeLeft || orientation == UIInterfaceOrientation.LandscapeRight)
    {
       if(orientation != orientations) {
            println("Landscape")
            //Do Rotation stuff here
            orientations = orientation
        }
    }
}

Bir yönelim değişkeni eklememin nedeni, fiziksel bir cihaz üzerinde test yaparken, yön bildiriminin sadece döndüğünde değil, cihazdaki her küçük harekette çağrılmasıdır. Var ve if deyimlerinin eklenmesi, kodu yalnızca ters yöne geçtiyse çağırır.


11
Bu, Apple'ın önerdiği yaklaşım değildir, çünkü uygulamanızdaki her görünümün, kendisine verilen alanı dikkate almak yerine, cihazın yönüne göre nasıl görüntüleneceğine karar verdiği anlamına gelir.
smileyborg

2
Apple, 8.0 ile donanımı da dikkate almıyor. Bir AVPreview katmanına, eğer bir görüntü denetleyicisi üzerinden sunulursa, yönelim konusunda endişelenmesine gerek olmadığını söyleyin. Çalışmıyor, ancak 8.2'de düzeltildi
Nick Turner

superarasında viewDidAppearve viewWillDisappearçağrılmalıdır
Andrew Bogaevskyi

Not: UIDeviceOrientation! = UIInterfaceOrientation. Deneylerimde statusBarOrientation güvenilir değil.
nnrales

2

Bir kullanıcı arayüzü perspektifinden, Boyut Sınıflarını kullanmanın, farklı yönlerde, boyutlarda ve ölçeklerdeki arayüzleri işlemek için Apple'ın önerdiği yaklaşım olduğuna inanıyorum.

Şu bölüme bakın: Özellikler Bir Arayüzün Boyut Sınıfını ve Ölçeğini Açıklayın : https://developer.apple.com/library/ios/releasenotes/General/WhatsNewIniOS/Articles/iOS8.html

"iOS 8, ekran boyutu ve yönünü çok daha çok yönlü hale getiren yeni özellikler ekliyor."

Bu da iyi bir makale: https://carpeaqua.com/thinking-in-terms-of-ios-8-size-classes/

Güncel Bağlantıyı DÜZENLE : https://carpeaqua.com/2014/06/14/thinking-in-terms-of-ios-8-size-classes/ (Kredi: Koen)


Evet, görünüşe göre tüm sitesi şu anda kapalı.
Aaron

Makale gerçekten okumaya değer ve işte doğru adres: carpeaqua.com/thinking-in-terms-of-ios-8-size-classes
uem

Ama ya boyut sınıfları ve kullanıcı arayüzü hakkında değil, örneğin AVFoundation'dan bahsediyorsak. Video kaydederken, bazı durumlarda doğru meta verileri ayarlamak için viewControllers yönünü bilmeniz gerekir. Bu basit imkansız. "çok yönlü".
Julian F.Weinert

OP'nin sorduğu / bahsettiği bu değil.
Aaron

1
Güncellenen bağlantı: carpeaqua.com/2014/06/14/…
koen
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.