AutoLayout'u UITableView'ın tableHeaderView ile kullanmak mümkün müdür?


100

AutoLayoutHer yerde kullandığımı keşfettiğimden beri , şimdi onu bir tableHeaderView.

Ben yapılan subclassbir UIView(etiketler vs ...) Sonra ben bu ilave, onların kısıtlamalarıyla istedik ilave her şeyi CustomViewiçin UITableView' tableHeaderView.

Her şey hariç sadece para cezası işleri UITableViewhep ekranlar üzerindeCustomView , tarafından yukarıda demek CustomViewolduğunu altındanUITableView o görülemez böylece!

Ne yaptığım olursa olsun, görünüyor heightait UITableView' tableHeaderViewolduğu hep (şimdiye genişlik, x ve y) 0.

Sorum: çerçeveyi manuel olarak ayarlamadan bunu başarmak mümkün mü?

DÜZENLEME: Kullandığım CustomView' subviewşu kısıtlamalara sahip:

_title = [[UILabel alloc]init];
_title.text = @"Title";
[self addSubview:_title];
[_title keep:[KeepTopInset rules:@[[KeepEqual must:5]]]]; // title has to stay at least 5 away from the supperview Top
[_title keep:[KeepRightInset rules:@[[KeepMin must:5]]]];
[_title keep:[KeepLeftInset rules:@[[KeepMin must:5]]]];
[_title keep:[KeepBottomInset rules:@[[KeepMin must:5]]]];

Kullanışlı bir kitaplık 'KeepLayout' kullanıyorum çünkü kısıtlamaları manuel olarak yazmak, tek bir kısıtlama için sonsuza kadar ve çok fazla satır alıyor, ancak yöntemler kendi kendini açıklıyor.

Ve UITableViewşu kısıtlamalara sahiptir:

_tableView = [[UITableView alloc]init];
_tableView.translatesAutoresizingMaskIntoConstraints = NO;
_tableView.delegate = self;
_tableView.dataSource = self;
_tableView.backgroundColor = [UIColor clearColor];
[self.view addSubview:_tableView];
[_tableView keep:[KeepTopInset rules:@[[KeepEqual must:0]]]];// These 4 constraints make the UITableView stays 0 away from the superview top left right and bottom.
[_tableView keep:[KeepLeftInset rules:@[[KeepEqual must:0]]]];
[_tableView keep:[KeepRightInset rules:@[[KeepEqual must:0]]]];
[_tableView keep:[KeepBottomInset rules:@[[KeepEqual must:0]]]];

_detailsView = [[CustomView alloc]init];
_tableView.tableHeaderView = _detailsView;

Bazı kısıtlamaları doğrudan üzerinde ayarlamam gerekip gerekmediğini bilmiyorum CustomView, sanırım CustomView yüksekliğinin içindeki UILabel"başlık" üzerindeki kısıtlamalar tarafından belirlendiğini düşünüyorum.

DÜZENLEME 2: Başka bir incelemeden sonra, CustomView'un yüksekliği ve genişliği doğru bir şekilde hesaplanmış gibi görünüyor, ancak CustomView'un üst kısmı hala UITableView'ın üst seviyesiyle aynı seviyede ve kaydırdığımda birlikte hareket ediyorlar.


Evet mümkün. Kullandığınız kodu gösterebilir misiniz? Başlık görünümünde hangi kısıtlamaları ayarladığınızı bilmeden tavsiye vermek zordur.
jrturton

Bunu başarmanın kolay bir yolu, IB'deki görünümü tableView'e eklemektir .. sadece görünümü tablo görünümünü içeren aynı sahnede oluşturun ve tabloya sürükleyin .
Mariam K.


1
Apple, geliştiricilere otomatik düzen söz konusu olduğunda mümkün olduğunda IB'yi kullanmalarını tavsiye ediyor. Pek çok tutarsızlık sorunundan kaçınmaya gerçekten yardımcı olur.
Mariam K.

Gerçek tam otomatik
düzen

Yanıtlar:


136

Burada benzer bir soru sordum ve cevapladım . Özetle, başlığı bir kez ekliyorum ve gerekli yüksekliği bulmak için kullanıyorum. Bu yükseklik daha sonra başlığa uygulanabilir ve başlık, değişikliği yansıtmak için ikinci kez ayarlanır.

- (void)viewDidLoad
{
    [super viewDidLoad];

    self.header = [[SCAMessageView alloc] init];
    self.header.titleLabel.text = @"Warning";
    self.header.subtitleLabel.text = @"This is a message with enough text to span multiple lines. This text is set at runtime and might be short or long.";

    //set the tableHeaderView so that the required height can be determined
    self.tableView.tableHeaderView = self.header;
    [self.header setNeedsLayout];
    [self.header layoutIfNeeded];
    CGFloat height = [self.header systemLayoutSizeFittingSize:UILayoutFittingCompressedSize].height;

    //update the header's frame and set it again
    CGRect headerFrame = self.header.frame;
    headerFrame.size.height = height;
    self.header.frame = headerFrame;
    self.tableView.tableHeaderView = self.header;
}

