ऑटोलयूट के साथ सभी साक्षात्कारों को फिट करने के लिए सुपरवाइज का आकार कैसे बदलें?


142

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

क्या इस प्रक्रिया को उलटने का कोई तरीका है? मैं बाधाओं और आंतरिक आकारों के आधार पर सुपरवाइज का आकार बदलना चाहता हूं। इसे प्राप्त करने का सबसे सरल तरीका क्या है?

मेरे पास Xcode में डिज़ाइन किया गया दृश्य है जिसे मैं एक हेडर के रूप में उपयोग करता हूं UITableView। इस दृश्य में एक लेबल और एक बटन शामिल है। लेबल का आकार डेटा के आधार पर भिन्न होता है। अवरोधों के आधार पर लेबल सफलतापूर्वक बटन को नीचे धकेलता है या अगर बटन के नीचे कोई अवरोध होता है और पर्यवेक्षण के नीचे लेबल होता है।

मुझे कुछ ऐसे ही सवाल मिले हैं लेकिन उनके पास अच्छे और आसान जवाब नहीं हैं।


28
आपको नीचे दिए गए उत्तरों में से एक का चयन करना चाहिए, जैसा कि टॉम स्विफ्ट्स ने आपके प्रश्न का उत्तर दिया है। सभी पोस्टरों ने आपकी सहायता करने के लिए एक बड़ी राशि खर्च की, अब आपको अपना हिस्सा करना चाहिए और उस उत्तर का चयन करना चाहिए जो आपको सबसे अच्छा लगता है।
डेविड एच।

जवाबों:


149

उपयोग करने के लिए सही एपीआई या UIView systemLayoutSizeFittingSize:तो गुजर रहा है UILayoutFittingCompressedSizeया UILayoutFittingExpandedSize

UIViewऑटोलेयूट का उपयोग करते हुए एक सामान्य के लिए यह तब तक काम करना चाहिए जब तक कि आपके अवरोध सही न हों। यदि आप इसे UITableViewCell(उदाहरण के लिए पंक्ति ऊंचाई निर्धारित करने के लिए) पर उपयोग करना चाहते हैं, तो आपको इसे अपने सेल के खिलाफ कॉल करना चाहिए contentViewऔर ऊंचाई को पकड़ना चाहिए।

आगे के विचार मौजूद हैं यदि आपके पास एक या एक से अधिक यूलैबेल हैं जो आपके विचार में बहुस्तरीय हैं। इसके लिए यह आवश्यक है कि preferredMaxLayoutWidthसंपत्ति को सही ढंग से सेट किया जाए ताकि लेबल एक सही प्रदान करे intrinsicContentSize, जिसका उपयोग systemLayoutSizeFittingSize'sगणना में किया जाएगा ।

संपादित करें: अनुरोध द्वारा, तालिका दृश्य सेल के लिए ऊंचाई गणना का उदाहरण जोड़कर

टेबल-सेल ऊंचाई गणना के लिए ऑटोलाययूट का उपयोग करना सुपर कुशल नहीं है, लेकिन यह सुनिश्चित करना सुविधाजनक है, खासकर यदि आपके पास एक सेल है जिसमें एक जटिल लेआउट है।

जैसा कि मैंने ऊपर कहा, यदि आप एक बहुस्तरीय का उपयोग कर रहे हैं तो UILabelयह preferredMaxLayoutWidthलेबल की चौड़ाई के साथ सिंक करने के लिए जरूरी है । मैं ऐसा करने के लिए एक कस्टम UILabelउपवर्ग का उपयोग करता हूं :

@implementation TSLabel

- (void) layoutSubviews
{
    [super layoutSubviews];

    if ( self.numberOfLines == 0 )
    {
        if ( self.preferredMaxLayoutWidth != self.frame.size.width )
        {
            self.preferredMaxLayoutWidth = self.frame.size.width;
            [self setNeedsUpdateConstraints];
        }
    }
}

