IOS 8 में ओरिएंटेशन परिवर्तनों को संभालने के लिए "सही" तरीका क्या है?


104

क्या कोई मुझे आईओएस 8 में पोर्ट्रेट और लैंडस्केप इंटरफ़ेस ओरिएंटेशन के साथ काम करने के लिए "सही" या "सर्वश्रेष्ठ" दृष्टिकोण बता सकता है? ऐसा लगता है कि उस उद्देश्य के लिए मेरे द्वारा उपयोग किए जाने वाले सभी कार्यों को iOS 8 में पदावनत किया गया है, और मेरे शोध से कोई स्पष्ट, सुरुचिपूर्ण विकल्प नहीं निकला है। क्या मैं वास्तव में चौड़ाई और ऊंचाई को देखने के लिए खुद को निर्धारित करने वाला हूं कि क्या हम चित्र या लैंडस्केप मोड में हैं?

उदाहरण के लिए, मेरे विचार नियंत्रक में, मुझे निम्नलिखित छद्मकोड को कैसे लागू करना चाहिए?

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
के लिए डॉक्स पढ़ें UIViewController। "हैंडलिंग घूर्णन देखें" शीर्षक वाला अनुभाग देखें। यह बताता है कि आपको क्या करना चाहिए।
rammdy

कि वे पदावनत हैं एक सुराग है। आप कुछ और का उपयोग करना होगा .... कि कुछ और AutoLayout और आकार वर्ग होना चाहिए :-)
हारून

जवाबों:


262

Apple आकार वर्गों का उपयोग करने की सिफारिश करता है कि स्क्रीन स्पेस कितना उपलब्ध है, इसके मोटे उपाय के रूप में, ताकि आपका यूआई अपने लेआउट और उपस्थिति को महत्वपूर्ण रूप से बदल सके। विचार करें कि पोर्ट्रेट में एक iPad के आकार के वर्ग समान हैं, जैसा कि यह परिदृश्य में करता है (नियमित चौड़ाई, नियमित ऊंचाई)। इसका मतलब यह है कि आपका यूआई कमोबेश दोनों झुकावों के बीच समान होना चाहिए।

हालांकि, एक iPad में पोर्ट्रेट से परिदृश्य में बदलाव काफी महत्वपूर्ण है कि आपको यूआई में कुछ छोटे समायोजन करने की आवश्यकता हो सकती है, भले ही आकार की कक्षाएं नहीं बदली हों। चूंकि इंटरफ़ेस अभिविन्यास संबंधित तरीकों UIViewControllerको हटा दिया गया है, Apple अब UIViewControllerप्रतिस्थापन के रूप में निम्नलिखित नई पद्धति को लागू करने की सिफारिश करता है:

- (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:]

    }];
}

महान! अब आपको रोटेशन शुरू होने से ठीक पहले कॉलबैक मिल रहा है, और इसके खत्म होने के बाद। लेकिन वास्तव में यह जानने के बारे में कि क्या रोटेशन चित्र या परिदृश्य के लिए है?

माता-पिता के आकार में परिवर्तन के रूप में Apple रोटेशन के बारे में सोचने की सलाह देता है। दूसरे शब्दों में, परिदृश्य को पोर्ट्रेट से एक iPad रोटेशन के दौरान, आप इसे की जड़-स्तरीय दृश्य बस अपने को बदलने के रूप में सोच सकते हैं bounds.sizeसे {768, 1024}करने के लिए {1024, 768}। यह जानने के बाद, आपको चित्र या परिदृश्य के लिए घूम रहे हैं या नहीं, यह पता लगाने के लिए ऊपर sizeदी गई viewWillTransitionToSize:withTransitionCoordinator:विधि में पारित का उपयोग करना चाहिए ।

यदि आप चीजों को करने के नए iOS 8 तरीके से विरासत कोड को स्थानांतरित करने के लिए और भी अधिक सहज तरीका चाहते हैं, तो UIView पर इस सरल श्रेणी का उपयोग करने पर विचार करें , जिसका उपयोग यह निर्धारित करने के लिए किया जा सकता है कि क्या कोई दृश्य "पोर्ट्रेट" या "लैंडस्केप" इसके आधार पर है आकार।

