मैं बाधाओं को कैसे चेतन करूं?


959

मैं एक पुराने ऐप को अपडेट कर रहा हूं AdBannerViewऔर जब कोई विज्ञापन नहीं होता है, तो वह स्क्रीन को बंद कर देता है। जब कोई विज्ञापन आता है तो वह स्क्रीन पर स्लाइड होता है। मूल सामान।

पुरानी शैली, मैंने एक एनीमेशन ब्लॉक में फ्रेम सेट किया। नई शैली, मेरे पास IBOutletऑटो-लेआउट बाधा के लिए है जो Yस्थिति को निर्धारित करता है , इस मामले में यह पर्यवेक्षक के नीचे से दूरी है, और निरंतर को संशोधित करें:

- (void)moveBannerOffScreen {
    [UIView animateWithDuration:5 animations:^{
        _addBannerDistanceFromBottomConstraint.constant = -32;
    }];
    bannerIsVisible = FALSE;
}

- (void)moveBannerOnScreen {
    [UIView animateWithDuration:5 animations:^{
        _addBannerDistanceFromBottomConstraint.constant = 0;
    }];
    bannerIsVisible = TRUE;
}

और बैनर चलता है, बिल्कुल उम्मीद के मुताबिक, लेकिन कोई एनीमेशन नहीं


अद्यतन: मैं डब्ल्यूडब्ल्यूडीसी 12 को फिर से देख रहा हूँ जिसमें मास्ट्रिंग ऑटो लेआउट के लिए सर्वोत्तम अभ्यास हैं जो एनीमेशन को कवर करता है। यह चर्चा करता है कि CoreAnimation का उपयोग करके बाधाओं को कैसे अद्यतन किया जाए :

मैंने निम्नलिखित कोड के साथ प्रयास किया है, लेकिन ठीक उसी परिणाम प्राप्त करें:

- (void)moveBannerOffScreen {
    _addBannerDistanceFromBottomConstraint.constant = -32;
    [UIView animateWithDuration:2 animations:^{
        [self.view setNeedsLayout];
    }];
    bannerIsVisible = FALSE;
}

- (void)moveBannerOnScreen {
    _addBannerDistanceFromBottomConstraint.constant = 0;
    [UIView animateWithDuration:2 animations:^{
        [self.view setNeedsLayout];
    }];
    bannerIsVisible = TRUE;
}

एक साइड नोट पर, मैंने कई बार जांच की है और इसे मुख्य धागे पर निष्पादित किया जा रहा है ।


11
मैं इतने सारे इतने पर लिखने में कोई त्रुटि पर एक सवाल-जवाब के लिए की पेशकश की वोट से पहले कभी नहीं देखा है
abbood

3
यदि उत्तर में कोई टाइपो है, तो आपको उत्तर को संपादित करना चाहिए। इसलिए वे संपादन योग्य हैं।
___जॉर्फ

@ जेफामफोन - यदि आप टाइपो को इंगित करते हैं तो यह अधिक उपयोगी होगा इसलिए मुझे पता था कि गलती कहां थी। आप स्वयं ही उत्तर को संपादित कर सकते हैं और टाइपो को तय कर सकते हैं और बाकी सभी को हमारे डायट्रीब से बचा सकते हैं। मैंने इसे एनीमेशन ब्लॉक से स्थिरांक हटाने के लिए संपादित किया था, यदि आप इसका उल्लेख कर रहे थे।
DBD

1
मुझे नहीं पता कि टाइपो क्या है। मैं ऊपर टिप्पणियों का जवाब दे रहा था।
इ_म_जॉर्फ

9
तब टाइपो है सवाल। स्टुपिडली मैं "लेआउटइन्फाइड" के बजाय "सेटनैड्स लाइउट" टाइप कर रहा था। यह मेरे प्रश्न में स्पष्ट रूप से दिखाया गया है जब मैं अपने कोड को सही कमांड के साथ त्रुटि और स्क्रीनशॉट के साथ काटता हूं और पेस्ट करता हूं। अभी तक यह नोटिस करने के लिए प्रतीत नहीं हो सकता है कि किसी ने इसे इंगित किया है।
DBD

जवाबों:


1696

दो महत्वपूर्ण नोट:

  1. आपको layoutIfNeededएनीमेशन ब्लॉक के भीतर कॉल करना होगा । Apple वास्तव में आपको एनीमेशन ब्लॉक से पहले एक बार कॉल करने की सलाह देता है ताकि यह सुनिश्चित हो सके कि सभी लंबित लेआउट ऑपरेशन पूरे हो चुके हैं

  2. आपको इसे विशेष रूप से अभिभावक के दृष्टिकोण (जैसे self.view) पर कॉल करने की आवश्यकता है , न कि उस बच्चे के दृष्टिकोण से, जिसमें इससे जुड़ी अड़चनें हैं। ऐसा करने से सभी विवश विचारों को अद्यतन किया जाएगा , जिसमें अन्य विचार भी शामिल हैं जिन्हें देखने के लिए विवश किया जा सकता है कि आपने बाधा को बदल दिया है (उदाहरण देखें बी देखें ए के नीचे से जुड़ा हुआ है और आपने बस देखें ए का शीर्ष ऑफसेट बदल दिया है और आप बी देखें। इसके साथ चेतन करने के लिए)