- (CGSize) intrinsicContentSize
{
    CGSize s = [super intrinsicContentSize];

    if ( self.numberOfLines == 0 )
    {
        // found out that sometimes intrinsicContentSize is 1pt too short!
        s.height += 1;
    }

    return s;
}

@end

यहां एक UITableViewController उपक्लास का प्रदर्शन किया गया है जो ऊँचाई का प्रदर्शन करता है RowAtIndexPath:

#import "TSTableViewController.h"
#import "TSTableViewCell.h"

@implementation TSTableViewController

- (NSString*) cellText
{
    return @"Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.";
}

#pragma mark - Table view data source

- (NSInteger) numberOfSectionsInTableView: (UITableView *) tableView
{
    return 1;
}

- (NSInteger) tableView: (UITableView *)tableView numberOfRowsInSection: (NSInteger) section
{
    return 1;
}

- (CGFloat) tableView: (UITableView *) tableView heightForRowAtIndexPath: (NSIndexPath *) indexPath
{
    static TSTableViewCell *sizingCell;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{

        sizingCell = (TSTableViewCell*)[tableView dequeueReusableCellWithIdentifier: @"TSTableViewCell"];
    });

    // configure the cell
    sizingCell.text = self.cellText;

    // force layout
    [sizingCell setNeedsLayout];
    [sizingCell layoutIfNeeded];

    // get the fitting size
    CGSize s = [sizingCell.contentView systemLayoutSizeFittingSize: UILayoutFittingCompressedSize];
    NSLog( @"fittingSize: %@", NSStringFromCGSize( s ));

    return s.height;
}

- (UITableViewCell *) tableView: (UITableView *) tableView cellForRowAtIndexPath: (NSIndexPath *) indexPath
{
    TSTableViewCell *cell = (TSTableViewCell*)[tableView dequeueReusableCellWithIdentifier: @"TSTableViewCell" ];

    cell.text = self.cellText;

    return cell;
}

@end

एक साधारण कस्टम सेल:

#import "TSTableViewCell.h"
#import "TSLabel.h"

@implementation TSTableViewCell
{
    IBOutlet TSLabel* _label;
}

- (void) setText: (NSString *) text
{
    _label.text = text;
}

@end

और, यहाँ स्टोरीबोर्ड में परिभाषित बाधाओं की एक तस्वीर है। ध्यान दें कि लेबल पर कोई ऊँचाई / चौड़ाई की कमी नहीं है - वे लेबल से अनुमानित हैं intrinsicContentSize:

यहां छवि विवरण दर्ज करें


1
क्या आप एक उदाहरण दे सकते हैं कि ऊँचाई का कार्यान्वयन क्या हैForRowAtIndexPath: एक बहु-पंक्ति लेबल वाले सेल के साथ इस पद्धति का उपयोग करना चाहेंगे? मैंने इसके साथ बहुत गड़बड़ की है, और इसे काम करने के लिए नहीं दिया है। आपको एक सेल कैसे मिलती है (विशेषकर यदि सेल स्टोरीबोर्ड में सेटअप है)? इसे काम करने के लिए आपको किन बाधाओं की आवश्यकता है?
rdelmar

@rdelmar - ज़रूर। मैंने अपने उत्तर में एक उदाहरण जोड़ा है।
टॉमस्विफ्ट

7
यह मेरे लिए तब तक काम नहीं कर रहा था जब तक कि मैंने सेल के निचले भाग से सेल में सबसे निचले सबव्यू के नीचे तक एक अंतिम लंबवत अवरोध नहीं जोड़ा। ऐसा लगता है कि ऊर्ध्वाधर बाधाओं को सेल और इसकी सामग्री के बीच शीर्ष और निचले ऊर्ध्वाधर रिक्ति को शामिल करना चाहिए ताकि सेल ऊंचाई की गणना सफल हो सके।
एरिक बेकर

