मैं ऑटोलयूट के साथ tableHeaderView (UITableView) की ऊंचाई कैसे निर्धारित करूं?


86

मैं पिछले 3 या 4 घंटों से इसके खिलाफ दीवार पर अपना सिर मार रहा हूं और मैं इसका पता नहीं लगा सकता। मेरे पास इसके अंदर एक पूर्ण स्क्रीन UITableView के साथ एक UIViewController है (स्क्रीन पर कुछ अन्य सामान है, यही कारण है कि मैं एक UITableViewController का उपयोग नहीं कर सकता) और मैं ऑटोलाययूट के साथ आकार बदलने के लिए अपना tableHeaderView प्राप्त करना चाहता हूं। कहने की जरूरत नहीं है, यह सहयोग नहीं कर रहा है।

नीचे स्क्रीनशॉट देखें

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

क्योंकि ओवरव्यूब्लाब (उदाहरण के लिए "सूची की जानकारी यहाँ देखें।" पाठ) में गतिशील सामग्री है, मैं इसे आकार देने के लिए ऑटोलॉययट का उपयोग कर रहा हूँ और यह पर्यवेक्षण है। मुझे टेबलहैदर व्यू को छोड़कर, अच्छी तरह से सब कुछ मिल गया है, जो कि खोज में पैरालैक्स टेबल व्यू के ठीक नीचे है।

एक ही तरीका है कि मैंने उस हेडर दृश्य को आकार देने के लिए प्रोग्रामिक रूप से निम्न कोड के साथ पाया है:

CGRect headerFrame = self.headerView.frame;
headerFrame.size.height = headerFrameHeight;
self.headerView.frame = headerFrame;
[self.listTableView setTableHeaderView:self.headerView];

इस मामले में, शीर्ष लेखफ्रैमहाइट टेबल व्यूहाइडर ऊंचाई की एक मैनुअल गणना है जो निम्नानुसार है (इनरहेडर व्यू सफेद क्षेत्र है, या दूसरा "दृश्य" है, हेडर व्यू टेबलहैडर व्यू है) :

CGFloat startingY = self.innerHeaderView.frame.origin.y + self.overviewLabel.frame.origin.y;
CGRect overviewSize = [self.overviewLabel.text
                       boundingRectWithSize:CGSizeMake(290.f, CGFLOAT_MAX)
                       options:NSStringDrawingUsesLineFragmentOrigin
                       attributes:@{NSFontAttributeName: self.overviewLabel.font}
                       context:nil];
CGFloat overviewHeight = overviewSize.size.height;
CGFloat overviewPadding = ([self.overviewLabel.text length] > 0) ? 10 : 0; // If there's no overviewText, eliminate the padding in the overall height.
CGFloat headerFrameHeight = ceilf(startingY + overviewHeight + overviewPadding + 21.f + 10.f);

मैनुअल गणना काम करती है, लेकिन अगर भविष्य में चीजें बदल जाती हैं तो यह स्पष्ट है और त्रुटि की संभावना है। मैं जो करने में सक्षम होना चाहता हूं, वह प्रदान की गई बाधाओं के आधार पर tableHeaderView ऑटो-आकार है, जैसे आप कहीं और कर सकते हैं। लेकिन मेरे जीवन के लिए, मैं इसका पता नहीं लगा सकता।

इस बारे में SO पर कई पोस्ट हैं, लेकिन कोई भी स्पष्ट नहीं है और मुझे और अधिक भ्रमित कर रहा है। यहाँ कुछ है:

यह वास्तव में अनुवाद बदलने के लिए समझ में नहीं आता है। कोई भी मेरे लिए त्रुटियों का कारण बनता है और वैसे भी वैचारिक रूप से समझ में नहीं आता है।

आपकी किसी भी मदद के हम दिल से आभारी होंगे!

EDIT 1: टॉमस्विफ्ट के सुझाव के लिए धन्यवाद, मैं यह पता लगाने में सक्षम था। अवलोकन की ऊंचाई की मैन्युअल रूप से गणना करने के बजाय, मैं इसे निम्नानुसार मेरे लिए गणना कर सकता हूं और फिर तालिकाहैडर व्यू को पहले से फिर से सेट कर सकता हूं।

[self.headerView setNeedsLayout];
[self.headerView layoutIfNeeded];
CGFloat height = [self.innerHeaderView systemLayoutSizeFittingSize:UILayoutFittingCompressedSize].height + self.innerHeaderView.frame.origin.y; // adding the origin because innerHeaderView starts partway down headerView.