संक्षेप में दुहराना:

  1. मूल रूप से भिन्न UI दिखाने के लिए आपको आकार वर्गों का उपयोग करना चाहिए (उदाहरण के लिए "iPhone-like" UI बनाम "iPad-like" UI)
  2. यदि आकार वर्ग में परिवर्तन होने पर आपको अपने यूआई में छोटे समायोजन करने की आवश्यकता होती है, लेकिन आपके कंटेनर (अभिभावक दृश्य) का आकार ऐसा करता है, जैसे कि जब iPad घूमता है, तो viewWillTransitionToSize:withTransitionCoordinator:UIViewController में कॉलबैक का उपयोग करें।
  3. आपके ऐप के प्रत्येक दृश्य को केवल उस स्थान के आधार पर लेआउट निर्णय लेना चाहिए जो इसे लेआउट में दिया गया है। विचारों की प्राकृतिक पदानुक्रम इस जानकारी को कम कर देती है।
  4. इसी तरह, statusBarOrientation"पोर्ट्रेट" बनाम "लैंडस्केप" के लिए एक दृश्य को लेआउट करने के लिए निर्धारित करने के लिए - जो मूल रूप से एक डिवाइस-स्तरीय संपत्ति है - का उपयोग न करें । स्टेटस बार ओरिएंटेशन का उपयोग केवल उन चीजों से निपटने वाले कोड द्वारा किया जाना चाहिए, UIWindowजो वास्तव में ऐप के बहुत मूल स्तर पर रहते हैं।

5
बहुत बढ़िया जवाब! BTW, AL पर आपका यूट्यूब वीडियो अविश्वसनीय रूप से जानकारीपूर्ण था। साझा करने के लिए Thanx। इसकी जांच - पड़ताल करें! youtube.com/watch?v=taWaW2GzfCI
smileBot

2
एकमात्र समस्या मुझे यह मिली कि कभी-कभी आप डिवाइस ओरिएंटेशन जानना चाहते हैं, और यह आपको इसकी जानकारी नहीं देगा। IPad पर इसे स्टेटस बार या डिवाइस ओरिएंटेशन वैल्यू में बदलाव से पहले कहा जाता है। यदि उपयोगकर्ता पोर्ट्रेट या पोर्ट्रेट-अप-डाउन में डिवाइस रखता है तो आप नहीं बता सकते। यह परीक्षण करना भी असंभव है, क्योंकि UIViewControllerTransitionCoordinator
मॉकिंग

@Darrarski आप उन मुद्दों के साथ सामना करने के लिए एक सुंदर समाधान मिल गया है?
Xvolks

तो viewdidlayoutsubviewsफिर कहाँ है ? मुझे लगा कि viewdidlayoutsubviewsरोटेशन के कारण बाध्य परिवर्तनों को पकड़ने के लिए उपयोग किया जाता है। क्या आप इसके बारे में विस्तार से बता सकते हैं?
हनी

1
यदि हम स्टेटसबोरिएशन का उपयोग नहीं करते हैं, तो परिदृश्य बनाम बाएं परिदृश्य के बीच अंतर कैसे करें? मुझे वह भेद चाहिए। इसके अलावा, यहाँ वर्णित अन्य समस्याएं भी हैं - stackoverflow.com/questions/53364498/…
दीपक शर्मा

17

स्माइबॉर्ग के बहुत अच्छी तरह से विस्तृत (और स्वीकृत) उत्तर के आधार पर, यहां स्विफ्ट 3 का उपयोग कर एक अनुकूलन है:

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()
    })        
}

और UICollectionViewDelegateFlowLayoutकार्यान्वयन में,

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

मैं केवल अधिसूचना केंद्र का उपयोग करता हूं:

एक अभिविन्यास चर जोड़ें (अंत में समझाएंगे)

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

दृश्य दिखाई देने पर अधिसूचना जोड़ें

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

जब दृश्य चला जाए तो अधिसूचना निकालें

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

अधिसूचना चालू होने पर वर्तमान अभिविन्यास प्राप्त होता है

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

अभिविन्यास (चित्र / परिदृश्य) की जाँच करता है और घटनाओं को संभालता है

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
        }
    }
}

मेरे द्वारा अभिविन्यास चर जोड़ने का कारण यह है कि जब किसी भौतिक उपकरण पर परीक्षण किया जाता है, तो अभिविन्यास अधिसूचना डिवाइस में प्रत्येक छोटी चाल पर कॉल की जाती है, और न केवल जब यह घूमता है। संस्करण जोड़ना और यदि कथन केवल कोड को कॉल करते हैं यदि यह विपरीत अभिविन्यास में बदल जाता है।


11
यह Apple का अनुशंसित दृष्टिकोण नहीं है क्योंकि इसका अर्थ है कि आपके ऐप का प्रत्येक दृश्य यह तय कर रहा है कि डिवाइस के अभिविन्यास के आधार पर कैसे प्रदर्शित किया जाए, इसके स्थान पर विचार नहीं किया गया है।
स्माइबॉर्ग

2
Apple 8.0 के साथ हार्डवेयर पर भी विचार नहीं कर रहा है। किसी AVPreview लेयर को बताएं यदि इसे किसी व्यू कंट्रोलर के सामने प्रस्तुत किया जाए तो उसे ओरिएंटेशन के बारे में चिंता करने की आवश्यकता नहीं है। काम नहीं करता है, लेकिन यह 8.2 में तय है
निक टर्नर

superकी viewDidAppearऔर viewWillDisappearकहा जाना चाहिए
एंड्रयू Bogaevskyi

नोट: UIDeviceOrientation! = UIInterfaceOrientation। मेरे प्रयोगों में, StatusBarOrientation विश्वसनीय नहीं है।
nnrales

2

UI दृष्टिकोण से, मेरा मानना ​​है कि विभिन्न अभिविन्यासों, आकारों और तराजू में इंटरफेस को संभालने के लिए आकार वर्ग का उपयोग करना Apple का अनुशंसित दृष्टिकोण है।

अनुभाग देखें: लक्षण यहां एक इंटरफ़ेस के आकार वर्ग और स्केल का वर्णन करते हैं: https://developer.apple.com/library/ios/releasenotes/General/WhatsNewIniOS/Articles/iOS3.html

"iOS 8 में नए फीचर्स जोड़े गए हैं जो स्क्रीन साइज और ओरिएंटेशन को और अधिक वर्सेटाइल बनाते हैं।"

यह एक अच्छा लेख है: https://carpeaqua.com/thinking-in-terms-of-ios-8-size-classes/

EDIT अपडेटेड लिंक: https://carpeaqua.com/2014/06/14/thinking-in-terms-of-ios-8-size-classes/ (क्रेडिट: कोएन)


हाँ, ऐसा लग रहा है कि फिलहाल उनकी पूरी साइट डाउन है।
एरन

लेख वास्तव में पढ़ने के लायक है और यहां सही पता है: carpeaqua.com/thinking-in-terms-of-ios-8-size-classes
uem

लेकिन क्या होगा अगर हम आकार वर्गों और UI के बारे में बात नहीं कर रहे हैं, लेकिन उदाहरण के लिए AVFoundation के बारे में। वीडियो रिकॉर्ड करते समय, कुछ मामलों में आपको सही मेटाडेटा सेट करने के लिए viewControllers ओरिएंटेशन पता होना चाहिए। यह सरल असंभव है। "बहुमुखी"।
जूलियन एफ वेइनर्ट

यही नहीं ओपी पूछ रहा था / बात कर रहा था।
एरोन

1
अपडेट किया गया लिंक: carpeaqua.com/2014/06/14/...
कोएन
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.