2015-10-12 10 views
19

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

(
    "<NSLayoutConstraint:0x1396632d0 'UISV-canvas-connection' UIStackView:0x1392c5020.top == UILabel:0x13960cd30'Also available on iBooks'.top>", 
    "<NSLayoutConstraint:0x139663470 'UISV-canvas-connection' V:[UIButton:0x139554f80]-(0)-| (Names: '|':UIStackView:0x1392c5020)>", 
    "<NSLayoutConstraint:0x139552350 'UISV-hiding' V:[UIStackView:0x1392c5020(0)]>", 
    "<NSLayoutConstraint:0x139663890 'UISV-spacing' V:[UILabel:0x13960cd30'Also available on iBooks']-(8)-[UIButton:0x139554f80]>" 
) 

विशेष रूप से, UISV-spacing बाधा: जब एक UIStackView इसकी उच्च बाधा हो जाता है एक 0 लगातार छुपा है, लेकिन है कि आंतरिक stackview की रिक्ति बाधा के साथ संघर्ष करने के लिए लगता है: यह 8 अंक की आवश्यकता है मेरे लेबल और बटन के बीच, जो छिपाने की बाधा के साथ असहनीय है और इसलिए बाधाएं दुर्घटनाग्रस्त हो जाती हैं।

क्या इसके आसपास कोई रास्ता है? मैंने छिपे हुए स्टैक व्यू के सभी आंतरिक स्टैक व्यू को दोबारा छिपाने की कोशिश की है, लेकिन इसके परिणामस्वरूप अजीब एनिमेशन होते हैं जहां सामग्री स्क्रीन से बाहर निकलती है, और गंभीर एफपीएस बूंदों को बूट करने का कारण बनती है, जबकि समस्या को ठीक नहीं किया जाता है।

उत्तर

11

आदर्श रूप से हम UISV-spacing बाधा को कम मूल्य पर प्राथमिकता निर्धारित कर सकते हैं, लेकिन ऐसा करने का कोई तरीका नहीं दिखता है। :)

मुझे छिपाने से पहले spacing नेस्टेड स्टैक दृश्यों की संपत्ति को 0 से पहले सफलतापूर्वक सेट करने और इसे फिर से दिखने के बाद उचित मूल्य पर पुनर्स्थापित करने में सफलता मिल रही है।

मुझे लगता है कि नेस्टेड स्टैक दृश्यों पर यह बार-बार ऐसा करना काम करेगा। आप एक शब्दकोश में spacing संपत्ति का मूल मान संग्रहीत कर सकते हैं और बाद में इसे पुनर्स्थापित कर सकते हैं।

मेरी परियोजना में केवल घोंसले का एक स्तर है, इसलिए मुझे यकीन नहीं है कि इससे एफपीएस की समस्याएं आती हैं। जब तक आप अंतराल में बदलावों को एनिमेट नहीं करते हैं, मुझे नहीं लगता कि यह बहुत अधिक हिट पैदा करेगा।

+1

धन्यवाद, मैं आज कोशिश करूँगा और अगर यह काम करता है तो जवाब स्वीकार करें :) –

12

मैंने यूआईएसवी-छिपाने के साथ एक ही समस्या को मारा। मेरे लिए, समाधान अपनी खुद की बाधाओं की प्राथमिकताओं को कम से कम (1000) से कम करने के लिए कम करना था। जब यूआईएसवी-छिपाने की बाधाओं को जोड़ा जाता है, तो वे प्राथमिकता लेते हैं और बाधाएं अब संघर्ष नहीं करती हैं।

+2