CGRect headerFrame = self.headerView.frame;
headerFrame.size.height = height;
self.headerView.frame = headerFrame;
[self.listTableView setTableHeaderView:self.headerView];

संपादित करें 2: जैसा कि अन्य ने नोट किया है, संपादित 1 में पोस्ट किया गया समाधान, व्यूडेलड में काम नहीं करता है। हालाँकि, यह देखने में काम करता है, फिर भी WillLayoutSubviews में देखें। नीचे उदाहरण कोड:

// Note 1: The variable names below don't match the variables above - this is intended to be a simplified "final" answer.
// Note 2: _headerView was previously assigned to tableViewHeader (in loadView in my case since I now do everything programatically).
// Note 3: autoLayout code can be setup programatically in updateViewConstraints.
- (void)viewWillLayoutSubviews {
    [super viewWillLayoutSubviews];

    [_headerWrapper setNeedsLayout];
    [_headerWrapper layoutIfNeeded];
    CGFloat height = [_headerWrapper systemLayoutSizeFittingSize:UILayoutFittingCompressedSize].height;

    CGRect headerFrame = _headerWrapper.frame;
    headerFrame.size.height = height;
    _headerWrapper.frame = headerFrame;
    _tableView.tableHeaderView = _headerWrapper;
}

2
setTableHeaderViewXcode6 पर काम नहीं करता है। समस्या यह है कि टेबलहैडर व्यू द्वारा कोशिकाओं को ओवरलैप किया जाता है। हालाँकि, यह Xcode5
DawnSong

@DawnSong Xcode6 के लिए एक समाधान जानता है ताकि मैं उत्तर को अपडेट कर सकूं?
एंड्रयू क्रॉस

1
बहुत परीक्षण के बाद, मैं टेबलहेडर व्यू के बजाय यूआईटेबल व्यूसेल का उपयोग करता हूं, और यह काम करता है।
डॉनसॉन्ग

मैंने भी अपना सर पीट लिया!
अक्षय जवेरी

सच्चा पूर्ण
ऑटोलैयूट

जवाबों:


35

आपको UIView systemLayoutSizeFittingSize:अपने हेडर दृश्य के न्यूनतम बाउंडिंग आकार को प्राप्त करने के लिए विधि का उपयोग करने की आवश्यकता है ।

मैं इस क्यू / ए में इस एपीआई का उपयोग करने पर आगे चर्चा प्रदान करता हूं:

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


यह ऊँचाई = 0 के साथ वापस आ रहा है, हालांकि मुझे 100% यकीन नहीं है कि मैंने इसे सही तरीके से कॉन्फ़िगर किया है क्योंकि यह UITableViewCell नहीं है, इसलिए "systemLayoutSizeFittingSize" पर कॉल करने के लिए सामग्री दृश्य नहीं है। मैंने क्या कोशिश की: [self.headerView setNeedsLayout]; [self.headerView LayoutIfNeeded]; CGFloat height = [self.headerView systemLayoutSizeFittingSize: UILayoutFittingCompressedSize] .height; CGRect हैडरफ्रेम = self.headerView.frame; हैडरफ्रेम.साइज़.हाइट = ऊंचाई; self.headerView.frame = हैडरफ्रेम; [self.listTableView setTableHeaderView: self.headerView]; मैंने यह भी पुष्टि की कि पसंदीदामैक्स ... वैध है।
एंड्रयू क्रॉस

अहा! यह पता लगा, मैं करने की जरूरत है [self.innerHeaderView systemLayoutSizeFittingSize ...] के बजाय self.headerView के रूप में कि वास्तविक गतिशील सामग्री क्या है। अनेक अनेक धन्यवाद!
एंड्रयू क्रास

यह काम करता है, लेकिन मेरे ऐप में एक छोटी ऊंचाई की विसंगति है। शायद इसलिए कि मेरे लेबल एक जिम्मेदार पाठ और गतिशील प्रकार का उपयोग कर रहे हैं।
जैव

23

मैं वास्तव में इस एक के साथ जूझ रहा था और viewDidLoad में सेटअप का काम नहीं कर रहा था क्योंकि फ्रेम viewDidLoad में सेट नहीं है, मैं भी गन्दी चेतावनी के टन के साथ समाप्त हो गया जहाँ हेडर के एन्कैप्सुलेटेड ऑटो लेआउट की ऊँचाई 0 पर कम हो रही थी । जब मैंने फॉर्म प्रेजेंटेशन में टेबल व्यू पेश किया तो मैंने केवल iPad पर ही इस मुद्दे पर ध्यान दिया।

मेरे लिए इस मुद्दे को हल करने के लिए viewDillLoad के बजाय viewWillLayoutSubviews में tableViewHeader सेट कर रहा था।