इसे इस्तेमाल करे:

उद्देश्य सी

- (void)moveBannerOffScreen {
    [self.view layoutIfNeeded];

    [UIView animateWithDuration:5
        animations:^{
            self._addBannerDistanceFromBottomConstraint.constant = -32;
            [self.view layoutIfNeeded]; // Called on parent view
        }];
    bannerIsVisible = FALSE;
}

- (void)moveBannerOnScreen { 
    [self.view layoutIfNeeded];

    [UIView animateWithDuration:5
        animations:^{
            self._addBannerDistanceFromBottomConstraint.constant = 0;
            [self.view layoutIfNeeded]; // Called on parent view
        }];
    bannerIsVisible = TRUE;
}

स्विफ्ट 3

UIView.animate(withDuration: 5) {
    self._addBannerDistanceFromBottomConstraint.constant = 0
    self.view.layoutIfNeeded()
}

199
तुम्हें पता है क्या ... तुम्हारा जवाब काम करता है। WWDC काम करता है .... मेरी दृष्टि विफल हो जाती है। किसी कारण से मुझे यह महसूस करने में एक सप्ताह लग गया कि मैं setNeedsLayoutइसके बजाय कॉल कर रहा हूं layoutIfNeeded। मैं थोड़े घबड़ा गया हूं कि मैंने कितने घंटे बिताए, मैंने सिर्फ गलत तरीके का नाम टाइप नहीं किया।
DBD

23
समाधान काम करता है, लेकिन आपको एनीमेशन ब्लॉक के भीतर बाधा निरंतर बदलने की आवश्यकता नहीं है । एनीमेशन को बंद करने से पहले एक बार कसना सेट करना पूरी तरह से ठीक है। आपको अपना उत्तर संपादित करना चाहिए।
Ortwin Gentz

74
यह मेरे लिए शुरुआत में काम नहीं आया और तब मुझे महसूस हुआ कि आपको लेआउट को कॉल करने की आवश्यकता है, क्योंकि यह देखने के लिए नहीं है कि बाधाएं लागू होती हैं।
ओलिवर पियरमैन

20
LayoutIfNeeded का उपयोग करने से सभी सबवेशन रिफ्रेश होने में बाधा होगी, न कि बस। आप कैसे ही बाधाओं को बदल सकते हैं?
ngb

11
"Apple वास्तव में आपको एनीमेशन ब्लॉक से पहले एक बार कॉल करने की सलाह देता है ताकि यह सुनिश्चित हो सके कि सभी लंबित लेआउट ऑपरेशन पूरे हो चुके हैं", धन्यवाद, इस बारे में कभी नहीं सोचा था, लेकिन यह समझ में आता है।
रिक वैन डेर लिंडे

109

मैं प्रदान किए गए उत्तर की सराहना करता हूं, लेकिन मुझे लगता है कि इसे थोड़ा आगे ले जाना अच्छा होगा।

प्रलेखन से मूल ब्लॉक एनीमेशन

[containerView layoutIfNeeded]; // Ensures that all pending layout operations have been completed
[UIView animateWithDuration:1.0 animations:^{
     // Make all constraint changes here
     [containerView layoutIfNeeded]; // Forces the layout of the subtree animation block and then captures all of the frame changes
}];

लेकिन वास्तव में यह एक बहुत ही सरल परिदृश्य है। क्या होगा अगर मैं updateConstraintsविधि के माध्यम से सबव्यू अवरोधों को चेतन करना चाहता हूं ?

एक एनीमेशन ब्लॉक जो सबव्यू अपडेट कॉलस्ट्रेन्ट विधि को कॉल करता है

[self.view layoutIfNeeded];
[self.subView setNeedsUpdateConstraints];
[self.subView updateConstraintsIfNeeded];
[UIView animateWithDuration:1.0f delay:0.0f options:UIViewAnimationOptionLayoutSubviews animations:^{
    [self.view layoutIfNeeded];
} completion:nil];

UpdateConstraints विधि UIView उपवर्ग में ओवरराइड हो गई है और विधि के अंत में सुपर को कॉल करना होगा।

- (void)updateConstraints
{
    // Update some constraints

    [super updateConstraints];
}