1
मुझे इसे काम करने के लिए केवल एक और चाल की जरूरत थी। और @EricBaker की टिप ने आखिरकार इसे रद्द कर दिया। उस आदमी को बांटने के लिए धन्यवाद। मुझे गैर-शून्य आकार मिला या तो अब sizingCellइसके खिलाफ या इसके विपरीत contentView
MkVal

1
जिन लोगों को सही ऊँचाई न मिलने की समस्या है, सुनिश्चित करें कि आपकी sizingCellचौड़ाई आपकी चौड़ाई से मेल खाती है tableView
एमकेवल

30

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

ध्यान दें, यह स्क्रॉल दृश्यों के साथ काम करने वालों के लिए विशेष रूप से महत्वपूर्ण हो सकता है क्योंकि यह एक एकल सामग्री दृश्य के चारों ओर डिजाइन करने के लिए सामान्य है जो इसके आकार को निर्धारित करता है (और स्क्रॉल दृश्य में यह संचार करता है) गतिशील रूप से आप जो भी इसमें डालते हैं उसके आधार पर। सौभाग्य, आशा है कि यह किसी को वहाँ से बाहर निकलने में मदद करता है।

//
//  ViewController.m
//  AutoLayoutDynamicVerticalContainerHeight
//

#import "ViewController.h"

@interface ViewController ()
@property (strong, nonatomic) UIView *contentView;
@property (strong, nonatomic) UILabel *myLabel;
@property (strong, nonatomic) UILabel *myOtherLabel;
@end

@implementation ViewController