समस्या यह है कि मुझे उन तत्वों पर अपने आप में कोई बाधा नहीं है :(हालांकि, इस मामले में अन्य समान मुद्दों को हल किया गया है I किया। –

+0

मुझे एक ही समस्या थी और यह मेरे लिए तय किया गया। – SeanR

+0

पवित्र गाय! सोचने, सोचने और कुछ गंभीर दिमागी तूफान के एक दिन बाद, यह था। यह समझ में आता है कि UIStackView बाधाओं पर काम करेगा जो हम नहीं करते हैं ' टी देखें, लेकिन हमारी बाधाओं के साथ स्वाभाविक रूप से संघर्ष करें। महान उत्तर, धन्यवाद @ जेनस! – kbpontius

13

यह नेस्टेड स्टैक दृश्यों को छिपाने के साथ एक ज्ञात समस्या है।

अनिवार्य रूप से इस समस्या का समाधान कर रहे हैं 3:

  1. बदलें 0 रिक्ति है, लेकिन फिर आप पिछले रिक्ति मूल्य याद करने की आवश्यकता होगी।
  2. innerStackView.removeFromSuperview() पर कॉल करें, लेकिन फिर आपको याद रखना होगा कि स्टैक व्यू कहां डालना है।
  3. कम से कम एक 999 बाधा के साथ एक UIView में स्टैक व्यू लपेटें। जैसे शीर्ष @ 1000, अग्रणी @ 1000, पीछे @ 1000, नीचे @ 999।

तीसरा विकल्प मेरी राय में सबसे अच्छा है। इस समस्या के बारे में अधिक जानकारी के लिए, ऐसा क्यों होता है, विभिन्न समाधान, और समाधान 3 को कैसे कार्यान्वित करें, my answer to a similar question देखें।

+1

समाधान 3 मेरे लिए काम करता है, मैंने सभी किनारों (जैसे सामान्य एक) के लिए बाध्य एक UIView के अंदर स्टैक दृश्य डाल दिया। ऐसा लगता है कि स्टैक व्यू रूट व्यू होने की तरह नहीं है। – malhal

0

स्नैपकिट बाधाओं का उपयोग करके स्विफ्ट 3 कक्षा के रूप में लिखे गए सेंसफुल के सुझाव # 3 का कार्यान्वयन यहां दिया गया है।मैं भी गुण अधिभावी कोशिश की, लेकिन यह कभी नहीं चेतावनियों के बिना काम कर रहा है, तो मैं लपेटकर UIStackView साथ रह सकते हैं:

class NestableStackView: UIView { 
    private var actualStackView = UIStackView() 

    override init(frame: CGRect) { 
     super.init(frame: frame); 
     addSubview(actualStackView); 
     actualStackView.snp.makeConstraints { (make) in 
      // Lower edges priority to allow hiding when spacing > 0 
      make.edges.equalToSuperview().priority(999); 
     } 
    } 

    convenience init() { 
     self.init(frame: CGRect.zero); 
    } 

    required init?(coder aDecoder: NSCoder) { 
     fatalError("init(coder:) has not been implemented") 
    } 

    func addArrangedSubview(_ view: UIView) { 
     actualStackView.addArrangedSubview(view); 
    } 

    func removeArrangedSubview(_ view: UIView) { 
     actualStackView.removeArrangedSubview(view); 
    } 

    var axis: UILayoutConstraintAxis { 
     get { 
      return actualStackView.axis; 
     } 
     set { 
      actualStackView.axis = newValue; 
     } 
    } 

    open var distribution: UIStackViewDistribution { 
     get { 
      return actualStackView.distribution; 
     } 
     set { 
      actualStackView.distribution = newValue; 
     } 
    } 

    var alignment: UIStackViewAlignment { 
     get { 
      return actualStackView.alignment; 
     } 
     set { 
      actualStackView.alignment = newValue; 
     } 
    } 

    var spacing: CGFloat { 
     get { 
      return actualStackView.spacing; 
     } 
     set { 
      actualStackView.spacing = newValue; 
     } 
    } 
} 
7

तो आप इस राशि:

broken animation

और समस्या यह है , जब आप पहली बार भीतरी ढेर पतन, आप ऑटो लेआउट त्रुटियों मिलती है:,

2017-07-02 15:40:02.377297-0500 nestedStackViews[17331:1727436] [LayoutConstraints] Unable to simultaneously satisfy constraints. 
    Probably at least one of the constraints in the following list is one you don't want. 
    Try this: 
     (1) look at each constraint and try to figure out which you don't expect; 
     (2) find the code that added the unwanted constraint or constraints and fix it. 
(
    "<NSLayoutConstraint:0x62800008ce90 'UISV-canvas-connection' UIStackView:0x7fa57a70fce0.top == UILabel:0x7fa57a70ffb0'Top Label of Inner Stack'.top (active)>", 
    "<NSLayoutConstraint:0x62800008cf30 'UISV-canvas-connection' V:[UILabel:0x7fa57d30def0'Bottom Label of Inner Sta...']-(0)-| (active, names: '|':UIStackView:0x7fa57a70fce0)>", 
    "<NSLayoutConstraint:0x62000008bc70 'UISV-hiding' UIStackView:0x7fa57a70fce0.height == 0 (active)>", 
    "<NSLayoutConstraint:0x62800008cf80 'UISV-spacing' V:[UILabel:0x7fa57a70ffb0'Top Label of Inner Stack']-(8)-[UILabel:0x7fa57d30def0'Bottom Label of Inner Sta...'] (active)>" 
) 

Will attempt to recover by breaking constraint 
<NSLayoutConstraint:0x62800008cf80 'UISV-spacing' V:[UILabel:0x7fa57a70ffb0'Top Label of Inner Stack']-(8)-[UILabel:0x7fa57d30def0'Bottom Label of Inner Sta...'] (active)> 

Make a symbolic breakpoint at UIViewAlertForUnsatisfiableConstraints to catch this in the debugger. 
The methods in the UIConstraintBasedLayoutDebugging category on UIView listed in <UIKit/UIView.h> may also be helpful. 

समस्या के रूप में आप ने कहा कि बाहरी स्टेक दृश्य एक heig लागू होता है आंतरिक स्टैक दृश्य में एचटी = 0 बाधा। यह अपने स्वयं के सबव्यू के बीच आंतरिक स्टैक व्यू द्वारा लागू 8 बिंदु पैडिंग बाधा के साथ संघर्ष करता है। दोनों बाधाओं को एक साथ संतुष्ट नहीं किया जा सकता है।

बाहरी स्टैक व्यू इस ऊंचाई = 0 बाधा का उपयोग करता है, मेरा मानना ​​है, क्योंकि यह बेहतर दिखता है जब आंतरिक दृश्य को पहले बिना छेड़छाड़ किए छुपाया जा सकता है।

इसके लिए एक आसान फिक्स है: एक सादे UIView में आंतरिक स्टैक व्यू को लपेटें, और उस रैपर को छुपाएं। मैं दिखाऊंगा।

यहाँ ऊपर टूटा संस्करण के लिए दृश्य रूपरेखा है:

broken outline

समस्या को ठीक करने के लिए, आंतरिक स्टैक दृश्य का चयन करें।

embed in view

इंटरफ़ेस बिल्डर आवरण दृश्य पर एक चौड़ाई बाधा बनाया जब मैं इस किया था, ताकि चौड़ाई बाधा को हटा दें:: मेनू बार से, Editor> एम्बेड में> देखें चुनें

delete width constraint

create constraints

:

इसके बाद, आवरण के सभी चार किनारों और भीतरी स्टेक दृश्य के बीच बाधाओं बनाने

इस बिंदु पर, लेआउट वास्तव में रनटाइम पर सही है, लेकिन इंटरफ़ेस बिल्डर इसे गलत तरीके से खींचता है। आप आंतरिक ढेर के बच्चों की ऊर्ध्वाधर hugging प्राथमिकताओं को सेट करके इसे ठीक कर सकते हैं। मैं उन्हें 800 करने के लिए सेट:

hugging priorities

हम नहीं वास्तव में इस बिंदु पर unsatisfiable विवश समस्या तय कर दी है। ऐसा करने के लिए, नीचे बनाई गई निचली बाधा पाएं और इसकी प्राथमिकता आवश्यक से कम निर्धारित करें। इसे 800 करने के लिए बदल डालते हैं:

change bottom constraint priority

अंत में, आप शायद एक आउटलेट आपके विचार आंतरिक स्टैक दृश्य से जुड़े नियंत्रक में, था, क्योंकि आप अपने hidden संपत्ति बदलते रहे थे। आंतरिक स्टैक व्यू के बजाय रैपर दृश्य से कनेक्ट करने के लिए उस आउटलेट को बदलें। यदि आपका आउटलेट का प्रकार UIStackView है, तो आपको इसे UIView पर बदलना होगा।मेरा प्रकार UIView की पहले से ही था, इसलिए मैं सिर्फ स्टोरीबोर्ड में यह पुन: कनेक्ट:

change outlet

अब, जब आप आवरण देखने के hidden संपत्ति टॉगल, स्टेक दृश्य कोई unsatisfiable बाधा चेतावनी के साथ संक्षिप्त करने के लिए, दिखाई देगा। यह वस्तुतः समान दिखता है, इसलिए मैं ऐप चलाने के एक और जीआईएफ पोस्ट करने से परेशान नहीं होगा।

आप मेरी परीक्षा परियोजना in this github repository पा सकते हैं।

+0

ध्यान दें कि आप आसानी से रैपर व्यू का उपयोग करके एनीमेशन प्रभाव को बदल सकते हैं। रैपर व्यू पर "क्लिप टू बाउंड्स" को चालू करने और नीचे की बाधा की प्राथमिकता 600 को सेट करने का प्रयास करें। आपको स्क्विंग प्रभाव के बजाय एक अच्छा स्लाइड-अंडर प्रभाव मिलता है। –

0

एक और दृष्टिकोण

कोशिश नेस्टेड UIStackViews से बचने के लिए। मैं उन्हें प्यार करता हूं और उनके साथ लगभग सबकुछ बना देता हूं। लेकिन जैसा कि मैंने पहचाना है कि वे गुप्त रूप से बाधाओं को जोड़ते हैं, मैं केवल उच्चतम स्तर पर उपयोग करने की कोशिश करता हूं और जहां संभव हो वहां गैर-घोंसला लगाता हूं। इस तरह से मैं दूसरी उच्चतम प्राथमिकता .defaultHigh को अंतरण बाधा में निर्दिष्ट कर सकता हूं जो मेरी चेतावनियों को हल करता है।

यह प्राथमिकता अधिकांश लेआउट समस्याओं को रोकने के लिए पर्याप्त है।

बेशक आपको कुछ और बाधाओं को निर्दिष्ट करने की आवश्यकता है, लेकिन इस तरह से आप उनका पूरा नियंत्रण रखते हैं और अपना व्यू लेआउट स्पष्ट बनाते हैं।

संबंधित मुद्दे