AutoLayout गाइड वांछित होने के लिए बहुत कुछ छोड़ देता है लेकिन यह पढ़ने लायक है। मैं खुद इसे एक सरल और सूक्ष्म पतन एनीमेशन (0.2 सेकंड लंबा) के साथ एस UISwitchकी एक जोड़ी के साथ एक उप-वर्ग के एक भाग के रूप में उपयोग कर रहा हूं UITextField। उपर्युक्त के लिए बाधाओं को UIView उपवर्ग अपडेटकोस्ट्रेन्ट विधियों में संभाला जा रहा है जैसा कि ऊपर वर्णित है।


ऊपर दिए गए सभी तरीकों को कॉल करते समय self.view(और उस दृश्य के सब-वे पर नहीं), कॉल updateConstraintsIfNeededकरना आवश्यक नहीं है (क्योंकि उस दृश्य के setNeedsLayoutट्रिगर भी updateConstraints)। सबसे के लिए तुच्छ हो सकता है, लेकिन यह मेरे लिए अब तक नहीं था;)
वार्षिकी

आपके विशेष मामले में ऑटोलाययूट और स्प्रिंग्स और स्ट्रट्स लेआउट के पूर्ण परस्पर क्रिया को जाने बिना टिप्पणी करना कठिन है। मैं पूरी तरह से शुद्ध ऑटोलैयट परिदृश्य के बारे में बोल रहा हूं। मुझे यह जानने के लिए उत्सुक होना चाहिए कि वास्तव में आपके लेआउटसबव्यू पद्धति में क्या हो रहा है।
कैमरन लोवेल पामर

TranslatesAutoresizingMaskIntoConstraints = NO; यदि आप शुद्ध-ऑटोलैयूट करना चाहते हैं तो आपको इसे निश्चित रूप से अक्षम करना चाहिए।
कैमरन लोवेल पामर

मैंने वह नहीं देखा है, लेकिन मैं वास्तव में कुछ कोड के बिना मुद्दे पर बात नहीं कर सकता। हो सकता है कि आप एक TableView का मजाक उड़ा सकते हैं और इसे GitHub पर चिपका सकते हैं?
कैमरन लोवेल पामर