func viewWillLayoutSubviews() {
        super.viewWillLayoutSubviews()
        if tableView.tableViewHeaderView == nil {
            let header: MyHeaderView = MyHeaderView.createHeaderView()
            header.setNeedsUpdateConstraints()
            header.updateConstraintsIfNeeded()
            header.frame = CGRectMake(0, 0, CGRectGetWidth(tableView.bounds), CGFloat.max)
            var newFrame = header.frame
            header.setNeedsLayout()
            header.layoutIfNeeded()
            let newSize = header.systemLayoutSizeFittingSize(UILayoutFittingCompressedSize)
            newFrame.size.height = newSize.height
            header.frame = newFrame
            self.tableView.tableHeaderView = header
        }
    }

न्यूनतम कोड के साथ अद्यतन समाधान के लिए यह कोशिश करें: stackoverflow.com/a/63594053/3933302
सौरभ शर्मा

23

मैंने एनीमेशन के साथ और बिना टेबल हेडर के आकार बदलने के लिए ऑटो लेआउट का उपयोग करने का एक शानदार तरीका पाया है।

बस इसे अपने व्यू कंट्रोलर में जोड़ें।

func sizeHeaderToFit(tableView: UITableView) {
    if let headerView = tableView.tableHeaderView {
        let height = headerView.systemLayoutSizeFittingSize(UILayoutFittingCompressedSize).height
        var frame = headerView.frame
        frame.size.height = height
        headerView.frame = frame
        tableView.tableHeaderView = headerView
        headerView.setNeedsLayout()
        headerView.layoutIfNeeded()
    }
}

गतिशील रूप से बदलते लेबल के अनुसार आकार बदलने के लिए:

@IBAction func addMoreText(sender: AnyObject) {
    self.label.text = self.label.text! + "\nThis header can dynamically resize according to its contents."
}

override func viewDidLayoutSubviews() {
    // viewDidLayoutSubviews is called when labels change.
    super.viewDidLayoutSubviews()
    sizeHeaderToFit(tableView)
}

एक बाधा में परिवर्तन के अनुसार आकार बदलने के लिए:

@IBOutlet weak var makeThisTallerHeight: NSLayoutConstraint!

@IBAction func makeThisTaller(sender: AnyObject) {

    UIView.animateWithDuration(0.3) {
        self.tableView.beginUpdates()
        self.makeThisTallerHeight.constant += 20
        self.sizeHeaderToFit(self.tableView)
        self.tableView.endUpdates()
    }
}

कार्रवाई में यह देखने के लिए AutoResizingHeader प्रोजेक्ट देखें। https://github.com/p-sun/Swift2-iOS9-UI

AutoResizingHeader


हे पी-सूरज। महान उदाहरण के लिए धन्यवाद। लगता है कि मेरे पास tableViewHeader के साथ समस्या है। मैंने आपके उदाहरण में वैसी ही अड़चन डालने की कोशिश की, लेकिन काम नहीं कर रहा। मुझे बिल्‍कुल अड़चनें डालनी चाहिए कि मैं किस ऊंचाई को बढ़ाना चाहता हूं? किसी भी सुझाव के लिए धन्यवाद
Bonnke

1
सुनिश्चित करें कि आप उस लेबल को हुक करते हैं जिसे आप उदाहरण में लंबा @IBOutlet makeThisTallerऔर @IBAction fun makeThisTallerपसंद करना चाहते हैं । इसके अलावा, अपने लेबल के सभी पक्षों को tableViewHeader (जैसे ऊपर, नीचे, बाएँ और दाएँ) पर विवश करें।
पी-सूर्य

आपका बहुत बहुत धन्यवाद! अंत में इस लाइन को जोड़कर हल किया गया: lblFeedDescription.preferredMaxLayoutWidth = lblFeedDescription.bounds.widthजहां लेबल वह है जिसे मैं आकार बढ़ाना चाहता हूं। धन्यवाद !
बोनाके

धन्यवाद! यदि आप एक ViewController के बजाय किसी दृश्य के अंदर ऐसा कर रहे हैं, तो दृश्य को देखने के बजाय DidLayoutSubviews, आप लेआउट को ओवरराइड कर सकते हैं
Andy Weinstein

4

यह समाधान tableHeaderView का आकार बदलता है और उस viewDidLayoutSubviews()विधि में अनंत लूप से बचता है जो मैं यहां कुछ अन्य उत्तरों के साथ कर रहा था:

override func viewDidLayoutSubviews() {
    super.viewDidLayoutSubviews()

    if let headerView = tableView.tableHeaderView {
        let height = headerView.systemLayoutSizeFitting(UILayoutFittingCompressedSize).height
        var headerFrame = headerView.frame

        // comparison necessary to avoid infinite loop
        if height != headerFrame.size.height {
            headerFrame.size.height = height
            headerView.frame = headerFrame
            tableView.tableHeaderView = headerView
        }
    }
}

इस पोस्ट को भी देखें: https://stackoverflow.com/a/34689293/1245231


1
मैं इस विधि का भी उपयोग कर रहा हूं। सोचें कि यह सबसे अच्छा है क्योंकि बाधाओं के साथ कोई फिडिंग नहीं है। यह बहुत कॉम्पैक्ट भी है।
जैव

3

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

SystemLayoutSizeFittingSize प्राप्त करने के लिए: प्रत्येक अद्यतन के बाद सही आकार वापस करने के लिए मुझे पहले इसे अपडेट करने से पहले टेबल हेडर दृश्य को हटाना होगा और फिर से जोड़ना होगा:

self.listTableView.tableHeaderView = nil;
[self.headerView removeFromSuperview];

2

इसने मेरे लिए ios10 और Xcode 8 पर काम किया

func layoutTableHeaderView() {

    guard let headerView = tableView.tableHeaderView else { return }
    headerView.translatesAutoresizingMaskIntoConstraints = false

    let headerWidth = headerView.bounds.size.width;
    let temporaryWidthConstraints = NSLayoutConstraint.constraintsWithVisualFormat("[headerView(width)]", options: NSLayoutFormatOptions(rawValue: UInt(0)), metrics: ["width": headerWidth], views: ["headerView": headerView])

    headerView.addConstraints(temporaryWidthConstraints)

    headerView.setNeedsLayout()
    headerView.layoutIfNeeded()

    let headerSize = headerView.systemLayoutSizeFittingSize(UILayoutFittingCompressedSize)
    let height = headerSize.height
    var frame = headerView.frame

    frame.size.height = height
    headerView.frame = frame

    self.tableView.tableHeaderView = headerView

    headerView.removeConstraints(temporaryWidthConstraints)
    headerView.translatesAutoresizingMaskIntoConstraints = true

}

2

यह शीर्ष लेख दृश्य और पाद लेख दोनों के लिए काम करता है बस शीर्ष लेख को पाद लेख के साथ बदलें

func sizeHeaderToFit() {
    if let headerView = tableView.tableHeaderView {

        headerView.setNeedsLayout()
        headerView.layoutIfNeeded()

        let height = headerView.systemLayoutSizeFitting(UILayoutFittingCompressedSize).height
        var frame = headerView.frame
        frame.size.height = height
        headerView.frame = frame

        tableView.tableHeaderView = headerView
    }
}

1

IOS 12 और इसके बाद के संस्करण के लिए, निम्न चरण आपके टेबल और हेडर दोनों में ऑटोलेयूट ठीक से काम करेगा।

  1. पहले अपना टेबल व्यू बनाएं, फिर हेडर।
  2. अपने हेडर निर्माण कोड के अंत में, कॉल करें:
[headerV setNeedsLayout];
[headerV layoutIfNeeded];
  1. अभिविन्यास परिवर्तन पर, लेआउट के लिए हेडर को फिर से चिह्नित करें और तालिका को फिर से लोड करें, यह अभिविन्यास परिवर्तन की सूचना दिए जाने के बाद थोड़ा होने की आवश्यकता है:
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 0.1 *NSEC_PER_SEC), dispatch_get_main_queue(), ^{

  [tableV.tableHeaderView setNeedsLayout];
  [tableV.tableHeaderView layoutIfNeeded];
  [tableV reloadData];});

0

मेरे मामले में viewDidLayoutSubviewsबेहतर काम किया। viewWillLayoutSubviewsसफेद रेखाएं tableViewदिखाई देने का कारण बनती हैं। यदि मेरी headerViewवस्तु पहले से मौजूद है, तो भी मैंने जाँच को जोड़ा ।

- (void)viewDidLayoutSubviews
{
    [super viewDidLayoutSubviews];

    if ( ! self.userHeaderView ) {
        // Setup HeaderView
        self.userHeaderView = [[[NSBundle mainBundle] loadNibNamed:@"SSUserHeaderView" owner:self options:nil] objectAtIndex:0];
        [self.userHeaderView setNeedsLayout];
        [self.userHeaderView layoutIfNeeded];
        CGFloat height = [self.userHeaderView systemLayoutSizeFittingSize:UILayoutFittingCompressedSize].height;
        CGRect headerFrame = self.userHeaderView.frame;
        headerFrame.size.height = height;
        self.userHeaderView.frame = headerFrame;
        self.tableView.tableHeaderView = self.userHeaderView;

        // Update HeaderView with data
        [self.userHeaderView updateWithProfileData];
    }
}