Çok satırlı etiketleriniz varsa, bu aynı zamanda her etiketin PreferMaxLayoutWidth ayarını özel görünüm ayarına da bağlıdır:

- (void)layoutSubviews
{
    [super layoutSubviews];

    self.titleLabel.preferredMaxLayoutWidth = CGRectGetWidth(self.titleLabel.frame);
    self.subtitleLabel.preferredMaxLayoutWidth = CGRectGetWidth(self.subtitleLabel.frame);
}

veya belki daha genel olarak:

override func layoutSubviews() {
    super.layoutSubviews()  
    for view in subviews {
        guard let label = view as? UILabel where label.numberOfLines == 0 else { continue }
        label.preferredMaxLayoutWidth = CGRectGetWidth(label.frame)
    }
}

Ocak 2015 güncellemesi

Ne yazık ki bu hala gerekli görünüyor. İşte düzen sürecinin hızlı bir versiyonu:

tableView.tableHeaderView = header
header.setNeedsLayout()
header.layoutIfNeeded()
header.frame.size = header.systemLayoutSizeFittingSize(UILayoutFittingCompressedSize)
tableView.tableHeaderView = header

Bunu UITableView'daki bir uzantıya taşımayı yararlı buldum:

extension UITableView {
    //set the tableHeaderView so that the required height can be determined, update the header's frame and set it again
    func setAndLayoutTableHeaderView(header: UIView) {
        self.tableHeaderView = header
        header.setNeedsLayout()
        header.layoutIfNeeded()
        header.frame.size = header.systemLayoutSizeFittingSize(UILayoutFittingCompressedSize)
        self.tableHeaderView = header
    }
}

Kullanım:

let header = SCAMessageView()
header.titleLabel.text = "Warning"
header.subtitleLabel.text = "Warning message here."
tableView.setAndLayoutTableHeaderView(header)

8
Kullanmanın bir alternatifi, kullanmadan preferredMaxLayoutWidthönce başlık görünümüne bir genişlik kısıtlaması (tablo görünümünün genişliğine eşit) eklemektir systemLayoutSizeFittingSize:.
Benjohn

2
NOT: Başlığın ilk hücrelerin üzerinde olduğunu deneyimliyorsanız, başlık özelliğini sıfırlamayı unuttunuz:self.tableView.tableHeaderView
Laszlo

9
Çoğu zaman, bunun gibi tamamen önemsiz bir şey yapmanın ne kadar zor olduğu beni şaşırtıyor.
TylerJames

5
NOT: tableView olarak tam genişlik almanız gerekiyorsa, gerekli yatay öncelikli yükseklik elde etmelisinizlet height = header.systemLayoutSizeFittingSize(CGSizeMake(CGRectGetWidth(self.bounds), 0), withHorizontalFittingPriority: UILayoutPriorityRequired, verticalFittingPriority: UILayoutPriorityFittingSizeLevel).height
JakubKnejzlik

3
Just Use header.setNeedsLayout() header.layoutIfNeeded() header.frame.size = header.systemLayoutSizeFitting(UILayoutFittingCompressedSize) self.tableHeaderView = headeriOS 10.2'de çalışacak
Kesong Xie

24

Kısıtlamalar (kodda) kullanarak bir başlık görünümü ekleyemedim. Görüşüme bir genişlik ve / veya yükseklik kısıtlaması verirsem, şu mesajla bir çökme yaşarım:

 "terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Auto Layout still required after executing -layoutSubviews. UITableView's implementation of -layoutSubviews needs to call super."

Film şeridinde tablo görünümüme bir görünüm eklediğimde, hiçbir kısıtlama göstermez ve bir başlık görünümü olarak iyi çalışır, bu nedenle başlık görünümünün yerleşiminin kısıtlamalar kullanılarak yapılmadığını düşünüyorum. Bu konuda normal bir görüş gibi görünmüyor.

Genişlik otomatik olarak tablo görünümünün genişliğidir, ayarlamanız gereken tek şey yüksekliktir - başlangıç ​​değerleri göz ardı edilir, bu nedenle bunlar için ne koyduğunuz önemli değildir. Örneğin, bu iyi çalıştı (düzeltme için 0,0,0,80 gibi):

UIView *headerview = [[UIView alloc] initWithFrame:CGRectMake(1000,1000, 0, 80)];
headerview.backgroundColor = [UIColor yellowColor];
self.tableView.tableHeaderView = headerview;

Ben de bu
istisnam