क्षमा करें, मैं gitHub का उपयोग नहीं करता :(
anneblue

74

आम तौर पर, आपको बस अवरोध को अपडेट करने और layoutIfNeededएनीमेशन ब्लॉक के अंदर कॉल करने की आवश्यकता होती है । यह या तो .constantएक की संपत्ति को बदल सकता है NSLayoutConstraint, हटाने की कमी (iOS 7) को जोड़ सकता है, या .activeबाधाओं की संपत्ति को बदल सकता है (iOS 8 और 9)।

नमूना कोड:

[UIView animateWithDuration:0.3 animations:^{
    // Move to right
    self.leadingConstraint.active = false;
    self.trailingConstraint.active = true;

    // Move to bottom
    self.topConstraint.active = false;
    self.bottomConstraint.active = true;

    // Make the animation happen
    [self.view setNeedsLayout];
    [self.view layoutIfNeeded];
}];

नमूना सेटअप:

Xcode प्रोजेक्ट तो नमूना एनीमेशन परियोजना।

विवाद

इस बारे में कुछ सवाल हैं कि क्या एनीमेशन ब्लॉक से पहले बाधा को बदल दिया जाना चाहिए , या इसके अंदर (पिछले उत्तरों को देखें)।

मार्टिन पिल्किंगटन के बीच आईओएस, और ऑटो फेरी लिखने वाले केन फेरी के बीच एक ट्विटर वार्तालाप निम्नलिखित है। केन बताते हैं कि हालांकि एनीमेशन ब्लॉक के बाहर स्थिरांक बदलना वर्तमान में काम कर सकता है , यह सुरक्षित नहीं है और उन्हें वास्तव में एनीमेशन ब्लॉक के अंदर बदलना चाहिए । https://twitter.com/kongtomorrow/status/440627401018466305

एनिमेशन:

नमूना परियोजना

यहां एक सरल प्रोजेक्ट दिखाया गया है कि एक दृश्य कैसे एनिमेटेड हो सकता है। यह ऑब्जेक्टिव सी का उपयोग कर रहा है और .activeकई बाधाओं की संपत्ति को बदलकर दृश्य को एनिमेट करता है । https://github.com/shepting/SampleAutoLayoutAnimation


नए सक्रिय ध्वज का उपयोग करके एक उदाहरण दिखाने के लिए +1। इसके अलावा, एनीमेशन ब्लॉक के बाहर बाधा को बदलना हमेशा मेरे लिए एक हैक की तरह महसूस होता है
कोरी हिंटन

मैंने गितुब में एक मुद्दा उठाया क्योंकि यह समाधान उस दृश्य को वापस स्थानांतरित करने के लिए काम नहीं करता है जहां यह था। मेरा मानना ​​है कि सक्रिय परिवर्तन सही समाधान नहीं है और आपको इसके बजाय प्राथमिकता बदलनी चाहिए। 750 से ऊपर सेट करें, और नीचे 250 तक, फिर UILayoutPyerityDefaultHigh और UILayoutPyerityDefaultLow के बीच कोड वैकल्पिक रूप से।
मलहल

ब्लॉक के अंदर अपडेट करने का एक और कारण यह है कि यह कॉलिंग कोड से होने वाले परिवर्तनों को अलग करता है जो कि लेआउट लेआउट भी कह सकते हैं। (और ट्विटर लिंक के लिए धन्यवाद)
क्रिस कॉनवर

1
बहुत बढ़िया जवाब। विशेष रूप से क्योंकि आप इस बारे में मार्टिन और केन की बातचीत का उल्लेख करते हैं।
जोना

मैं बाधाओं को अद्यतन करने के तरीके के बारे में उलझन में हूँ और यह लिखा है । क्या आप कृपया देख सकते हैं?
हनी

36
// Step 1, update your constraint
self.myOutletToConstraint.constant = 50; // New height (for example)

// Step 2, trigger animation
[UIView animateWithDuration:2.0 animations:^{

    // Step 3, call layoutIfNeeded on your animated view's parent
    [self.view layoutIfNeeded];
}];

29

स्विफ्ट 4 समाधान

UIView.animate

तीन सरल चरण:

  1. बाधाओं को बदलें, उदाहरण के लिए:

    heightAnchor.constant = 50
  2. युक्त को बताएं viewकि इसका लेआउट गंदा है और ऑटोलैयट को लेआउट को पुनर्गणना करना चाहिए:

    self.view.setNeedsLayout()
  3. एनीमेशन ब्लॉक में लेआउट को पुनर्गणना करने के लिए लेआउट को बताएं, जो सीधे फ्रेम सेट करने के बराबर है (इस मामले में ऑटोलयूट फ़्रेम सेट करेगा):

    UIView.animate(withDuration: 0.5) {
        self.view.layoutIfNeeded()
    }

पूरा सरलतम उदाहरण:

heightAnchor.constant = 50
self.view.setNeedsLayout()
UIView.animate(withDuration: 0.5) {
    self.view.layoutIfNeeded()
}

पक्षीय लेख

एक वैकल्पिक 0 वां चरण है - बाधाओं को बदलने से पहले आप self.view.layoutIfNeeded()यह सुनिश्चित करने के लिए कॉल कर सकते हैं कि एनीमेशन के लिए प्रारंभिक बिंदु राज्य से है पुरानी बाधाओं के साथ लागू किया गया है (मामले में कुछ अन्य बाधाओं में बदलाव थे जिन्हें एनीमेशन में शामिल नहीं किया जाना चाहिए ):

otherConstraint.constant = 30
// this will make sure that otherConstraint won't be animated but will take effect immediately
self.view.layoutIfNeeded()

heightAnchor.constant = 50
self.view.setNeedsLayout()
UIView.animate(withDuration: 0.5) {
    self.view.layoutIfNeeded()
}

UIViewPropertyAnimator

चूंकि iOS 10 के साथ हमें एक नया ऐनिमेटिंग मैकेनिज्म मिला है - UIViewPropertyAnimatorहमें पता होना चाहिए कि मूल रूप से एक ही मैकेनिज्म इस पर लागू होता है। कदम मूल रूप से समान हैं:

heightAnchor.constant = 50
self.view.setNeedsLayout()
let animator = UIViewPropertyAnimator(duration: 0.5, timingParameters: UICubicTimingParameters(animationCurve: .linear))
animator.addAnimations {
    self.view.layoutIfNeeded()
}
animator.startAnimation()

चूंकि animatorएनीमेशन का एक एनकैप्सुलेशन है, हम इसे संदर्भ रख सकते हैं और इसे बाद में कॉल कर सकते हैं। हालांकि, एनीमेशन ब्लॉक के बाद से हम केवल फ्रेम को पुनर्गणना करने के लिए ऑटोलैयट को बताते हैं, हमें कॉल करने से पहले बाधाओं को बदलना होगा startAnimation। इसलिए ऐसा कुछ संभव है:

// prepare the animator first and keep a reference to it
let animator = UIViewPropertyAnimator(duration: 0.5, timingParameters: UICubicTimingParameters(animationCurve: .linear))
animator.addAnimations {
    self.view.layoutIfNeeded()
}

// at some other point in time we change the constraints and call the animator
heightAnchor.constant = 50
self.view.setNeedsLayout()
animator.startAnimation()

बाधाओं को बदलने और एक एनिमेटर शुरू करने का क्रम महत्वपूर्ण है - अगर हम सिर्फ बाधाओं को बदलते हैं और कुछ बाद के बिंदु के लिए हमारे एनिमेटर को छोड़ देते हैं, तो अगला रीड्रा चक्र ऑटोलैयूट पुनर्गणना को लागू कर सकता है और परिवर्तन एनिमेटेड नहीं होगा।

इसके अलावा, याद रखें कि एक एकल एनिमेटर गैर-पुन: प्रयोज्य है - एक बार जब आप इसे चलाते हैं, तो आप इसे "पुन: चलाएँ" नहीं कर सकते। इसलिए मुझे लगता है कि ऐनिमेटर को रखने के लिए वास्तव में एक अच्छा कारण नहीं है, जब तक कि हम इसका उपयोग इंटरैक्टिव एनीमेशन को नियंत्रित करने के लिए नहीं करते हैं।


स्विफ्ट 5 में भी शानदार है
spnkr

layoutIfNeeded () कुंजी है
मेधी

15

स्टोरीबोर्ड, कोड, टिप्स और कुछ गोटेच

अन्य उत्तर ठीक हैं, लेकिन यह एक हालिया उदाहरण का उपयोग करते हुए बाधाओं को कम करने के कुछ महत्वपूर्ण महत्वपूर्ण पर प्रकाश डाला गया है। निम्नलिखित का एहसास होने से पहले मैं बहुत भिन्नताओं से गुज़रा:

एक मजबूत संदर्भ रखने के लिए आप उन अवरोधों को बनाएं जिन्हें आप कक्षा चर में लक्षित करना चाहते हैं। स्विफ्ट में मैंने आलसी चर का उपयोग किया:

lazy var centerYInflection:NSLayoutConstraint = {
       let temp =  self.view.constraints.filter({ $0.firstItem is MNGStarRating }).filter ( { $0.secondItem is UIWebView }).filter({ $0.firstAttribute == .CenterY }).first
        return temp!
}()

कुछ प्रयोग के बाद मैंने नोट किया कि एक को ABOVE (उर्फ पर्यवेक्षणीय) को दो दृष्टिकोणों से कसना प्राप्त होता है जहां कसना परिभाषित किया गया है। नीचे दिए गए उदाहरण में (दोनों MNGStarRating और UIWebView दो प्रकार के आइटम हैं जिनके बीच मैं एक बाधा पैदा कर रहा हूं, और वे स्वयं के भीतर साक्षात्कार हैं)।

छानने का काम

मैं स्विफ्ट के फिल्टर विधि का लाभ उठाता हूं ताकि वांछित बिंदु को अलग किया जा सके जो विभक्ति बिंदु के रूप में काम करेगा। एक भी अधिक जटिल हो सकता है, लेकिन फ़िल्टर यहाँ एक अच्छा काम करता है।

एनिमेटेड स्विफ्ट का उपयोग करते हुए बाधाओं

नोटा बेने - यह उदाहरण स्टोरीबोर्ड / कोड समाधान है और मानता है कि किसी ने स्टोरीबोर्ड में डिफ़ॉल्ट बाधाएं बनाई हैं। फिर कोड का उपयोग करके परिवर्तन को चेतन किया जा सकता है।

मान लें कि आप सटीक मानदंड के साथ फ़िल्टर करने के लिए एक संपत्ति बनाते हैं और अपने एनीमेशन के लिए एक विशिष्ट विभक्ति बिंदु प्राप्त करते हैं (बेशक आप कई बाधाओं के लिए एक सरणी और लूप के लिए फ़िल्टर कर सकते हैं)

lazy var centerYInflection:NSLayoutConstraint = {
    let temp =  self.view.constraints.filter({ $0.firstItem is MNGStarRating }).filter ( { $0.secondItem is UIWebView }).filter({ $0.firstAttribute == .CenterY }).first
    return temp!
}()

....

कुछ समय बाद...

@IBAction func toggleRatingView (sender:AnyObject){

    let aPointAboveScene = -(max(UIScreen.mainScreen().bounds.width,UIScreen.mainScreen().bounds.height) * 2.0)

    self.view.layoutIfNeeded()


    //Use any animation you want, I like the bounce in springVelocity...
    UIView.animateWithDuration(1.0, delay: 0.0, usingSpringWithDamping: 0.3, initialSpringVelocity: 0.75, options: [.CurveEaseOut], animations: { () -> Void in

        //I use the frames to determine if the view is on-screen
        if CGRectContainsRect(self.view.frame, self.ratingView.frame) {

            //in frame ~ animate away
            //I play a sound to give the animation some life

            self.centerYInflection.constant = aPointAboveScene
            self.centerYInflection.priority = UILayoutPriority(950)

        } else {

            //I play a different sound just to keep the user engaged
            //out of frame ~ animate into scene
            self.centerYInflection.constant = 0
            self.centerYInflection.priority = UILayoutPriority(950)
            self.view.setNeedsLayout()
            self.view.layoutIfNeeded()
         }) { (success) -> Void in

            //do something else

        }
    }
}

कई गलत मोड़

ये नोट वास्तव में युक्तियों का एक सेट है जो मैंने खुद के लिए लिखा था। मैंने व्यक्तिगत रूप से और दर्द से सभी काम नहीं किए। उम्मीद है कि यह गाइड दूसरों को बख्श सकता है।

  1. ZPositioning के लिए बाहर देखो। कभी-कभी जब स्पष्ट रूप से कुछ भी नहीं हो रहा होता है, तो आपको कुछ अन्य दृश्यों को छिपाना चाहिए या अपने एनिमेटेड दृश्य का पता लगाने के लिए व्यू डीबगर का उपयोग करना चाहिए। मुझे ऐसे मामले भी मिले हैं, जहां एक उपयोगकर्ता परिभाषित रनटाइम अट्रैक्शन स्टोरीबोर्ड के xml में खो गया था और एनिमेटेड दृश्य को कवर किया गया था (काम करते समय)।

  2. प्रलेखन (नए और पुराने), त्वरित सहायता और हेडर पढ़ने के लिए हमेशा एक मिनट का समय लें। AutoLayout बाधाओं को बेहतर तरीके से प्रबंधित करने के लिए Apple बहुत सारे बदलाव करता रहता है (स्टैक विचार देखें)। या कम से कम AutoLayout रसोई की किताब । ध्यान रखें कि कभी-कभी सबसे अच्छा समाधान पुराने प्रलेखन / वीडियो में होते हैं।

  3. एनीमेशन में मूल्यों के साथ चारों ओर खेलें और अन्य चेतनता अवधि वेरिएंट का उपयोग करने पर विचार करें।

  4. अन्य स्थिरांक में परिवर्तन निर्धारित करने के मापदंड के रूप में विशिष्ट लेआउट मानों को हार्डकोड न करें, इसके बजाय उन मानों का उपयोग करें जो आपको दृश्य के स्थान को निर्धारित करने की अनुमति देते हैं। CGRectContainsRectएक उदाहरण है

  5. यदि आवश्यक हो, तो बाधा परिभाषा में भाग लेने वाले दृश्य से जुड़े लेआउट मार्जिन का उपयोग करने में संकोच न करें let viewMargins = self.webview.layoutMarginsGuide: उदाहरण के लिए
  6. वह काम न करें जो आपको नहीं करना है, स्टोरीबोर्ड पर बाधाओं के साथ सभी विचारों को संपत्ति से जुड़ी बाधाएं हैं।
  7. 1000 से कम के लिए किसी भी बाधाओं के लिए अपनी प्राथमिकताएं बदलें। मैंने स्टोरीबोर्ड पर 250 (कम) या 750 (उच्च) के लिए मेरा सेट किया; (यदि आप किसी कोड में 1000 प्राथमिकता को बदलने की कोशिश करते हैं तो ऐप क्रैश हो जाएगा क्योंकि 1000 की आवश्यकता है)
  8. तुरंत सक्रियण का उपयोग करने की कोशिश नहीं करने पर विचार करें औरConstraints को निष्क्रिय करें (उनके पास अपनी जगह है लेकिन जब आप सीख रहे हैं या यदि आप इनका उपयोग करके एक स्टोरीबोर्ड का उपयोग कर रहे हैं, तो इसका मतलब है कि आपका बहुत अधिक ~ वे एक जगह है हालांकि नीचे जैसा देखा गया है)
  9. AddConstraints / removeConstraints का उपयोग न करने पर विचार करें जब तक कि आप वास्तव में कोड में एक नई बाधा नहीं जोड़ रहे हों। मैंने पाया कि ज्यादातर बार मैं स्टोरीबोर्ड में विचारों को वांछित बाधाओं (दृश्य को ऑफस्क्रीन रखते हुए) के साथ लेआउट करता हूं, फिर कोड में, मैं पहले दृश्य को स्थानांतरित करने के लिए स्टोरीबोर्ड में बनाई गई बाधाओं को चेतन करता हूं।
  10. मैंने नए NSAnchorLayout वर्ग और उपवर्गों के साथ बाधाओं का निर्माण करने में बहुत समय बर्बाद किया। ये ठीक काम करते हैं लेकिन मुझे यह महसूस करने में थोड़ा समय लगा कि स्टोरीबोर्ड में पहले से मौजूद सभी बाधाओं की मुझे जरूरत थी। यदि आप कोड में बाधाओं का निर्माण करते हैं तो निश्चित रूप से इस पद्धति का उपयोग अपनी बाधाओं को एकत्र करने के लिए करें:

स्टोरीबोर्ड का उपयोग करते समय AVOID को समाधान का त्वरित नमूना

private var _nc:[NSLayoutConstraint] = []
    lazy var newConstraints:[NSLayoutConstraint] = {

        if !(self._nc.isEmpty) {
            return self._nc
        }

        let viewMargins = self.webview.layoutMarginsGuide
        let minimumScreenWidth = min(UIScreen.mainScreen().bounds.width,UIScreen.mainScreen().bounds.height)

        let centerY = self.ratingView.centerYAnchor.constraintEqualToAnchor(self.webview.centerYAnchor)
        centerY.constant = -1000.0
        centerY.priority = (950)
        let centerX =  self.ratingView.centerXAnchor.constraintEqualToAnchor(self.webview.centerXAnchor)
        centerX.priority = (950)

        if let buttonConstraints = self.originalRatingViewConstraints?.filter({

            ($0.firstItem is UIButton || $0.secondItem is UIButton )
        }) {
            self._nc.appendContentsOf(buttonConstraints)

        }

        self._nc.append( centerY)
        self._nc.append( centerX)

        self._nc.append (self.ratingView.leadingAnchor.constraintEqualToAnchor(viewMargins.leadingAnchor, constant: 10.0))
        self._nc.append (self.ratingView.trailingAnchor.constraintEqualToAnchor(viewMargins.trailingAnchor, constant: 10.0))
        self._nc.append (self.ratingView.widthAnchor.constraintEqualToConstant((minimumScreenWidth - 20.0)))
        self._nc.append (self.ratingView.heightAnchor.constraintEqualToConstant(200.0))

        return self._nc
    }()

यदि आप इन युक्तियों में से किसी एक या अधिक सरल को भूल जाते हैं, जैसे कि लेआउट को कहां जोड़ा जाए। यदि ऐसा किया जाता है, तो सबसे अधिक संभावना है कि कुछ भी नहीं होगा: इस मामले में आपके पास इस तरह का आधा बेक किया हुआ समाधान हो सकता है:

एनबी - नीचे दिए गए ऑटोलॉयट सेक्शन और मूल गाइड को पढ़ने के लिए कुछ समय निकालें। अपने डायनेमिक एनिमेटरों को पूरक करने के लिए इन तकनीकों का उपयोग करने का एक तरीका है।

UIView.animateWithDuration(1.0, delay: 0.0, usingSpringWithDamping: 0.3, initialSpringVelocity: 1.0, options: [.CurveEaseOut], animations: { () -> Void in

            //
            if self.starTopInflectionPoint.constant < 0  {
                //-3000
                //offscreen
                self.starTopInflectionPoint.constant = self.navigationController?.navigationBar.bounds.height ?? 0
                self.changeConstraintPriority([self.starTopInflectionPoint], value: UILayoutPriority(950), forView: self.ratingView)

            } else {

                self.starTopInflectionPoint.constant = -3000
                 self.changeConstraintPriority([self.starTopInflectionPoint], value: UILayoutPriority(950), forView: self.ratingView)
            }

        }) { (success) -> Void in

            //do something else
        }

    }