- (void)viewDidLoad
{
    // INVOKE SUPER
    [super viewDidLoad];

    // INIT ALL REQUIRED UI ELEMENTS
    self.contentView = [[UIView alloc] init];
    self.myLabel = [[UILabel alloc] init];
    self.myOtherLabel = [[UILabel alloc] init];
    NSDictionary *viewsDictionary = NSDictionaryOfVariableBindings(_contentView, _myLabel, _myOtherLabel);

    // TURN AUTO LAYOUT ON FOR EACH ONE OF THEM
    self.contentView.translatesAutoresizingMaskIntoConstraints = NO;
    self.myLabel.translatesAutoresizingMaskIntoConstraints = NO;
    self.myOtherLabel.translatesAutoresizingMaskIntoConstraints = NO;

    // ESTABLISH VIEW HIERARCHY
    [self.view addSubview:self.contentView]; // View adds content view
    [self.contentView addSubview:self.myLabel]; // Content view adds my label (and all other UI... what's added here drives the container height (and width))
    [self.contentView addSubview:self.myOtherLabel];

    // LAYOUT

    // Layout CONTENT VIEW (Pinned to left, top. Note, it expects to get its vertical height (and horizontal width) dynamically based on whatever is placed within).
    // Note, if you don't want horizontal width to be driven by content, just pin left AND right to superview.
    [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[_contentView]" options:0 metrics:0 views:viewsDictionary]]; // Only pinned to left, no horizontal width yet
    [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[_contentView]" options:0 metrics:0 views:viewsDictionary]]; // Only pinned to top, no vertical height yet

    /* WHATEVER WE ADD NEXT NEEDS TO EXPLICITLY "PUSH OUT ON" THE CONTAINING CONTENT VIEW SO THAT OUR CONTENT DYNAMICALLY DETERMINES THE SIZE OF THE CONTAINING VIEW */
    // ^To me this is what's weird... but okay once you understand...

    // Layout MY LABEL (Anchor to upper left with default margin, width and height are dynamic based on text, font, etc (i.e. UILabel has an intrinsicContentSize))
    [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-[_myLabel]" options:0 metrics:0 views:viewsDictionary]];
    [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-[_myLabel]" options:0 metrics:0 views:viewsDictionary]];

    // Layout MY OTHER LABEL (Anchored by vertical space to the sibling label that comes before it)
    // Note, this is the view that we are choosing to use to drive the height (and width) of our container...

    // The LAST "|" character is KEY, it's what drives the WIDTH of contentView (red color)
    [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-[_myOtherLabel]-|" options:0 metrics:0 views:viewsDictionary]];

    // Again, the LAST "|" character is KEY, it's what drives the HEIGHT of contentView (red color)
    [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:[_myLabel]-[_myOtherLabel]-|" options:0 metrics:0 views:viewsDictionary]];

    // COLOR VIEWS
    self.view.backgroundColor = [UIColor purpleColor];
    self.contentView.backgroundColor = [UIColor redColor];
    self.myLabel.backgroundColor = [UIColor orangeColor];
    self.myOtherLabel.backgroundColor = [UIColor greenColor];

    // CONFIGURE VIEWS

    // Configure MY LABEL
    self.myLabel.text = @"HELLO WORLD\nLine 2\nLine 3, yo";
    self.myLabel.numberOfLines = 0; // Let it flow

    // Configure MY OTHER LABEL
    self.myOtherLabel.text = @"My OTHER label... This\nis the UI element I'm\narbitrarily choosing\nto drive the width and height\nof the container (the red view)";
    self.myOtherLabel.numberOfLines = 0;
    self.myOtherLabel.font = [UIFont systemFontOfSize:21];
}

@end

Autolayout.png के साथ सभी साक्षात्कारों को फिट करने के लिए पर्यवेक्षक का आकार कैसे बदलें


3
यह एक महान चाल है और अच्छी तरह से ज्ञात नहीं है। दोहराने के लिए: यदि आंतरिक विचारों की आंतरिक ऊंचाई है और इसे ऊपर और नीचे पिन किया गया है, तो बाहरी दृश्य को इसकी ऊंचाई निर्दिष्ट करने की आवश्यकता नहीं होगी और वास्तव में इसकी सामग्री को गले लगाना होगा। वांछित परिणाम प्राप्त करने के लिए आपको आंतरिक दृश्यों के लिए सामग्री संपीड़न और हगिंग को समायोजित करने की आवश्यकता हो सकती है।
फतमान

यह पैसा है! बेहतर संक्षिप्त VFL उदाहरणों में से एक मैंने देखा है।
इवान आर

यह वही है जिसकी मैं तलाश कर रहा था (धन्यवाद @ जॉन) इसलिए मैंने यहां
जेम्स

1
"आपको चुनना होगा कि कौन सा सबवे कंटेनर की ऊंचाई और / या चौड़ाई को ड्राइव करने वाला है ... सबसे अधिक यूआई तत्व जो आपने अपने समग्र यूआई के निचले दाएं कोने में रखा है" .. मैं PureLayout का उपयोग कर रहा हूं, और यह मेरे लिए महत्वपूर्ण था। एक पैरेंट व्यू के लिए, एक चाइल्ड व्यू के साथ, यह चाइल्ड व्यू को नीचे दाईं ओर पिन करने के लिए बैठा था, जिससे अचानक पैरेंट व्यू को आकार मिला। धन्यवाद!
स्टीवन इलियट

1
चौड़ाई को ड्राइव करने के लिए एक दृश्य चुनना वास्तव में वही है जो मैं नहीं कर सकता। कभी-कभी एक सबव्यू व्यापक होता है, कभी-कभी दूसरा सबव्यू व्यापक होता है। उस मामले के लिए कोई विचार?
हेनिंग

3

आप इसे एक बाधा बनाकर और इंटरफ़ेस बिल्डर के माध्यम से जोड़कर कर सकते हैं

स्पष्टीकरण देखें: Auto_Layout_Constraints_in_Interface_Builder

रेवेंडरलिच शुरुआत-ऑटो-लेआउट

AutolayoutPG लेखों का मूल आधार है

@interface ViewController : UIViewController {
    IBOutlet NSLayoutConstraint *leadingSpaceConstraint;
    IBOutlet NSLayoutConstraint *topSpaceConstraint;
}
@property (weak, nonatomic) IBOutlet NSLayoutConstraint *leadingSpaceConstraint;

अपने उप विचारों के साथ इस बाधा आउटलेट को कनेक्ट करें बाधा या सुपर विचारों को भी कनेक्ट करें और इसे अपनी आवश्यकताओं के अनुसार सेट करें

 self.leadingSpaceConstraint.constant = 10.0;//whatever you want to assign

मुझे उम्मीद है कि यह इसे स्पष्ट करता है।


तो स्रोत कोड से XCode में बनाए गए अवरोधों को कॉन्फ़िगर करना संभव है। लेकिन सवाल यह है कि पर्यवेक्षी का आकार बदलने के लिए उन्हें कैसे कॉन्फ़िगर किया जाए।
DAK

हाँ @ दक। कृपया पर्यवेक्षक लेआउट के बारे में सुनिश्चित करें। कॉन्स्ट्रेविंट को सुपरविजन में रखें और जब भी आपके सबव्यू में वृद्धि हो, तब भी कॉन्स्टेंट को ऊंचाई तक बढ़ाएं।
चंदन

यह भी मेरे लिए काम किया। यह मदद करता है कि मेरे पास आकार की कोशिकाएं (60px की ऊंचाई) हैं। इसलिए जब दृश्य लोड होता है, तो मैंने अपना IBOutlet'd ऊंचाई की सीमा 60 * x निर्धारित की जहां x कोशिकाओं की संख्या है। अंत में, आप संभवतः इसे स्क्रॉल दृश्य में चाहते हैं ताकि आप पूरी चीज़ देख सकें।
सैंडी चैपमैन

-1

यह subviewएक बड़े के अंदर एक सामान्य के लिए किया जा सकता है UIView, लेकिन यह स्वचालित रूप से काम नहीं करता है headerViews। एक की ऊंचाई headerViewक्या द्वारा लौटाई गई से निर्धारित होता है tableView:heightForHeaderInSection:तो आप की गणना करने के लिए है heightके आधार पर heightकी UILabelके लिए प्लस अंतरिक्ष UIButtonऔर किसी भी paddingआप की जरूरत। आपको ऐसा कुछ करने की आवश्यकता है:

-(CGFloat)tableView:(UITableView *)tableView 
          heightForHeaderInSection:(NSInteger)section {
    NSString *s = self.headeString[indexPath.section];
    CGSize size = [s sizeWithFont:[UIFont systemFontOfSize:17] 
                constrainedToSize:CGSizeMake(281, CGFLOAT_MAX)
                    lineBreakMode:NSLineBreakByWordWrapping];
    return size.height + 60;
}

यहाँ headerStringआप को भरने के लिए चाहते हैं जो कुछ भी स्ट्रिंग है UILabel, और 281 नंबर widthकी UILabel(में सेटअप के रूप में Interface Builder)


दुर्भाग्य से यह काम नहीं करता है। सुपरवाइवे पर "साइज टू फिट कंटेंट" उस अड़चन को दूर करता है जो आपके द्वारा भविष्यवाणी की गई बटन को बटन को सुपरवाइवे से जोड़ता है। रनटाइम के दौरान लेबल का आकार बदल दिया जाता है और यह बटन को नीचे धकेल देता है लेकिन पर्यवेक्षक स्वचालित रूप से आकार परिवर्तन नहीं करता है।
DAK

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

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

@Dak, क्षमा करें, मुझे नहीं लगता कि एक बेहतर तरीका है, यह सिर्फ टेबल व्यू का काम है।
rdelmar

कृपया मेरा उत्तर देखें। "बेहतर तरीका" UIView systemLayoutSizeFittingSize का उपयोग करना है:। उस ने कहा, एक टेबलव्यू में आवश्यक ऊंचाई पाने के लिए सिर्फ एक दृश्य या सेल पर एक पूर्ण ऑटोलैयूट प्रदर्शन करना काफी महंगा है। मैं इसे जटिल कोशिकाओं के लिए करूँगा, लेकिन सरल मामलों के लिए शायद आपकी तरह समाधान के लिए।
टॉमस्विफ्ट
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.