Yine de önerdiğiniz şeyi deneyeceğim, ama yarın sabah saat 1:34 yatacağım, zaman ayırıp cevap verdiğiniz için çok teşekkür ederim! (Ama gerçekten bir yükseklik belirtmek istemiyorum, bunun
CustomView'daki

Denedim ve evet çerçeveyi ayarlamak işe yarıyor, ancak çerçeveyi ayarlamaktan kaçınmanın bir yolunu arıyordum, aramaya devam edeceğim ve başka bir şey bulamazsam cevabınızı kabul edeceğim
ItsASecret

1
Eklenen başlık görünümü varsa bu istisnayı (şu anda test edilen 7.1) alıyorum translatesAutoresizingMaskIntoConstraints = NO. Çeviriyi açmak hatayı önler - UITableView7.1'den itibaren başlık görünümünü otomatik olarak düzenlemeye çalışmadığından ve çerçeve önceden ayarlanmış bir şey istediğinden şüpheleniyorum .
Benjohn

17

Burada çok fazla gereksiz şey yapan birçok yöntem gördüm, ancak başlık görünümünde otomatik düzeni kullanmak için bu kadar fazlasına ihtiyacınız yok. Sadece size xib dosyası oluşturmanız, kısıtlamalarınızı koymanız ve bunu şu şekilde başlatmanız gerekir:

func loadHeaderView () {
        guard let headerView = Bundle.main.loadNibNamed("CourseSearchHeader", owner: self, options: nil)?[0] as? UIView else {
            return
        }
        headerView.autoresizingMask = .flexibleWidth
        headerView.translatesAutoresizingMaskIntoConstraints = true
        tableView.tableHeaderView = headerView
    }

Bu, çok satırlı etiketlere sahip dinamik yükseklik başlığıyla iOS 11'de bizim için de işe yaradı.
Ben Scheirman

1
Elbette IB'deki flexibleHeight-Autoresizing-Option'ı da kaldırabilirsiniz.
d4Rk

TableFooterView'umun yüksekliğini (bir xib / uç aracılığıyla) ayarlamaya çalışıyordum ve çerçeve, yükseklik, layoutIfNeeded (), vb. Ayarlarında başarılı olamadım. Ama bu çözüm sonunda onu ayarlamama izin verdi.
vikzilla

Bir xib dosyasında tüm görünüme yükseklik kısıtlaması ayarlamayı unutmayın.
Denis Kutlubaev

6

Başka bir çözüm, başlık görünümü oluşturmayı bir sonraki ana iş parçacığı çağrısına göndermektir:

- (void)viewDidLoad {
    [super viewDidLoad];

    // ....

    dispatch_async(dispatch_get_main_queue(), ^{
        _profileView = [[MyView alloc] initWithNib:@"MyView.xib"];
        self.tableView.tableHeaderView = self.profileView;
    });
}

Not: Yüklenen görünüm sabit bir yüksekliğe sahip olduğunda hatayı düzeltir. Başlık yüksekliği yalnızca içeriğine bağlı olduğunda denemedim.

DÜZENLE :

Bu işlevi uygulayarak ve arayarak bu soruna daha temiz bir çözüm bulabilirsiniz .viewDidLayoutSubviews

- (void)viewDidLayoutSubviews {
    [super viewDidLayoutSubviews];

    [self sizeHeaderToFit];
}

1
@TussLaszlo tableHeaderView, otomatik düzen ile bir tür hatalı. Bunun gibi bazı geçici çözümler var. Bunu yazdım çünkü Ama, burada daha iyi ve daha temiz bir çözüm buldum stackoverflow.com/a/21099430/127493 onun arayarak - (void)sizeHeaderToFitinviewDidLayoutSubviews
Martin

4

Kod:

  extension UITableView {

          func sizeHeaderToFit(preferredWidth: CGFloat) {
            guard let headerView = self.tableHeaderView else {
              return
            }

            headerView.translatesAutoresizingMaskIntoConstraints = false
            let layout = NSLayoutConstraint(
              item: headerView,
              attribute: .Width,
              relatedBy: .Equal,
              toItem: nil,
              attribute:
              .NotAnAttribute,
              multiplier: 1,
              constant: preferredWidth)

            headerView.addConstraint(layout)

            let height = headerView.systemLayoutSizeFittingSize(UILayoutFittingCompressedSize).height
            headerView.frame = CGRectMake(0, 0, preferredWidth, height)

            headerView.removeConstraint(layout)
            headerView.translatesAutoresizingMaskIntoConstraints = true

            self.tableHeaderView = headerView
          }
  }

Tüm tablobaşı görünümü alt görünümlerine uygun otomatik düzen kısıtlamaları verin. Tek bir kısıtlamayı kaçırırsanız, işe yaramaz.
abhimuralidharan

4

Bu çözüm http://collindonnell.com/2015/09/29/dynamically-sized-table-view-header-or-footer-using-auto-layout/ tablo altbilgi görünümü için genişletildi :

@interface AutolayoutTableView : UITableView

@end

@implementation AutolayoutTableView

- (void)layoutSubviews {
    [super layoutSubviews];

    // Dynamic sizing for the header view
    if (self.tableHeaderView) {
        CGFloat height = [self.tableHeaderView systemLayoutSizeFittingSize:UILayoutFittingCompressedSize].height;
        CGRect headerFrame = self.tableHeaderView.frame;

        // If we don't have this check, viewDidLayoutSubviews() will get
        // repeatedly, causing the app to hang.
        if (height != headerFrame.size.height) {
            headerFrame.size.height = height;
            self.tableHeaderView.frame = headerFrame;
            self.tableHeaderView = self.tableHeaderView;
        }

        [self.tableHeaderView layoutIfNeeded];
    }

    // Dynamic sizing for the footer view
    if (self.tableFooterView) {
        CGFloat height = [self.tableFooterView systemLayoutSizeFittingSize:UILayoutFittingCompressedSize].height;
        CGRect footerFrame = self.tableFooterView.frame;

        // If we don't have this check, viewDidLayoutSubviews() will get
        // repeatedly, causing the app to hang.
        if (height != footerFrame.size.height) {
            footerFrame.size.height = height;
            self.tableFooterView.frame = footerFrame;
            self.tableFooterView = self.tableFooterView;
        }

        self.tableFooterView.transform = CGAffineTransformMakeTranslation(0, self.contentSize.height - footerFrame.size.height);
        [self.tableFooterView layoutIfNeeded];
    }
}

@end

Dün tableHeader'ın otomatik olarak yeniden boyutlandırılması / düzenlenmesi için bir gün geçirdim. Bu çözüm benim için çalışıyor. Çok teşekkürler.
docchang

Selam! Lütfen self.tableFooterView.transformbölümü açıklar mısınız? Neden gereklidir?
mrvn

@mrvn dönüşümü, altbilgiyi tableView'in altına taşımak için kullanılır.
k06a

3

SystemLayoutSizeFittingSize yöntemini kullanarak size bir boyut sağlamak için otomatik düzen elde edebilirsiniz .

Daha sonra uygulamanız için çerçeve oluşturmak için bunu kullanabilirsiniz. Bu teknik, dahili olarak otomatik düzen kullanan bir görünümün boyutunu bilmeniz gerektiğinde çalışır.

Swift'deki kod şuna benziyor:

//Create the view
let tableHeaderView = CustomTableHeaderView()

//Set the content
tableHeaderView.textLabel.text = @"Hello world"

//Ask auto layout for the smallest size that fits my constraints    
let size = tableHeaderView.systemLayoutSizeFittingSize(UILayoutFittingCompressedSize)

//Create a frame    
tableHeaderView.frame = CGRect(origin: CGPoint.zeroPoint, size: size)

//Set the view as the header    
self.tableView.tableHeaderView = self.tableHeaderView

Veya Objective-C'de

//Create the view
CustomTableHeaderView *header = [[CustomTableHeaderView alloc] initWithFrame:CGRectZero];

//Set the content
header.textLabel.text = @"Hello world";

//Ask auto layout for the smallest size that fits my constraints
CGSize size = [header systemLayoutSizeFittingSize:UILayoutFittingCompressedSize];

//Create a frame
header.frame = CGRectMake(0,0,size.width,size.height);

//Set the view as the header  
self.tableView.tableHeaderView = header

Ayrıca, bu özel durumda, alt sınıfınızda requireConstraintBasedLayout'u geçersiz kılmanın, bir düzen geçişinin gerçekleştirilmesine neden olduğu, ancak bu düzen geçişinin sonuçlarının göz ardı edildiği ve sistem çerçevesinin tableView genişliğine ve 0 yüksekliğine ayarlandığı da unutulmamalıdır.


3

Aşağıdakiler benim için çalıştı.

  1. UIViewBaşlık görünümü olarak sade bir eski kullanın .
  2. Buna alt görünümler ekleyin UIView
  3. Alt görünümlerde otomatik düzen kullanın

Gördüğüm ana fayda, çerçeve hesaplamalarını sınırlamaktır. Apple, UITableViewbunu kolaylaştırmak için API'sini gerçekten güncellemelidir .

SnapKit kullanım örneği:

let layoutView = UIView(frame: CGRect(x: 0, y: 0, width: tableView.bounds.width, height: 60))
layoutView.backgroundColor = tableView.backgroundColor
tableView.tableHeaderView = layoutView

let label = UILabel()
layoutView.addSubview(label)
label.text = "I'm the view you really care about"
label.snp_makeConstraints { make in
    make.edges.equalTo(EdgeInsets(top: 10, left: 15, bottom: -5, right: -15))
}

3

Tuhaf şeyler olur. systemLayoutSizeFittingSize, iOS9 için harika çalışıyor, ancak benim durumumda iOS 8 için çalışmıyor. Yani bu problemler oldukça kolay çözülür. Süper çağrı güncelleme başlık görünümü sınırlarından sonra yüksekliği CGRectGetMaxY (yourview.frame) + padding olarak ekleyerek başlıkta ve viewDidLayoutSubviews alt görünümde alt görünüme bağlantı alın

UPD: Şimdiye kadarki en kolay çözüm : Yani, başlık görünümünde alt görünümü yerleştirin ve sola , sağa , üste sabitleyin . Bu alt görünümde, alt görünümlerinizi otomatik yükseklik kısıtlamaları ile yerleştirin. Bundan sonra tüm işi otomatik düzene verin (hesaplama gerekmez)

- (void)viewDidLayoutSubviews {
    [super viewDidLayoutSubviews];

    CGFloat height = CGRectGetMaxY(self.tableView.tableHeaderView.subviews.firstObject.frame);
    self.tableView.tableHeaderView.bounds = CGRectMake(0, 0, CGRectGetWidth(self.tableView.bounds), height);
    self.tableView.tableHeaderView = self.tableView.tableHeaderView;
}

Sonuç olarak, alt görünüm olması gerektiği gibi genişliyor / küçülüyor, sonunda viewDidLayoutSubviews'i çağırıyor. Şu anda görünümün gerçek boyutunu biliyoruz, bu nedenle headerView yüksekliğini ayarlayın ve yeniden atayarak güncelleyin. Tıkır tıkır çalışıyor!

Ayrıca altbilgi görünümü için de çalışır.


1
Bu, iOS 10'da benim için döngüye giriyor.
Simon

3

Swift 4.2 için güncellendi

extension UITableView {

    var autolayoutTableViewHeader: UIView? {
        set {
            self.tableHeaderView = newValue
            guard let header = newValue else { return }
            header.setNeedsLayout()
            header.layoutIfNeeded()
            header.frame.size = 
            header.systemLayoutSizeFitting(UIView.layoutFittingCompressedSize)
            self.tableHeaderView = header
        }
        get {
            return self.tableHeaderView
        }
    }
}

2

Doğru bir şekilde yerleştirmek için başlık ve tablo görünümü arasına üst + yatay konum kısıtlaması ekleyebilirsiniz (başlığın kendisi doğru bir çerçeveye sahip olmak için gerekli tüm dahili düzen kısıtlamalarını içeriyorsa)

tableViewController viewDidLoad yönteminde

    headerView.translatesAutoresizingMaskIntoConstraints = false

    tableView.tableHeaderView = headerView

    headerView.widthAnchor.constraint(equalTo: tableView.widthAnchor).isActive = true
    headerView.topAnchor.constraint(equalTo: tableView.topAnchor).isActive = true
    headerView.centerXAnchor.constraint(equalTo: tableView.centerXAnchor).isActive = true

1

Tablo başlık görünümüm bir UIView alt sınıfıdır - Başlatıcı içinde, sınırları tablo başlığı görünümünün çerçevesiyle aynı olan tek bir contentView UIView oluşturdum ve tüm nesnelerimi bunun bir alt görünümü olarak ekledim.

Ardından, nesneleriniz için kısıtlamaları layoutSubviewsbaşlatıcı yerine tablo başlığı görünümünün yöntemine ekleyin . Bu kazayı çözdü.

- (id)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:CGRectMake(0, 0, 0, 44.0)];
    if (self) {
        UIView *contentView = [[UIView alloc] initWithFrame:self.bounds];
        contentView.autoresizingMask = UIViewAutoresizingFlexibleWidth;

        // add other objects as subviews of content view

    }
    return self;
}