AutoLayout गाइड से स्निपेट (ध्यान दें कि दूसरा स्निपेट OS X का उपयोग करने के लिए है)। BTW - यह अब तक के मौजूदा गाइड में नहीं है जहां तक ​​मैं देख सकता हूं। पसंदीदा तकनीकों का विकास जारी है।

ऑटो लेआउट द्वारा किए गए परिवर्तन एनिमेटेड

यदि आपको ऑटो लेआउट द्वारा किए गए परिवर्तनों को पूरा करने पर पूर्ण नियंत्रण की आवश्यकता है, तो आपको अपने अवरोधों को प्रोग्रामेटिक रूप से बदलना होगा। मूल अवधारणा iOS और OS X दोनों के लिए समान है, लेकिन कुछ मामूली अंतर हैं।

एक iOS ऐप में, आपका कोड कुछ इस तरह दिखाई देगा:

[containerView layoutIfNeeded]; // Ensures that all pending layout operations have been completed
[UIView animateWithDuration:1.0 animations:^{
     // Make all constraint changes here
     [containerView layoutIfNeeded]; // Forces the layout of the subtree animation block and then captures all of the frame changes
}];

OS X में, परत-समर्थित एनिमेशन का उपयोग करते समय निम्नलिखित कोड का उपयोग करें:

[containterView layoutSubtreeIfNeeded];
[NSAnimationContext runAnimationGroup:^(NSAnimationContext *context) {
     [context setAllowsImplicitAnimation: YES];
     // Make all constraint changes here
     [containerView layoutSubtreeIfNeeded];
}];

जब आप परत-समर्थित एनिमेशन का उपयोग नहीं कर रहे हैं, तो आपको बाधा के एनीमेटर का उपयोग करके निरंतर को चेतन करना होगा:

[[constraint animator] setConstant:42];

जो लोग बेहतर सीखते हैं उनके लिए Apple के इस शुरुआती वीडियो को देखें

विशेस ध्यान दें

अक्सर प्रलेखन में छोटे नोट या कोड के टुकड़े होते हैं जो बड़े विचारों को जन्म देते हैं। उदाहरण के लिए डायनेमिक एनिमेटरों के लिए ऑटो लेआउट बाधाओं को जोड़ना एक बड़ा विचार है।

गुड लक और मे द फोर्स आपके साथ हो।



6

कार्य समाधान 100% स्विफ्ट 3.1

मैंने सभी उत्तर पढ़ लिए हैं और लाइनों के कोड और पदानुक्रम को साझा करना चाहता हूं, जो मैंने अपने सभी अनुप्रयोगों में उन्हें सही तरीके से चेतन करने के लिए उपयोग किए हैं, यहां कुछ समाधान काम नहीं कर रहे हैं, आपको उन्हें इस समय धीमे उपकरणों जैसे आईफोन 5 की जांच करनी चाहिए।