0

जे के UIViewरूप में किसी भी एएल इनर सबव्यू संरचना के साथ जेनेरिक ऑटोलेयूट-आधारित का उपयोग करना काफी संभव है tableHeaderView

केवल एक चीज की जरूरत है tableFooterViewपहले एक सरल सेट करें !

आज्ञाचक्र self.headerViewआधारित है UIView

- (void)viewDidLoad {

    ........................

    self.tableView.tableFooterView = [UIView new];

    [self.headerView layoutIfNeeded]; // to set initial size

    self.tableView.tableHeaderView = self.headerView;

    [self.tableView.leadingAnchor constraintEqualToAnchor:self.headerView.leadingAnchor].active = YES;
    [self.tableView.trailingAnchor constraintEqualToAnchor:self.headerView.trailingAnchor].active = YES;
    [self.tableView.topAnchor constraintEqualToAnchor:self.headerView.topAnchor].active = YES;

    // and the key constraint
    [self.tableFooterView.trailingAnchor constraintEqualToAnchor:self.headerView.trailingAnchor].active = YES;
}

अगर self.headerViewयूआई रोटेशन के तहत ऊँचाई में परिवर्तन होता है तो किसी को लागू करना होगा

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

    [coordinator animateAlongsideTransition: ^(id<UIViewControllerTransitionCoordinatorContext> context) {
        // needed to resize header height
        self.tableView.tableHeaderView = self.headerView;
    } completion: NULL];
}

इस उद्देश्य के लिए एक व्यक्ति ओबीसी श्रेणी का उपयोग कर सकता है

@interface UITableView (AMHeaderView)
- (void)am_insertHeaderView:(UIView *)headerView;
@end

@implementation UITableView (AMHeaderView)

- (void)am_insertHeaderView:(UIView *)headerView {

    NSAssert(self.tableFooterView, @"Need to define tableFooterView first!");

    [headerView layoutIfNeeded];

    self.tableHeaderView = headerView;

    [self.leadingAnchor constraintEqualToAnchor:headerView.leadingAnchor].active = YES;
    [self.trailingAnchor constraintEqualToAnchor:headerView.trailingAnchor].active = YES;
    [self.topAnchor constraintEqualToAnchor:headerView.topAnchor].active = YES;

    [self.tableFooterView.trailingAnchor constraintEqualToAnchor:headerView.trailingAnchor].active = YES;
}
@end

और स्विफ्ट एक्सटेंशन भी

extension UITableView {

    func am_insertHeaderView2(_ headerView: UIView) {

        assert(tableFooterView != nil, "Need to define tableFooterView first!")

        headerView.layoutIfNeeded()

        tableHeaderView = headerView

        leadingAnchor.constraint(equalTo: headerView.leadingAnchor).isActive = true
        trailingAnchor.constraint(equalTo: headerView.trailingAnchor).isActive = true
        topAnchor.constraint(equalTo: headerView.topAnchor).isActive = true

        tableFooterView?.trailingAnchor.constraint(equalTo: headerView.trailingAnchor).isActive = true
    }
}

0

यह समाधान मेरे लिए पूरी तरह से काम करता है:

https://spin.atomicobject.com/2017/08/11/swift-extending-uitableviewcontroller/

यह UITableViewController का विस्तार करता है। लेकिन अगर आप सिर्फ यूआईटेबल व्यू का उपयोग कर रहे हैं, तो यह अभी भी काम करेगा, यूआईटेबल व्यू कॉन्ट्रोलर के बजाय यूआईटेबल व्यू का विस्तार करें। तरीकों को बुलाओ sizeHeaderToFit()या sizeFooterToFit()जब भी कोई घटना होती है जो tableViewHeaderऊंचाई बदलती है ।


0

इस पद से नकल की गई

override func viewDidLayoutSubviews() {
    super.viewDidLayoutSubviews()
    
    if let headerView = tableView.tableHeaderView {

        let height = headerView.systemLayoutSizeFitting(UIView.layoutFittingCompressedSize).height
        var headerFrame = headerView.frame
        
        //Comparison necessary to avoid infinite loop
        if height != headerFrame.size.height {
            headerFrame.size.height = height
            headerView.frame = headerFrame
            tableView.tableHeaderView = headerView
        }
    }
}
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.