- (void)layoutSubviews
{
    [super layoutSubviews];

    // remake constraints here
}

1

Otomatik Yerleşimim çok iyi çalışıyor:

CGSize headerSize = [headerView systemLayoutSizeFittingSize:CGSizeMake(CGRectGetWidth([UIScreen mainScreen].bounds), 0) withHorizontalFittingPriority:UILayoutPriorityRequired verticalFittingPriority:UILayoutPriorityFittingSizeLevel];
headerView.frame = CGRectMake(0, 0, headerSize.width, headerSize.height);
self.tableView.tableHeaderView = headerView;

Bunu tam olarak yapmadım ama sen bana iyi bir fikir verdin - headerView'ı kaldırmak, çerçevesini yeniden ayarlamak ve tekrar eklemek.
dinesharjani

1

Çoğu durumda en iyi çözüm çerçeveyle savaşmamak ve otomatik yeniden boyutlandırma maskelerini benimsememektir:

// embrace autoresizing masks and let the framework add the constraints for you
headerView.translatesAutoresizingMaskIntoConstraints = true
headerView.autoresizingMask = [.flexibleWidth, .flexibleHeight]

// figure out what's the best size based on the table view width
let width = self.tableView.frame.width
let targetSize = headerView.systemLayoutSizeFitting(CGSize(width: width, height: CGFloat.greatestFiniteMagnitude), withHorizontalFittingPriority: .required, verticalFittingPriority: .fittingSizeLevel)
headerView.frame.size = targetSize
self.tableView.tableHeaderView = headerView