self.view.layoutIfNeeded() // Force lays of all subviews on root view
UIView.animate(withDuration: 0.5) { [weak self] in // allowing to ARC to deallocate it properly
       self?.tbConstraint.constant = 158 // my constraint constant change
       self?.view.layoutIfNeeded() // Force lays of all subviews on root view again.
}

4

मैं बाधाओं को चेतन करने की कोशिश कर रहा था और वास्तव में एक अच्छी व्याख्या करना आसान नहीं था।

अन्य जवाब जो कह रहे हैं वह पूरी तरह से सच है: आपको [self.view layoutIfNeeded];अंदर कॉल करने की आवश्यकता है animateWithDuration: animations:। हालाँकि, दूसरा महत्वपूर्ण बिंदु यह है कि NSLayoutConstraintआप चेतन करने के इच्छुक लोगों के लिए संकेत दें ।

मैंने GitHub में एक उदाहरण बनाया


4

Xcode 8.3.3 के साथ स्विफ्ट 3 के लिए कार्य करना और अभी-अभी परीक्षण किया गया समाधान:

self.view.layoutIfNeeded()
self.calendarViewHeight.constant = 56.0

UIView.animate(withDuration: 0.5, delay: 0.0, options: UIViewAnimationOptions.curveEaseIn, animations: {
        self.view.layoutIfNeeded()
    }, completion: nil)