Otomatik yeniden boyutlandırma maskelerini kullanarak, çerçeveye, süpervizör boyutu değiştiğinde görünümünüzün boyutunu nasıl değiştirmesi gerektiğini anlatırsınız. Ancak bu değişiklik, belirlediğiniz ilk kareye bağlıdır.


0

Bunun eski bir gönderi olduğunu biliyorum ama bununla ilgili tüm SO gönderilerini inceledikten ve bütün bir öğleden sonra bununla oynadıktan sonra nihayet temiz ve yine de çok basit bir çözüm buldum.

Her şeyden önce, benim görüş hiyerarşim şuna benzer:

  1. Tablo görünümü
    1. Görünüm tableHeaderView
      1. Görünüm bir çıkış denir ile headerView

Şimdi Görünümün (No.3) içinde, tüm kısıtlamaları normalde alt alanı konteynere dahil edeceğim şekilde ayarlıyorum. Bu, kabın (yani 3.View yani headerView) alt görünümlerine ve kısıtlamalarına göre kendisini boyutlandırmasını sağlayacaktır.

Bundan sonra, sınırlamaları bunlara 3. Viewve 2. Viewbunlara ayarlıyorum :

  1. Konteynere Üst Alan: 0
  2. Öncü Uzaydan konteynere: 0
  3. Uzaydan konteynere son: 0