बस यह ध्यान रखें कि self.calendarViewHeight एक कस्टम व्यू (कैलेंडर दृश्य) के लिए संदर्भित बाधा है। मैंने .layoutIfNeeded () को self.view पर बुलाया और self.calendarView पर नहीं

उममीद है कि इससे मदद मिलेगी।


3

इस बारे में एक लेख चर्चा है: http://weblog.invasivecode.com/post/42362079291/auto-layout-and-core-animation-auto-layout-was

जिसमें, उन्होंने इस तरह कोडित किया:

- (void)handleTapFrom:(UIGestureRecognizer *)gesture {
    if (_isVisible) {
        _isVisible = NO;
        self.topConstraint.constant = -44.;    // 1
        [self.navbar setNeedsUpdateConstraints];  // 2
        [UIView animateWithDuration:.3 animations:^{
            [self.navbar layoutIfNeeded]; // 3
        }];
    } else {
        _isVisible = YES;
        self.topConstraint.constant = 0.;
        [self.navbar setNeedsUpdateConstraints];
        [UIView animateWithDuration:.3 animations:^{
            [self.navbar layoutIfNeeded];
        }];
    }
}

आशा है ये मदद करेगा।


1

बाधा एनीमेशन के संदर्भ में, मैं एक विशिष्ट स्थिति का उल्लेख करना चाहूंगा, जहां मैं एक कीबोर्ड_रूपित अधिसूचना के भीतर एक बाधा को तुरंत एनिमेटेड करता हूं।

बाधा ने एक टेक्स्टफील्ड से कंटेनर के शीर्ष तक एक शीर्ष स्थान को परिभाषित किया। कीबोर्ड खोलने पर, मैं सिर्फ 2 से कंटीन्यू को विभाजित करता हूं।

मैं सीधे कीबोर्ड अधिसूचना के भीतर एक सुसंगत चिकनी बाधा एनीमेशन को प्राप्त करने में असमर्थ था। लगभग आधा बार दृश्य बस अपनी नई स्थिति पर कूद जाएगा - बिना एनिमेशन के।

यह मुझे पता चला कि कीबोर्ड खोलने के परिणामस्वरूप कुछ अतिरिक्त लेआउटिंग हो सकते हैं। 10ms की देरी के साथ एक साधारण डिस्पैच_ आफ्टर ब्लॉक को जोड़ने से एनिमेशन हर बार चलता है - कोई जंपिंग नहीं।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.