En alt alanı kasıtlı olarak atladığıma dikkat edin.

Bunların hepsi film şeridinde yapıldıktan sonra, yapılması gereken her şey bu üç satır kodu yapıştırmaktır:

if (self.headerView.frame.size.height != self.tableView.tableHeaderView.frame.size.height) {
    UIView *header = self.tableView.tableHeaderView;
    CGRect frame = self.tableView.tableHeaderView.frame;
    frame.size.height = self.headerView.frame.size.height + frame.origin.y;
    header.frame = frame;
    self.tableView.tableHeaderView = header;
}

0

İpuçları: setAndLayoutTableHeaderView yöntemini kullanırsanız, alt görünümlerin çerçevesini güncellemelisiniz, bu nedenle bu durumda UILabel'in preferMaxLayoutWidth'i systemLayoutSizeFittingSize çağrılmadan önce çağırmalıdır, layoutSubview'da arama yapmayın.

kod gösterisi


0

Yaklaşımımı paylaşın.

UITableView+XXXAdditions.m

- (void)xxx_setTableHeaderView:(UIView *)tableHeaderView layoutBlock:(void(^)(__kindof UIView *tableHeaderView, CGFloat *containerViewHeight))layoutBlock {
      CGFloat containerViewHeight = 0;
      UIView *backgroundView = [[UIView alloc] initWithFrame:CGRectZero];
      [backgroundView addSubview:tableHeaderView];
      layoutBlock(tableHeaderView, &containerViewHeight);

      backgroundView.frame = CGRectMake(0, 0, 0, containerViewHeight);

      self.tableHeaderView = backgroundView;
}

Kullanım.

[self.tableView xxx_setTableHeaderView:myView layoutBlock:^(__kindof UIView * _Nonnull tableHeaderView, CGFloat *containerViewHeight) {
    *containerViewHeight = 170;

    [tableHeaderView mas_makeConstraints:^(MASConstraintMaker *make) {
      make.top.equalTo(@20);
      make.centerX.equalTo(@0);
      make.size.mas_equalTo(CGSizeMake(130, 130));
    }];
  }];

0

Benim durumumda systemLayoutSizeFittingSize ile yöntemim nedense işe yaramadı. Benim için işe yarayan şey, HotJard tarafından yayınlanan bir çözüm değişikliğidir (orijinal çözümü de iOS 8'deki durumumda işe yaramadı). Yapmam gereken şey, başlık görünümünde bir alt görünüm yerleştirmek ve onu sola, sağa, üste sabitlemektir (aşağıya sabitlemeyin). Otomatik düzen kullanarak her şeyi bu alt görünümde yerleştirin ve kodda şunu yapın:

- (void)viewDidLayoutSubviews
{
    [super viewDidLayoutSubviews];
    [self resizeHeaderToFitSubview];
}

- (void)resizeHeaderToFitSubview
{
    UIView *header = self.tableView.tableHeaderView;
    [header setNeedsLayout];
    [header layoutIfNeeded];
    CGFloat height = CGRectGetHeight(header.subviews.firstObject.bounds);
    header.bounds = CGRectMake(0, 0, CGRectGetWidth(self.tableView.bounds), height);
    self.tableView.tableHeaderView = nil;
    self.tableView.tableHeaderView = header;
}

0

Eski bir gönderi. Ama iyi bir gönderi. İşte benim 2 sentim.

İlk olarak, başlık görünümünüzün kendi iç içerik boyutunu destekleyebilecek şekilde düzenlenmiş olduğundan emin olun. Sonra aşağıdakileri yapın.

//ViewDidLoad
headerView.translatesAutoresizingMaskIntoConstraints = false
headerView.configure(title: "Some Text A")

//Somewhere else
headerView.update(title: "Some Text B)

private var widthConstrained = false

override func viewDidLayoutSubviews() {
    super.viewDidLayoutSubviews()
    if widthConstrained == false {
        widthConstrained = true
        tableView.addConstraint(NSLayoutConstraint(item: headerView, attribute: .width, relatedBy: .equal, toItem: tableView, attribute: .width, multiplier: 1, constant: 0))
        headerView.layoutIfNeeded()
        tableView.layoutIfNeeded()
    }
}

override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
    super.viewWillTransition(to: size, with: coordinator)
    coordinator.animate(alongsideTransition: { (context) in
        self.headerView.layoutIfNeeded()
        self.tableView.layoutIfNeeded()
    }, completion: nil)
}

0

Bunu aşağıdaki yaklaşımla başardım (bu, altbilgi için de aynı şekilde çalışır).

İlk önce küçük ihtiyacınız olacak UITableView uzantıya :

Hızlı 3

extension UITableView {
    fileprivate func adjustHeaderHeight() {
        if let header = self.tableHeaderView {
            adjustFrame(header)
        }
    }

    private func adjustFrame(_ view: UIView) {
        view.frame.size.height = calculatedViewHeight(view)
    }

    fileprivate func calculatedHeightForHeader() -> CGFloat {
        if let header = self.tableHeaderView {
            return calculatedViewHeight(header)
        }
        return 0.0
    }

    private func calculatedViewHeight(_ view: UIView) -> CGFloat {
        view.setNeedsLayout()
        let height = view.systemLayoutSizeFitting(UILayoutFittingCompressedSize).height
        return height
    }
}

Görünüm denetleyici sınıfı uygulamanızda:

// this is a UIView subclass with autolayout
private var headerView = MyHeaderView()

override func loadView() {
    super.loadView()
    // ...
    self.tableView.tableHeaderView = headerView
    self.tableView.sectionHeaderHeight = UITableViewAutomaticDimension
    // ...
}

override func viewWillLayoutSubviews() {
    super.viewWillLayoutSubviews()

    // this is to prevent recursive layout calls
    let requiredHeaderHeight = self.tableView.calculatedHeightForHeader()
    if self.headerView.frame.height != requiredHeaderHeight {
        self.tableView.adjustHeaderHeight()
    }
}

Bir başlığın alt UIViewgörünüm uygulamasıyla ilgili notlar :

  1. Başlık görünümünüzün doğru otomatik düzen kurulumuna sahip olduğundan% 100 emin olmalısınız. Basit bir başlık görünümü ile sadece bir yükseklik kısıtlamasıyla başlamanızı ve yukarıdaki kurulumu denemenizi öneririm.

  2. Geçersiz kıl requiresConstraintBasedLayoutve geri dön true:

.

class MyHeaderView: UIView {
   // ...
   override static var requiresConstraintBasedLayout : Bool {
       return true
   }
   // ...
}

0

Xamarin kullanıcıları için:

public override void ViewDidLayoutSubviews()
{
    base.ViewDidLayoutSubviews();

    TableviewHeader.SetNeedsLayout();
    TableviewHeader.LayoutIfNeeded();

    var height = TableviewHeader.SystemLayoutSizeFittingSize(UIView.UILayoutFittingCompressedSize).Height;
    var frame = TableviewHeader.Frame;
    frame.Height = height;
    TableviewHeader.Frame = frame;
}

Tablo görünümünüzün başlık görünümünü TableviewHeader olarak adlandırdığınızı varsayarsak


0

İşte nasıl yapabileceğiniz UIViewController

override func viewDidLayoutSubviews() {
    super.viewDidLayoutSubviews()

    if headerView.frame.size.height == 0 {
      headerView.label.preferredMaxLayoutWidth = view.bounds.size.width - 20
      let height = headerView.systemLayoutSizeFitting(UILayoutFittingCompressedSize).height

      headerView.frame.size = CGSize(width: tableView.bounds.size.width, height: height)
    }
  }

0

Herhangi bir kısıtlama temelli UIViewiyi olabilir tableHeaderView.

Bir ihtiyaçları belirlemek için tableFooterViewönce ve sonra ek sondaki kısıtlamasını empoze tableFooterViewve tableHeaderView.

- (void)viewDidLoad {

    ........................
    // let self.headerView is some constraint-based UIView
    self.tableView.tableFooterView = [UIView new];
    [self.headerView layoutIfNeeded];
    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;
    [self.tableFooterView.trailingAnchor constraintEqualToAnchor:self.headerView.trailingAnchor].active = YES;

}

Tüm ayrıntıları ve kod parçalarını burada bulabilirsiniz


0

Bir çözüm buldum. autolayout wrriten xib başlık görünümünüzü boş bir uiview sarmalayıcısına sarın ve başlık görünümünü tableView'in tableViewHeader özelliğine atayın.

    UIView *headerWrapper = [[UIView alloc] init];
    AXLHomeDriverHeaderView *headerView = [AXLHomeDriverHeaderView loadViewFromNib];
    [headerWrapper addSubview:headerView];
    [headerView mas_makeConstraints:^(MASConstraintMaker *make) {
        make.edges.equalTo(headerWrapper);
    }];
    self.tableView.tableHeaderView = headerView;

0

İOS 12'de UITableViewController için işe yarayan özellikler şunlardır:

Üstbilgi için tüm prototip hücrelerinin üzerinde ve altbilgi için tüm prototip hücrelerinin altında TableView'e bir UIView yerleştirin. Üstbilgi ve altbilginizi gerektiği gibi ayarlayın. Gerekli tüm kısıtlamaları ayarlayın.

Şimdi aşağıdaki uzantı yöntemlerini kullanın

public static class UITableVIewExtensions
{

    public static void MakeHeaderAutoDimension(this UITableView tableView)
    {
        if (tableView.TableHeaderView is UIView headerView) {
            var size = headerView.SystemLayoutSizeFittingSize(UIView.UILayoutFittingCompressedSize);
            if (headerView.Frame.Size.Height != size.Height) {
                var frame = headerView.Frame;
                frame.Height = size.Height;
                headerView.Frame = frame;
                tableView.TableHeaderView = headerView;
                tableView.LayoutIfNeeded();
            }
        }
    }

    public static void MakeFooterAutoDimension(this UITableView tableView)
    {
        if (tableView.TableFooterView is UIView footerView) {
            var size = footerView.SystemLayoutSizeFittingSize(UIView.UILayoutFittingCompressedSize);
            if (footerView.Frame.Size.Height != size.Height) {
                var frame = footerView.Frame;
                frame.Height = size.Height;
                footerView.Frame = frame;
                tableView.TableFooterView = footerView;
                tableView.LayoutIfNeeded();
            }
        }
    }
}

ve UITableViewController alt sınıfının ViewDidLayoutSubviews'lerinde çağırın

public override void ViewDidLayoutSubviews()
{
    base.ViewDidLayoutSubviews();

    TableView.MakeHeaderAutoDimension();
    TableView.MakeFooterAutoDimension();
}

0

375pt genişlik alma sorunuyla karşılaştım, benim için işe yarayan tek yol, doğru genişliği elde etmek için tableView'i aktarmak. Ayrıca Çerçeve boyutunu ayarlamak yerine Otomatik Yerleşimi tercih ettim.

İşte benim için çalışan sürüm:

Xamarin.iOS

public static void AutoLayoutTableHeaderView(this UITableView tableView, UIView header)
{
    tableView.TableHeaderView = header;
    tableView.SetNeedsLayout();
    tableView.LayoutIfNeeded();
    header.WidthAnchor.ConstraintEqualTo(tableView.Bounds.Width).Active = true;       
    tableView.TableHeaderView = header;
}

Swift Versiyonu (@Ben Packard cevabından değiştirildi)

extension UITableView {
    //set the tableHeaderView so that the required height can be determined, update the header's frame and set it again
    func setAndLayoutTableHeaderView(header: UIView) {
        self.tableHeaderView = header
        self.setNeedsLayout()
        self.layoutIfNeeded()
        header.widthAnchor.widthAnchor.constraint(equalTo: self.bounds.width).isActive = true
        self.tableHeaderView = header
    }
}


0

Benim çözümüm bunun gibi yeni bir sınıf oluşturmak.

class BaseTableHeaderView: UIView {

    func sizeToFitBasedOnConstraints(width: CGFloat = Screen.width) {
        let size = systemLayoutSizeFitting(CGSize(width: width, height: 10000),
                                              withHorizontalFittingPriority: .required,
                                              verticalFittingPriority: .fittingSizeLevel)
        frame = CGRect(origin: .zero, size: size)
    }

    override func willMove(toSuperview newSuperview: UIView?) {
        sizeToFitBasedOnConstraints()
        super.willMove(toSuperview: newSuperview)
    }

}

Kullanmak için, tüm alt görünümlerinizi bir örneğine BaseTableHeaderViewekleyin ve tablo görünümünüze ekleyin.

let tableHeaderView = BaseTableHeaderView()
tableHeaderView.addSubview(...)
tableView.tableHeaderView = tableHeaderView

Kısıtlamalarına göre otomatik olarak yeniden boyutlandırılacaktır.


-1

Kabul edilen yanıt, yalnızca tek bölümlü tablolar için kullanışlıdır. Çoklu bölüm UITableViewiçin, başlığınızınUITableViewHeaderFooterView ve iyi olacaksınız.

Alternatif olarak, mevcut başlığınızı contentViewbir UITableViewHeaderFooterView. Tam olarak UITableViewCelleserler gibi .


9
soru tableHeaderViewbölüm başlığı ile ilgili değil.
Rpranata
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.