Dinamik hücre düzenleri ve değişken satır yükseklikleri için UITableView'da Otomatik Düzen kullanma


1501

UITableViewCellDüzgün kaydırma performansını korurken, her hücrenin içeriğinin ve alt görünümlerinin satır yüksekliğini (kendiliğinden / otomatik olarak) belirlemesini sağlamak için tablo görünümündeki Otomatik Mizanpaj'ı nasıl kullanırsınız ?


İşte hızlı bir şekilde örnek kod 2.3 github.com/dpakthakur/DynamicCellHeight
Deepak Thakur

Çok satırlı bir UILabel'a ilişkin cevapların çoğunu anlamak için, nasıl contentSizeve nasıl preferredMaxLayoutWidthçalıştığını tam olarak anlamanız gerekir . Buraya bakın . Kısıtlamalarınızı doğru bir şekilde ayarlarsanız, buna ihtiyacınız olmamalı preferredMaxLayoutWidthve aslında beklenmedik sonuçlar yaratabilirsiniz.
Bal

Yanıtlar:


2387

TL; DR: Okumayı sevmiyor musunuz? Doğrudan GitHub'daki örnek projelere atlayın:

Kavramsal Açıklama

Aşağıdaki ilk 2 adım, hangi iOS sürümleri için geliştirdiğinizden bağımsız olarak geçerlidir.

1. Kısıtlamalar Ayarla ve Ekle

Senin içinde UITableViewCellhücrenin subviews hücrenin kenarlarına sabitlenmiş onların kenarları, böylece alt sınıf, kısıtlamaları eklemek contentView (en önemlisi üst hem de alt kenarlarına). NOT: alt görünümleri hücrenin kendisine sabitlemeyin; sadece hücrenin contentView! Bu alt görüntülerin gerçek içerik boyutunun, her bir alt görünüm için dikey boyuttaki içerik sıkıştırma direncinin ve içerik sarılma kısıtlamalarının eklediğiniz daha yüksek öncelikli kısıtlamalarla geçersiz kılınmamasını sağlayarak tablo görünümü hücresinin içerik görünümünün yüksekliğini artırmasına izin verin . ( Ha? Buraya tıklayın. )

Unutmayın, fikir, hücrenin alt görünümlerinin hücrenin içerik görünümüne dikey olarak bağlanmasıdır, böylece "baskı uygulayabilir" ve içerik görünümünü onlara uyacak şekilde genişletebilirler. Birkaç alt görünüme sahip örnek bir hücre kullanarak , kısıtlamalarınızın bazılarının (hepsi değil!) Neye benzemesi gerektiğini gösteren görsel bir örnek :

Tablo görünümü hücresindeki kısıtlamaların örnek gösterimi.

Yukarıdaki örnek hücredeki çok satırlı gövde etiketine daha fazla metin eklendikçe, metni sığdırmak için dikey olarak büyümesi gerekeceğini ve bu da hücrenin yükseklikte büyümesini zorlayacağını hayal edebilirsiniz. (Elbette, bunun doğru bir şekilde çalışması için kısıtlamaları doğru yapmanız gerekir!)

Kısıtlamalarınızı doğru bir şekilde yapmak, dinamik hücre yüksekliklerini Otomatik Yerleşim ile çalışmanın kesinlikle en zor ve en önemli parçasıdır . Burada bir hata yaparsanız, her şeyin çalışmasını engelleyebilir - bu yüzden acele etmeyin! Hangi kısıtlamaların nereye eklendiğini tam olarak bildiğiniz için kısıtlamalarınızı kodda ayarlamanızı öneririz ve işler ters gittiğinde hata ayıklamak çok daha kolaydır. Kodda kısıtlama eklemek, yerleşim bağlantılarını veya GitHub'da bulunan harika açık kaynak API'lerinden birini kullanarak Interface Builder kadar kolay ve önemli ölçüde daha güçlü olabilir.

  • Kodda kısıtlamalar ekliyorsanız, bunu bir kez updateConstraintsUITableViewCell alt sınıfınızın yöntemi içinden yapmanız gerekir . updateConstraintsBir kereden fazla çağrılabileceğini unutmayın , bu nedenle aynı kısıtlamaları bir kereden fazla eklemekten kaçınmak için, kısıtlama kodunuzu ( updateConstraintsörneğin didSetupConstraints, kısıtlamanızı çalıştırdıktan sonra EVET olarak ayarladığınız) -kod eklendikten sonra). Öte yandan, mevcut kısıtlamaları güncelleyen bir kodunuz varsa ( constantbazı kısıtlamalarda özelliği ayarlamak gibi ), yöntemin her çağrıldığında çalışabilmesi updateConstraintsiçin didSetupConstraintsbunu denetimin içine ama dışına yerleştirin .

2. Benzersiz Tablo Görünümü Hücre Yeniden Tanımlama Tanımlayıcılarını Belirleme

Hücredeki her benzersiz sınırlama kümesi için benzersiz bir hücre yeniden kullanım tanımlayıcısı kullanın. Başka bir deyişle, hücreleriniz birden fazla benzersiz düzene sahipse, her benzersiz düzen kendi yeniden kullanım tanımlayıcısını almalıdır. (Yeni bir yeniden kullanım tanımlayıcısı kullanmanız için iyi bir ipucu, hücre değişkeninizin farklı sayıda alt görünümü olduğunda veya alt görünümlerin farklı bir şekilde düzenlenmiş olmasıdır.)

Örneğin, her hücrede bir e-posta mesajı görüntülüyorsanız, 4 benzersiz mizanpajınız olabilir: yalnızca konu içeren mesajlar, konu ve gövde içeren mesajlar, konu ve mesaj ekli mesajlar ve konu içeren mesajlar, gövde ve fotoğraf eki. Her düzen, bunu başarmak için tamamen farklı kısıtlamalara sahiptir, bu nedenle hücre başlatıldıktan ve bu hücre türlerinden biri için kısıtlamalar eklendiğinde, hücre, bu hücre türüne özgü benzersiz bir yeniden kullanım tanımlayıcısı almalıdır. Bu, bir hücreyi yeniden kullanmak üzere ayırdığınızda, kısıtlamalar zaten eklenmiş ve bu hücre türüne gitmeye hazır olduğunuz anlamına gelir.

İçsel içerik boyutundaki farklılıklar nedeniyle, aynı kısıtlamalara (tip) sahip hücrelerin yine de değişen yükseklikleri olabilir! Farklı içerik boyutları nedeniyle temel olarak farklı düzenleri (farklı kısıtlamalar) farklı hesaplanmış görünüm çerçeveleriyle (özdeş kısıtlamalardan çözülmüş) karıştırmayın.

  • Aynı yeniden kullanım havuzuna tamamen farklı kısıtlama kümelerine sahip hücreler eklemeyin (örn. Aynı yeniden kullanım tanımlayıcısını kullanın) ve ardından eski kısıtlamaları kaldırmaya ve her bir ayrışmadan sonra sıfırdan yeni kısıtlamalar oluşturmaya çalışmayın. Dahili Otomatik Yerleşim motoru, kısıtlamalardaki büyük ölçekli değişiklikleri ele alacak şekilde tasarlanmamıştır ve büyük performans sorunları görürsünüz.

İOS 8 için - Kendiliğinden Boyutlanan Hücreler

3. Satır Yüksekliği Tahminini Etkinleştir

Kendi kendine boyutlandırma tablo görünümü hücrelerini etkinleştirmek için, tablo görünümünün rowHeight özelliğini UITableViewAutomaticDimension olarak ayarlamanız gerekir. TahminiRowHeight özelliğine de bir değer atamalısınız. Bu özelliklerin her ikisi de ayarlanır ayarlanmaz, sistem satırın gerçek yüksekliğini hesaplamak için Otomatik Düzen'i kullanır

Apple: Kendinden Boyutlandırmalı Masa Görünümü Hücreleriyle Çalışma

İOS 8 ile Apple, daha önce iOS 8'den önce uygulamanız gereken işlerin çoğunu içselleştirdi: Kendiliğinden boyutlanan hücre mekanizmasının çalışmasına izin vermek için rowHeight, önce tablo görünümündeki özelliği sabit olarak ayarlamanız gerekir. UITableViewAutomaticDimension. Ardından, tablo görünümünün estimatedRowHeightözelliğini sıfır olmayan bir değere ayarlayarak satır yüksekliği tahminini etkinleştirmeniz yeterlidir , örneğin:

self.tableView.rowHeight = UITableViewAutomaticDimension;
self.tableView.estimatedRowHeight = 44.0; // set to whatever your "average" cell height is

Bunun yaptığı, tablo görünümüne henüz ekranda olmayan hücrelerin satır yükseklikleri için geçici bir tahmin / yer tutucu sağlamaktır. Daha sonra, bu hücreler ekranda kaydırılmak üzereyken, gerçek satır yüksekliği hesaplanacaktır. Her satır için gerçek yüksekliği belirlemek için, tablo görünümü her hücreye contentViewiçerik görünümünün bilinen sabit genişliğine (tablo görünümünün genişliğine dayanarak, bir bölüm dizini gibi ek şeyler eklenmesi) dayanması gereken yüksekliği otomatik olarak sorar. veya aksesuar görünümü) ve hücrenin içerik görünümüne ve alt görünümlerine eklediğiniz otomatik mizanpaj kısıtlamaları. Bu gerçek hücre yüksekliği belirlendikten sonra, satır için eski tahmini yükseklik yeni gerçek yükseklikle güncellenir (ve tablo görünümünün contentSize / contentOffset öğesinde yapılan tüm değişiklikler sizin için gerektiği gibi yapılır).

Genel olarak, sağladığınız tahminin çok doğru olması gerekmez - yalnızca kaydırma göstergesini tablo görünümünde doğru bir şekilde boyutlandırmak için kullanılır ve tablo görünümü, yanlış göstergeler için kaydırma göstergesini sizin gibi ayarlamak için iyi bir iş çıkarır. ekran üzerinde kaydırma hücreleri. Sen koymalıdır estimatedRowHeighttablo (görünümünde mülk viewDidLoad"ortalama" satır yüksekliği sabit bir değere veya benzeri). Yalnızca sıra yükseklikleriniz aşırı değişkenliğe sahipse (örn. Büyüklük sırasına göre farklılık gösterir) ve tableView:estimatedHeightForRowAtIndexPath:her bir satır için daha doğru bir tahmin döndürmek için gereken minimum hesaplamayı yapmak için uygulamayı yaparken, kaydırma sırasında kaydırma göstergesinin "atlama" olduğunu fark ederseniz .

İOS 7 desteği için (otomatik hücre boyutlandırmasını kendiniz uygulama)

3. Düzen Geçişi Yapın ve Hücre Yüksekliğini Alın

İlk olarak, kesinlikle yükseklik hesaplamaları için kullanılan her yeniden kullanım tanımlayıcısı için bir örnek olan bir tablo görünümü hücresinin bir ekran dışı örneğini başlatın . (Hücre başvurusunun, görünüm denetleyicisindeki bir özellik / ivar'da depolandığı ve hiçbir zaman tableView:cellForRowAtIndexPath:tablo görünümünün gerçekten ekranda görüntülenmesi için döndürülmediği anlamına gelir .) Ardından, hücrenin tam içerikle yapılandırılması gerekir (örn. Metin, resimler vb.). tablo görünümünde görüntülenecekse tutacağını unutmayın.

Ardından, hücreyi hemen alt görünümlerini düzenlemeye zorlayın ve ardından hücrenin gerekli yüksekliğinin ne olduğunu bulmak systemLayoutSizeFittingSize:için UITableViewCell's yöntemini kullanın contentView. UILayoutFittingCompressedSizeHücrenin tüm içeriğine sığması için gereken en küçük boyutu elde etmek için kullanın . Yükseklik daha sonra tableView:heightForRowAtIndexPath:delege yönteminden döndürülebilir .

4. Tahmini Satır Yüksekliklerini Kullanma

Tablo görünümünüzde birkaç düzineden fazla satır varsa, Otomatik Yükleme kısıtlama çözme işleminin, ilk yükleme sonrasında tableView:heightForRowAtIndexPath:her bir satırda çağrıldığı gibi , tablo görünümünü ilk yüklerken ana iş parçacığını hızla aşağı çekebileceğini göreceksiniz ( kaydırma göstergesinin boyutunu hesaplamak için).

İOS 7'den itibaren estimatedRowHeightözelliği tablo görünümünde kullanabilirsiniz (ve kesinlikle kullanmalısınız) . Bunun yaptığı, tablo görünümüne henüz ekranda olmayan hücrelerin satır yükseklikleri için geçici bir tahmin / yer tutucu sağlamaktır. Daha sonra, bu hücreler ekranda kaydırılmak üzereyken, gerçek satır yüksekliği (çağrılarak tableView:heightForRowAtIndexPath:) hesaplanacak ve tahmini yükseklik gerçek hücre ile güncellenecektir.

Genel olarak, sağladığınız tahminin çok doğru olması gerekmez - yalnızca kaydırma göstergesini tablo görünümünde doğru bir şekilde boyutlandırmak için kullanılır ve tablo görünümü, yanlış göstergeler için kaydırma göstergesini sizin gibi ayarlamak için iyi bir iş çıkarır. ekran üzerinde kaydırma hücreleri. Sen koymalıdır estimatedRowHeighttablo (görünümünde mülk viewDidLoad"ortalama" satır yüksekliği sabit bir değere veya benzeri). Yalnızca sıra yükseklikleriniz aşırı değişkenliğe sahipse (örn. Büyüklük sırasına göre farklılık gösterir) ve tableView:estimatedHeightForRowAtIndexPath:her bir satır için daha doğru bir tahmin döndürmek için gereken minimum hesaplamayı yapmak için uygulamayı yaparken, kaydırma sırasında kaydırma göstergesinin "atlama" olduğunu fark ederseniz .

5. (Gerekirse) Satır Yüksekliği Önbelleği Ekleme

Yukarıdakilerin tümünü yaptıysanız ve kısıtlama çözümü yaparken performansın kabul edilemez derecede yavaş olduğunu düşünüyorsanız tableView:heightForRowAtIndexPath:, maalesef hücre yükseklikleri için bazı önbellekleme uygulamanız gerekir. (Bu, Apple mühendisleri tarafından önerilen yaklaşımdır.) Genel fikir, Autolayout motorunun kısıtlamaları ilk kez çözmesine izin vermek, ardından o hücre için hesaplanan yüksekliği önbelleğe almak ve o hücrenin yüksekliği için gelecekteki tüm istekler için önbelleğe alınan değeri kullanmaktır. Elbette hile, hücrenin yüksekliğinin değişmesine neden olabilecek herhangi bir şey olduğunda bir hücrenin önbelleğe alınmış yüksekliğini temizlediğinizden emin olmaktır - öncelikle, bu hücrenin içeriği değiştiğinde veya diğer önemli olaylar gerçekleştiğinde (kullanıcı ayarlaması gibi) Dinamik Tür metin boyutu kaydırıcısı).

iOS 7 Genel Örnek Kodu (birçok sulu yorum ile)

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    // Determine which reuse identifier should be used for the cell at this 
    // index path, depending on the particular layout required (you may have
    // just one, or may have many).
    NSString *reuseIdentifier = ...;

    // Dequeue a cell for the reuse identifier.
    // Note that this method will init and return a new cell if there isn't
    // one available in the reuse pool, so either way after this line of 
    // code you will have a cell with the correct constraints ready to go.
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:reuseIdentifier];

    // Configure the cell with content for the given indexPath, for example:
    // cell.textLabel.text = someTextForThisCell;
    // ...

    // Make sure the constraints have been set up for this cell, since it 
    // may have just been created from scratch. Use the following lines, 
    // assuming you are setting up constraints from within the cell's 
    // updateConstraints method:
    [cell setNeedsUpdateConstraints];
    [cell updateConstraintsIfNeeded];

    // If you are using multi-line UILabels, don't forget that the 
    // preferredMaxLayoutWidth needs to be set correctly. Do it at this 
    // point if you are NOT doing it within the UITableViewCell subclass 
    // -[layoutSubviews] method. For example: 
    // cell.multiLineLabel.preferredMaxLayoutWidth = CGRectGetWidth(tableView.bounds);

    return cell;
}

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
    // Determine which reuse identifier should be used for the cell at this 
    // index path.
    NSString *reuseIdentifier = ...;

    // Use a dictionary of offscreen cells to get a cell for the reuse 
    // identifier, creating a cell and storing it in the dictionary if one 
    // hasn't already been added for the reuse identifier. WARNING: Don't 
    // call the table view's dequeueReusableCellWithIdentifier: method here 
    // because this will result in a memory leak as the cell is created but 
    // never returned from the tableView:cellForRowAtIndexPath: method!
    UITableViewCell *cell = [self.offscreenCells objectForKey:reuseIdentifier];
    if (!cell) {
        cell = [[YourTableViewCellClass alloc] init];
        [self.offscreenCells setObject:cell forKey:reuseIdentifier];
    }

    // Configure the cell with content for the given indexPath, for example:
    // cell.textLabel.text = someTextForThisCell;
    // ...

    // Make sure the constraints have been set up for this cell, since it 
    // may have just been created from scratch. Use the following lines, 
    // assuming you are setting up constraints from within the cell's 
    // updateConstraints method:
    [cell setNeedsUpdateConstraints];
    [cell updateConstraintsIfNeeded];

    // Set the width of the cell to match the width of the table view. This
    // is important so that we'll get the correct cell height for different
    // table view widths if the cell's height depends on its width (due to 
    // multi-line UILabels word wrapping, etc). We don't need to do this 
    // above in -[tableView:cellForRowAtIndexPath] because it happens 
    // automatically when the cell is used in the table view. Also note, 
    // the final width of the cell may not be the width of the table view in
    // some cases, for example when a section index is displayed along 
    // the right side of the table view. You must account for the reduced 
    // cell width.
    cell.bounds = CGRectMake(0.0, 0.0, CGRectGetWidth(tableView.bounds), CGRectGetHeight(cell.bounds));

    // Do the layout pass on the cell, which will calculate the frames for 
    // all the views based on the constraints. (Note that you must set the 
    // preferredMaxLayoutWidth on multiline UILabels inside the 
    // -[layoutSubviews] method of the UITableViewCell subclass, or do it 
    // manually at this point before the below 2 lines!)
    [cell setNeedsLayout];
    [cell layoutIfNeeded];

    // Get the actual height required for the cell's contentView
    CGFloat height = [cell.contentView systemLayoutSizeFittingSize:UILayoutFittingCompressedSize].height;

    // Add an extra point to the height to account for the cell separator, 
    // which is added between the bottom of the cell's contentView and the 
    // bottom of the table view cell.
    height += 1.0;

    return height;
}

// NOTE: Set the table view's estimatedRowHeight property instead of 
// implementing the below method, UNLESS you have extreme variability in 
// your row heights and you notice the scroll indicator "jumping" 
// as you scroll.
- (CGFloat)tableView:(UITableView *)tableView estimatedHeightForRowAtIndexPath:(NSIndexPath *)indexPath
{
    // Do the minimal calculations required to be able to return an 
    // estimated row height that's within an order of magnitude of the 
    // actual height. For example:
    if ([self isTallCellAtIndexPath:indexPath]) {
        return 350.0;
    } else {
        return 40.0;
    }
}

Örnek Projeler

Bu projeler, UILabels'de dinamik içerik içeren tablo görünümü hücreleri nedeniyle değişken satır yüksekliğine sahip tablo görünümlerinin tam olarak çalışan örnekleridir.

Xamarin (C # /. NET)

Xamarin kullanıyorsanız, @KentBoogaart tarafından bir araya getirilen bu örnek projeye göz atın .


1
Bu iyi çalışırken, gerekli boyutları biraz tahmin ediyorum (muhtemelen çeşitli yuvarlama sorunları nedeniyle) ve tüm
metnimin

5
@ Alex311 Çok ilginç, bu örneği sağladığınız için teşekkürler. Sonunda küçük bir test yaptım ve burada bazı yorumlar yazdım: github.com/Alex311/TableCellWithAutoLayout/commit/…
smileyborg

3
Her hücre yeniden tanımlayıcı türü için hücrenin önbelleğe alınmasını şiddetle tavsiye ederim. Yükseklik için her aykırışınızda, geri eklenmeyen kuyruğun dışına bir hücre çıkarıyorsunuz. Önbellekleme, tablo hücreleriniz için başlatıcı çağrılma süresini önemli ölçüde azaltabilir. Bazı nedenlerden dolayı, önbelleğe almadığımda, kullanılan bellek miktarı kaydırma yaptığım için artmaya devam etti.
Alex311

1
Aslında görsel senaryo taslakları. Bunun prototip hücreler için çalıştığını düşünmüyorum (en azından tüm VC'yi yeniden somutlaştırmadan). heightForRowAtIndexPathHücrede ayıklayarak , hücreyi koruyarak ve bir dahaki sefere geri dönerek sızıntıyı tamamen önlemek mümkün olabilir cellForRowAtIndexPath.
nschum

2
Is iOS8uygulama hala tavsiye iOS9ve iOS10veya bu cevabı yayımlandı beri orada yeni yaklaşımlar nelerdir?
koen

175

Yukarıdaki iOS 8 için gerçekten basit:

override func viewDidLoad() {  
    super.viewDidLoad()

    self.tableView.estimatedRowHeight = 80
    self.tableView.rowHeight = UITableView.automaticDimension
}

veya

func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
    return UITableView.automaticDimension
}

Ancak iOS 7 için anahtar, otomatik düzenlemeden sonra yüksekliği hesaplamaktır:

func calculateHeightForConfiguredSizingCell(cell: GSTableViewCell) -> CGFloat {
    cell.setNeedsLayout()
    cell.layoutIfNeeded()
    let height = cell.contentView.systemLayoutSizeFittingSize(UILayoutFittingExpandedSize).height + 1.0
    return height
}

Önemli

  • Birden çok satır etiketleri ise set unutma yok numberOfLinesetmek 0.

  • Unutma label.preferredMaxLayoutWidth = CGRectGetWidth(tableView.bounds)

Örnek kodun tamamı burada .


7
OS8 davasında heightForRowAtIndexPath işlevini uygulamamıza gerek olmadığını düşünüyorum
jpulikkottil

@Eddwinpaz'ın başka bir yanıtta belirttiği gibi, satır yüksekliğinde kilitlemek için kullanılan kısıtlamaların kenar boşluğu içermemesi önemlidir.
Richard

1
+1 için "Birden fazla satır etiketi varsa, numberOfLines değerini 0 olarak ayarlamayı unutmayın", bu, hücrelerimin boyut olarak dinamik olmamasına neden oluyordu.
Ian-Fogelman

Bana bir kontrol manyağı deyin ama iOS 11 günlerinde bile UITableViewAutomaticDimension'ı kullanmayı sevmiyorum. Geçmişte bazı kötü deneyimler vardı. Bu nedenle, genellikle burada listelenen iOS7 çözümlerini kullanıyorum. William'ın notunu unutmadığım label.preferredMaxLayoutWidth beni kurtardı.
Brian Sachetta

Kaydırma yaptığımızda, etiket birden çok satırda görünmeye başlar ve satır yüksekliği de artmaz
Karanveer Singh

93

UITableViewCell değişken yüksekliğine hızlı örnek

Swift 3 için güncellendi

William Hu'nun Swift yanıtı iyi, ama ilk kez bir şeyler yapmayı öğrenirken basit ama ayrıntılı adımlar atmamda bana yardımcı oluyor. Aşağıdaki örnek UITableViewdeğişken hücre yükseklikleri ile öğrenmeyi test projemdir. Swift için bu temel UITableView örneğini temel aldım .

Tamamlanan proje şöyle görünmelidir:

resim açıklamasını buraya girin

Yeni bir proje oluştur

Sadece bir Tekli Görünüm Uygulaması olabilir.

Kodu ekleyin

Projenize yeni bir Swift dosyası ekleyin. MyCustomCell olarak adlandırın. Bu sınıf, film şeridinde hücrenize eklediğiniz görünümlerin çıkışlarını tutar. Bu temel örnekte her hücrede yalnızca bir etiket bulunur.

import UIKit
class MyCustomCell: UITableViewCell {
    @IBOutlet weak var myCellLabel: UILabel!
}

Bu prizi daha sonra bağlayacağız.

ViewController.swift dosyasını açın ve aşağıdaki içeriğe sahip olduğunuzdan emin olun:

import UIKit
class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {

    // These strings will be the data for the table view cells
    let animals: [String] = [
        "Ten horses:  horse horse horse horse horse horse horse horse horse horse ",
        "Three cows:  cow, cow, cow",
        "One camel:  camel",
        "Ninety-nine sheep:  sheep sheep sheep sheep sheep sheep sheep sheep sheep sheep sheep sheep sheep sheep sheep sheep sheep sheep sheep sheep sheep sheep sheep sheep sheep sheep sheep sheep sheep sheep sheep sheep sheep sheep sheep sheep sheep sheep sheep sheep sheep sheep sheep sheep sheep sheep sheep sheep sheep sheep sheep sheep sheep sheep sheep sheep sheep sheep sheep sheep sheep sheep sheep sheep sheep sheep sheep sheep sheep sheep sheep sheep sheep sheep sheep sheep sheep sheep sheep sheep sheep sheep sheep sheep sheep sheep baaaa sheep sheep sheep sheep sheep sheep sheep sheep sheep sheep sheep sheep sheep",
        "Thirty goats:  goat goat goat goat goat goat goat goat goat goat goat goat goat goat goat goat goat goat goat goat goat goat goat goat goat goat goat goat goat goat "]

    // Don't forget to enter this in IB also
    let cellReuseIdentifier = "cell"

    @IBOutlet var tableView: UITableView!

    override func viewDidLoad() {
        super.viewDidLoad()

        // delegate and data source
        tableView.delegate = self
        tableView.dataSource = self

        // Along with auto layout, these are the keys for enabling variable cell height
        tableView.estimatedRowHeight = 44.0
        tableView.rowHeight = UITableViewAutomaticDimension
    }

    // number of rows in table view
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return self.animals.count
    }

    // create a cell for each table view row
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {

        let cell:MyCustomCell = self.tableView.dequeueReusableCell(withIdentifier: cellReuseIdentifier) as! MyCustomCell
        cell.myCellLabel.text = self.animals[indexPath.row]
        return cell
    }

    // method to run when table view cell is tapped
    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        print("You tapped cell number \(indexPath.row).")
    }
}

Önemli Not:

  • Değişken hücre yüksekliğini mümkün kılan aşağıdaki iki kod satırıdır (otomatik düzen ile birlikte):

    tableView.estimatedRowHeight = 44.0
    tableView.rowHeight = UITableViewAutomaticDimension

Film şeridini ayarla

Görünüm denetleyicinize bir Tablo Görünümü ekleyin ve dört tarafa sabitlemek için otomatik düzeni kullanın. Sonra bir Tablo Görünümü Hücresini Tablo Görünümü üzerine sürükleyin. Prototip hücresine bir Etiket sürükleyin. Etiketi Tablo Görünümü Hücresinin içerik görünümünün dört kenarına sabitlemek için otomatik düzeni kullanın.

resim açıklamasını buraya girin

Önemli Not:

  • Otomatik düzen, yukarıda bahsettiğim iki önemli kod satırı ile birlikte çalışır. Otomatik düzeni kullanmazsanız çalışmaz.

Diğer IB ayarları

Özel sınıf adı ve Tanımlayıcı

Tablo Görünümü Hücresini seçin ve özel sınıfı MyCustomCell(eklediğimiz Swift dosyasındaki sınıfın adı) olarak ayarlayın. Ayrıca Tanımlayıcı'yı cell( cellReuseIdentifieryukarıdaki kodda için kullandığımız dize) olarak ayarlayın .

resim açıklamasını buraya girin

Etiket için Sıfır Satırlar

0Etiketinizdeki satır sayısını ayarlayın . Bu, çok satırlı anlamına gelir ve etiketin içeriğine göre kendisini yeniden boyutlandırmasına olanak tanır.

resim açıklamasını buraya girin

Çıkışları Takın

  • Film şeridindeki Tablo Görünümü'nden koddaki tableViewdeğişkene sürüklemeyi kontrol edin ViewController.
  • Sınıftaki myCellLabeldeğişken için Prototip hücrenizdeki Etiket için de aynısını yapın MyCustomCell.

bitmiş

Projenizi şimdi çalıştırabilmeli ve değişken yükseklikte hücreler alabilmelisiniz.

notlar

  • Bu örnek yalnızca iOS 8 ve sonrası için geçerlidir. Hala iOS 7'yi desteklemeniz gerekiyorsa, bu sizin için çalışmaz.
  • Gelecekteki projelerinizde kendi özel hücreleriniz muhtemelen tek bir etiketten daha fazlasına sahip olacaktır. Otomatik düzenin kullanılacak doğru yüksekliği belirleyebilmesi için her şeyin doğru sabitlendiğinden emin olun. Dikey sıkıştırma direnci ve sarılmayı da kullanmanız gerekebilir. Bununla ilgili daha fazla bilgi için bu makaleye bakın .
  • Ön ve arka (sol ve sağ) kenarları sabitlemiyorsanız, etiketi preferredMaxLayoutWidthsarmanın ne zaman sarılacağını bilecek şekilde ayarlamanız da gerekebilir . Örneğin, ön ve arka kenarları sabitlemek yerine yukarıdaki projedeki etikete bir Yatay Yatay kısıtlama eklediyseniz, bu satırı tableView:cellForRowAtIndexPathyönteme eklemeniz gerekir :

     cell.myCellLabel.preferredMaxLayoutWidth = tableView.bounds.width

Ayrıca bakınız


preferredMaxLayoutWidthHücreye karşı koymak gerçekten daha iyi değil contentSizemi? Bir aksesuarView'ınız varsa veya düzenleme için kaydırılmış olsaydı, yine de dikkate alınır mı?
Tatlım

@Honey, haklı olabilirsin. Yaklaşık bir yıldır iOS'ta kalmadım ve şu anda size iyi cevap vermek için çok paslıyım.
Suragch

65

@ Smileyborg'un iOS7 çözümünü bir kategoriye tamamladım

@Smileyborg tarafından bu akıllı çözümü bir UICollectionViewCell+AutoLayoutDynamicHeightCalculationkategoriye kaydırmaya karar verdim .

Kategori ayrıca @ wildmonkey yanıtında özetlenen sorunları da düzeltir (bir uçtan bir hücre yükleme ve systemLayoutSizeFittingSize:geri dönme CGRectZero)

Herhangi bir önbelleklemeyi hesaba katmaz, ancak şu anda ihtiyaçlarımı karşılar. Kopyalamak, yapıştırmak ve kesmek için çekinmeyin.

UICollectionViewCell + AutoLayoutDynamicHeightCalculation.h

#import <UIKit/UIKit.h>

typedef void (^UICollectionViewCellAutoLayoutRenderBlock)(void);

/**
 *  A category on UICollectionViewCell to aid calculating dynamic heights based on AutoLayout contraints.
 *
 *  Many thanks to @smileyborg and @wildmonkey
 *
 *  @see stackoverflow.com/questions/18746929/using-auto-layout-in-uitableview-for-dynamic-cell-layouts-variable-row-heights
 */
@interface UICollectionViewCell (AutoLayoutDynamicHeightCalculation)

/**
 *  Grab an instance of the receiving type to use in order to calculate AutoLayout contraint driven dynamic height. The method pulls the cell from a nib file and moves any Interface Builder defined contrainsts to the content view.
 *
 *  @param name Name of the nib file.
 *
 *  @return collection view cell for using to calculate content based height
 */
+ (instancetype)heightCalculationCellFromNibWithName:(NSString *)name;

/**
 *  Returns the height of the receiver after rendering with your model data and applying an AutoLayout pass
 *
 *  @param block Render the model data to your UI elements in this block
 *
 *  @return Calculated constraint derived height
 */
- (CGFloat)heightAfterAutoLayoutPassAndRenderingWithBlock:(UICollectionViewCellAutoLayoutRenderBlock)block collectionViewWidth:(CGFloat)width;

/**
 *  Directly calls `heightAfterAutoLayoutPassAndRenderingWithBlock:collectionViewWidth` assuming a collection view width spanning the [UIScreen mainScreen] bounds
 */
- (CGFloat)heightAfterAutoLayoutPassAndRenderingWithBlock:(UICollectionViewCellAutoLayoutRenderBlock)block;

@end

UICollectionViewCell + AutoLayoutDynamicHeightCalculation.m

#import "UICollectionViewCell+AutoLayout.h"

@implementation UICollectionViewCell (AutoLayout)

#pragma mark Dummy Cell Generator

+ (instancetype)heightCalculationCellFromNibWithName:(NSString *)name
{
    UICollectionViewCell *heightCalculationCell = [[[NSBundle mainBundle] loadNibNamed:name owner:self options:nil] lastObject];
    [heightCalculationCell moveInterfaceBuilderLayoutConstraintsToContentView];
    return heightCalculationCell;
}

#pragma mark Moving Constraints

- (void)moveInterfaceBuilderLayoutConstraintsToContentView
{
    [self.constraints enumerateObjectsUsingBlock:^(NSLayoutConstraint *constraint, NSUInteger idx, BOOL *stop) {
        [self removeConstraint:constraint];
        id firstItem = constraint.firstItem == self ? self.contentView : constraint.firstItem;
        id secondItem = constraint.secondItem == self ? self.contentView : constraint.secondItem;
        [self.contentView addConstraint:[NSLayoutConstraint constraintWithItem:firstItem
                                                                     attribute:constraint.firstAttribute
                                                                     relatedBy:constraint.relation
                                                                        toItem:secondItem
                                                                     attribute:constraint.secondAttribute
                                                                    multiplier:constraint.multiplier
                                                                      constant:constraint.constant]];
    }];
}

#pragma mark Height

- (CGFloat)heightAfterAutoLayoutPassAndRenderingWithBlock:(UICollectionViewCellAutoLayoutRenderBlock)block
{
    return [self heightAfterAutoLayoutPassAndRenderingWithBlock:block
                                            collectionViewWidth:CGRectGetWidth([[UIScreen mainScreen] bounds])];
}

- (CGFloat)heightAfterAutoLayoutPassAndRenderingWithBlock:(UICollectionViewCellAutoLayoutRenderBlock)block collectionViewWidth:(CGFloat)width
{
    NSParameterAssert(block);

    block();

    [self setNeedsUpdateConstraints];
    [self updateConstraintsIfNeeded];

    self.bounds = CGRectMake(0.0f, 0.0f, width, CGRectGetHeight(self.bounds));

    [self setNeedsLayout];
    [self layoutIfNeeded];

    CGSize calculatedSize = [self.contentView systemLayoutSizeFittingSize:UILayoutFittingCompressedSize];

    return calculatedSize.height;

}

@end

Kullanım örneği:

- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath
{
    MYSweetCell *cell = [MYSweetCell heightCalculationCellFromNibWithName:NSStringFromClass([MYSweetCell class])];
    CGFloat height = [cell heightAfterAutoLayoutPassAndRenderingWithBlock:^{
        [(id<MYSweetCellRenderProtocol>)cell renderWithModel:someModel];
    }];
    return CGSizeMake(CGRectGetWidth(self.collectionView.bounds), height);
}

Neyse ki bu cazı iOS8'de yapmak zorunda kalmayacağız, ama şimdilik var!


2
Sadece a: [YourCell new]kullanabilmeniz ve bunu kukla olarak kullanabilmeniz gerekir. Kısıtlama kodu oluşturma kodu örneğinizde tetiklendiği sürece ve programlı bir düzen geçişini tetiklediğiniz sürece, gitmek için iyi olmalısınız.
Adam Waite

1
Teşekkürler! Bu çalışıyor. Kategoriniz harika. Bu tekniğin de işe yaradığını fark etmemi sağlayan şey buydu UICollectionViews.
Ricardo Sanchez-Saez

2
Bir film şeridinde tanımlanan bir prototip hücre kullanarak bunu nasıl yapardınız?
David Potter

57

İşte benim çözümüm:

Sen anlatmak gerekiyor bu görünümü yüklemeden önce. Aksi takdirde beklendiği gibi davranamaz.TableViewestimatedHeight

Objective-C

- (void)viewWillAppear:(BOOL)animated {
    _messageField.delegate = self;
    _tableView.estimatedRowHeight = 65.0;
    _tableView.rowHeight = UITableViewAutomaticDimension;
}

Swift 4.2 Güncellemesi

override func viewWillAppear(_ animated: Bool) {
    tableView.rowHeight = UITableView.automaticDimension
    tableView.estimatedRowHeight = 65.0
}

2
Otomatik yerleşimi doğru bir şekilde ayarlamak, viewDidLoad'a eklenen bu kodla birlikte hile yaptı.
Bruce

1
Peki ya estimatedRowHeightsatır satır değişiyorsa? fazla ya da az tahmin etmeli miyim? Kullandığım yükseklik minimum veya maksimum tableViewmu?
János

1
@ János bu rowHeight'ın noktası. Bunu yapmak için beklendiği gibi davranır, sınırsız kenar boşlukları kullanmanız ve nesneleri TableViewCell ile hizalamanız gerekir. ve bir UITextView kullandığınızı varsayıyorum, bu yüzden hala autoscroll = false kaldırmanız gerekiyor, aksi takdirde yüksekliği koruyacak ve Nispi yükseklik beklendiği gibi davranmayacaktır.
Eddwin Paz

1
Bu en sağlam çözüm. Endişelenmeyin estimatedRowHeight, çoğunlukla kaydırma çubuğunun boyutunu etkiler, asla gerçek hücrelerin yüksekliğini etkilemez. Seçtiğiniz yükseklikte kalın olun: ekleme / silme animasyonunu etkiler.
SwiftArchitect

İşte hızlı 2.3 kod örnek kodu github.com/dpakthakur/DynamicCellHeight
Deepak Thakur

47

@Smileyborg tarafından önerilen çözüm neredeyse mükemmel. Özel bir hücreyi varsa ve bir tane istiyorum veya daha fazla ise UILabeldinamik yükseklikleri sonra systemLayoutSizeFittingSize AutoLayout ile kombine yöntem döndürür etkin bir CGSizeZeroburaya @TomSwift önerdiği gibi (onun contentView için hücreden tüm cep kısıtlamaları taşımadığınız sürece hiç Superview boyutlandırmak için nasıl tüm alt görünümleri autolayout ile sığdır? ).

Bunu yapmak için özel UITableViewCell uygulamanıza aşağıdaki kodu eklemeniz gerekir (@Adrian sayesinde).

- (void)awakeFromNib{
    [super awakeFromNib];
    for (NSLayoutConstraint *cellConstraint in self.constraints) {
        [self removeConstraint:cellConstraint];
        id firstItem = cellConstraint.firstItem == self ? self.contentView : cellConstraint.firstItem;
        id seccondItem = cellConstraint.secondItem == self ? self.contentView : cellConstraint.secondItem;
        NSLayoutConstraint *contentViewConstraint =
        [NSLayoutConstraint constraintWithItem:firstItem
                                 attribute:cellConstraint.firstAttribute
                                 relatedBy:cellConstraint.relation
                                    toItem:seccondItem
                                 attribute:cellConstraint.secondAttribute
                                multiplier:cellConstraint.multiplier
                                  constant:cellConstraint.constant];
        [self.contentView addConstraint:contentViewConstraint];
    }
}

@Smileyborg cevabı bununla karıştırılmalı.


systemLayoutSizeFittingSizehücre üzerinde değil, içerikte çağrılması gerekiyor
onmyway133 25:14

25

Yeterince önemli bir cevap aldım.

@ smileyborg'un cevabı çoğunlukla doğrudur. Ancak, layoutSubviewsörneğin, özel hücre sınıfınızın yönteminde herhangi bir kod varsa , örneğin preferredMaxLayoutWidth, bu kodla çalıştırılmaz:

[cell.contentView setNeedsLayout];
[cell.contentView layoutIfNeeded];

Bir süre beni şaşırttı. Sonra fark ettim, çünkü bunlar sadece yerleşimi tetikliyor contentView, hücrenin kendisi değil.

Çalışma kodum şöyle:

TCAnswerDetailAppSummaryCell *cell = [self.tableView dequeueReusableCellWithIdentifier:@"TCAnswerDetailAppSummaryCell"];
[cell configureWithThirdPartyObject:self.app];
[cell layoutIfNeeded];
CGFloat height = [cell.contentView systemLayoutSizeFittingSize:UILayoutFittingCompressedSize].height;
return height;

Yeni bir hücre oluşturuyorsanız, setNeedsLayoutönceden ayarlanması gerektiği için aramanıza gerek olmadığından eminim . Bir hücreye başvuruyu kaydettiğiniz durumlarda, büyük olasılıkla onu çağırmalısınız. Her iki şekilde de hiçbir şeye zarar vermemelidir.

Başka bir ipucu gibi şeyleri ayarladığınız hücre alt sınıfları kullanıyorsanız preferredMaxLayoutWidth. @Smileyborg'un belirttiği gibi, "tablo görüntüleme hücrenizin genişliği henüz tablo görünümünün genişliğine sabitlenmedi". Bu doğrudur ve işinizi görünüm denetleyicisinde değil alt sınıfınızda yapıyorsanız sorun olur. Ancak, tablo genişliğini kullanarak bu noktada hücre çerçevesini ayarlayabilirsiniz:

Örneğin yükseklik hesaplamasında:

self.summaryCell = [self.tableView dequeueReusableCellWithIdentifier:@"TCAnswerDetailDefaultSummaryCell"];
CGRect oldFrame = self.summaryCell.frame;
self.summaryCell.frame = CGRectMake(oldFrame.origin.x, oldFrame.origin.y, self.tableView.frame.size.width, oldFrame.size.height);

(Bu hücreyi yeniden kullanmak için önbelleğe aldım, ancak bu alakasız).



19

Hücrendeki düzeniniz iyi olduğu sürece.

-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
    UITableViewCell *cell = [self tableView:tableView cellForRowAtIndexPath:indexPath];

    return [cell.contentView systemLayoutSizeFittingSize:UILayoutFittingCompressedSize].height;
}

Güncelleme: iOS 8'de sunulan dinamik yeniden boyutlandırmayı kullanmalısınız.


-İOS7 benim için bu çalışıyor, aramaya artık sorun yok tableView:cellForRowAtIndexPath:içinde tableView:heightForRowAtIndexPath:şimdi?
Karıncalar

Tamam bu işe yaramaz, ama zaman systemLayoutSizeFittingSize:içinde arama tableView:cellForRowAtIndexPath:ve önbellek sonra o zaman ve sonra kullanmak tableView:heightForRowAtIndexPath:kısıtlamalar elbette ayarlandığı sürece iyi çalışır!
Karıncalar

Bu yalnızca dequeueReusableCellWithIdentifier: kullanıyorsanız çalışır, dequeueReusableCellWithIdentifier: forIndexPath:
Antoine

1
Gerçekten tableView: cellForRowAtIndexPath çağıran sanmıyorum: doğrudan iyi bir yoldur.
Itachi

19

(altta okunan Xcode 8.x / Xcode 9.x için)

Xcode 7.x'te karışıklığa neden olabilecek aşağıdaki sorunlara dikkat edin:

Interface Builder, otomatik boyutlandırma hücresi kurulumunu düzgün işlemiyor. Kısıtlamalarınız kesinlikle geçerli olsa bile, IB yine de şikayet edecek ve size kafa karıştırıcı öneriler ve hatalar verecektir. Bunun nedeni, IB'nin kısıtlamalarınız dikte ettiği sırada satırın yüksekliğini değiştirmek istememesi (hücrenin içeriğinize sığması için). Bunun yerine, satırın yüksekliğini sabit tutar ve yok saymanız gereken kısıtlamalarınızı değiştirmenizi önerir .

Örneğin, her şeyi iyi ayarladığınızı, hiçbir uyarının, hatanın olmadığını, tümünün çalıştığını düşünün.

resim açıklamasını buraya girin

Şimdi yazı tipi boyutunu değiştirirseniz (bu örnekte açıklama etiketi yazı tipi boyutunu 17.0'dan 18.0'a değiştiriyorum).

resim açıklamasını buraya girin

Yazı tipi boyutu arttığından, etiket şimdi 3 satır işgal etmek istiyor (bundan önce 2 satır işgal ediyordu).

Arabirim Oluşturucu beklendiği gibi çalışırsa, yeni etiket yüksekliğini karşılamak için hücrenin yüksekliğini yeniden boyutlandıracaktır. Ancak gerçekte IB'nin kırmızı otomatik düzen hata simgesini görüntülemesi ve sarılma / sıkıştırma önceliklerini değiştirmenizi önermesidir.

resim açıklamasını buraya girin

Bu uyarıları dikkate almamalısınız. Bunun yerine * yapabileceğiniz şey satırın yüksekliğini manuel olarak değiştirmektir (Hücre> Boyut Denetçisi> Satır Yüksekliği'ni seçin).

resim açıklamasını buraya girin

Kırmızı ok hataları ortadan kalkıncaya kadar bu yüksekliği bir seferde bir tıklama (yukarı / aşağı adımını kullanarak) değiştiriyordum! (aslında sarı uyarılar alırsınız, bu noktada devam edin ve 'çerçeveleri güncelleyin', hepsi işe yaramalıdır).

* Bu kırmızı hataları veya sarı uyarıları gerçekten de Arayüz Oluşturucu'da çözmek zorunda olmadığınızı unutmayın - çalışma zamanında, her şey düzgün çalışacaktır (IB hatalar / uyarılar gösterse bile). Sadece konsol günlüğünde çalışma zamanında herhangi bir AutoLayout hatası almadığınızdan emin olun.

Aslında, IB'de satır yüksekliğini her zaman güncellemeye çalışmak çok sinir bozucu ve bazen imkansız (kesirli değerler nedeniyle).

Can sıkıcı IB uyarılarını / hatalarını önlemek için, ilgili görünümleri seçebilir Size Inspectorve mülk AmbiguityiçinVerify Position Only

resim açıklamasını buraya girin


Xcode 8.x / Xcode 9.x (bazen) Xcode 7.x'ten farklı şeyler yapıyor gibi görünüyor, ancak yine de yanlış. Örneğin compression resistance priority/ hugging priorityöğesi gerekli (1000) olarak ayarlandığında bile , Arayüz Oluşturucu bir etiketi hücreye sığacak şekilde uzatabilir veya klipsleyebilir (hücre yüksekliğini etiketin çevresine sığacak şekilde yeniden boyutlandırmak yerine). Böyle bir durumda, herhangi bir AutoLayout uyarısı veya hatası bile göstermeyebilir. Veya bazen yukarıda açıklanan Xcode 7.x'in tam olarak yaptığı şeyi yapar.


merhaba dinamik hücre içeriği ile hücre tablo görünümü olan hücre için dinamik yükseklik vermek mümkün mü?
Jignesh B

18

Satır yüksekliği ve tahmini satır yüksekliği için otomatik boyut ayarlamak üzere, hücre / satır yüksekliği düzeni için otomatik boyutun etkili olmasını sağlamak üzere aşağıdaki adımları uygulayın.

  • Tablo görünümü verilerini atama ve uygulama Kaynak ve temsilci seçme
  • UITableViewAutomaticDimensionRowHeight ve TahminiRowHeight'a ata
  • Temsilci / dataSource yöntemlerini uygulama (yani buna heightForRowAtbir değer döndürme UITableViewAutomaticDimension)

-

Hedef C:

// in ViewController.h
#import <UIKit/UIKit.h>

@interface ViewController : UIViewController <UITableViewDelegate, UITableViewDataSource>

  @property IBOutlet UITableView * table;

@end

// in ViewController.m

- (void)viewDidLoad {
    [super viewDidLoad];
    self.table.dataSource = self;
    self.table.delegate = self;

    self.table.rowHeight = UITableViewAutomaticDimension;
    self.table.estimatedRowHeight = UITableViewAutomaticDimension;
}

-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {

    return UITableViewAutomaticDimension;
}

Swift:

@IBOutlet weak var table: UITableView!

override func viewDidLoad() {
    super.viewDidLoad()

    // Don't forget to set dataSource and delegate for table
    table.dataSource = self
    table.delegate = self

    // Set automatic dimensions for row height
    // Swift 4.2 onwards
    table.rowHeight = UITableView.automaticDimension
    table.estimatedRowHeight = UITableView.automaticDimension


    // Swift 4.1 and below
    table.rowHeight = UITableViewAutomaticDimension
    table.estimatedRowHeight = UITableViewAutomaticDimension

}



// UITableViewAutomaticDimension calculates height of label contents/text
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
    // Swift 4.2 onwards
    return UITableView.automaticDimension

    // Swift 4.1 and below
    return UITableViewAutomaticDimension
}

UITableviewCell'deki etiket örneği için

  • Satır sayısını ayarlayın = 0 (& satır sonu modu = kesik kuyruk)
  • Denetleme / hücre kabına göre tüm kısıtlamaları (üst, alt, sağ sol) ayarlayın.
  • İsteğe bağlı : Etiket olmasa bile etiketle kaplı minimum dikey alan istiyorsanız, etiket için minimum yüksekliği ayarlayın.

resim açıklamasını buraya girin

Not : İçerik boyutuna göre ayarlanması gereken birden fazla dinamik uzunluğa sahip etiketiniz (UIElements) varsa: Daha yüksek önceliğe sahip genişletmek / sıkıştırmak istediğiniz etiketler için 'İçerik Sarılma ve Sıkıştırma Direnci Önceliği'ni ayarlayın.


1
Teşekkür ederim net ve basit bir çözüm gibi görünüyor ama ben bir sorun var Ben etiketleri ama metin görünümleri kullanmıyorum bu yüzden veri ekledikçe artırmak için satır yüksekliğine ihtiyacım var. Benim sorunum daha sonra heightForRowAt bilgi iletmektir. Değişen metin görünümlerimin yüksekliğini ölçebilirim, ancak şimdi satır yüksekliğini değiştirmeniz gerekiyor. Biraz yardım lütfen takdir ediyorum
Jeremy Andrews

@JeremyAndrews Sure size yardımcı olacaktır. Sorunuzu, denediğiniz kaynak koduyla ve sorunla ilgili ayrıntılarla yükseltin.
Krunal

tableView: heightForRowVeri kaynağı uygulamadan benim için çalışıyor .
Hemang

@Hemang - iOS 11+ sürümünden bu yana olmadan çalışıyor tableView: heightForRow. (iOS 10- tableView: heightForRowiçin gereklidir)
Krunal

1
@Hemang - Çözüm kesin sorgu tanımına bağlıdır. Burada sorgunuz için genel ortak çözümüm var. İçine koşul koy tableView: heightForRow..if (indexPath.row == 0) { return 100} else { return UITableView.automaticDimension }
Krunal

16

Gibi Bob-Spryn @ ben cevap olarak bu ilanıyla olduğunu önemli yeterince Yakaladım karşılaştım.

Bir süre @ smileyborg'un cevabı ile mücadele ettim . Ek elemanları ile (IB senin prototip hücreyi tanımladığınız eğer ran ki yakaladım olduğunu UILabels, UIButtonssen [ile hücreyi örneğini zaman IB, vs.) [YourTableViewCellClass alloc] init]Eğer bırakmadığınız sürece o hücre içinde diğer bütün unsurları örneğini olmaz bunu yapmak için kod yazdı. (Benzer bir deneyim yaşadım initWithStyle.)

Film şeridinin tüm ek öğelerin hücre ile elde edilmesini sağlamak için [tableView dequeueReusableCellWithIdentifier:@"DoseNeeded"]( [tableView dequeueReusableCellWithIdentifier:forIndexPath:]Bu ilginç sorunlara neden olacağı için değil .) Bunu yaptığınızda, IB'de tanımladığınız tüm öğeler örneklenecektir.


15

Dinamik Tablo Görünümü Hücre Yüksekliği ve Otomatik Düzen

Film şeridi Otomatik Düzen ile sorunu çözmenin iyi bir yolu:

- (CGFloat)heightForImageCellAtIndexPath:(NSIndexPath *)indexPath {
  static RWImageCell *sizingCell = nil;
  static dispatch_once_t onceToken;
  dispatch_once(&onceToken, ^{
    sizingCell = [self.tableView dequeueReusableCellWithIdentifier:RWImageCellIdentifier];
  });

  [sizingCell setNeedsLayout];
  [sizingCell layoutIfNeeded];

  CGSize size = [sizingCell.contentView systemLayoutSizeFittingSize:UILayoutFittingCompressedSize];
  return size.height;
}

1
Bu, bu soruya kabul edilen cevapta zaten geniş ölçüde ele alınmıştır.
smileyborg

2
Evet, biliyorum ... ama PureLayout'u kullanmak istemedim ve dispatch_once 'hile' bana sadece Storyboard'u kullanarak çalışmamda çok yardımcı oldu.
Mohnasm

13
tableView.estimatedRowHeight = 343.0
tableView.rowHeight = UITableViewAutomaticDimension

resim açıklamasını buraya girin


13

Başka bir "çözüm": Tüm bu hayal kırıklığını atlayın ve bunun yerine UITableView ile aynı görünen ve aynı hissi veren bir sonuç elde etmek için bir UIScrollView kullanın.

Tam anlamıyla 20+ çok sinir bozucu saat koyduktan sonra, smileyborg'un önerdiği ve aylarca başarısız olduğu ve App Store sürümlerinin üç versiyonu gibi bir şey oluşturmaya çalıştıktan sonra, bu acı verici "çözüm" oldu.

Benim iddiam, gerçekten iOS 7 desteğine ihtiyacınız varsa (bizim için önemlidir) o zaman teknoloji çok kırılgandır ve saçınızı denemekten çekersiniz. Ve gelişmiş satır düzenleme özelliklerinden bazılarını kullanmadığınız ve / veya 1000'den fazla "satırı" desteklemeniz gerekmediği sürece UITableView genellikle aşırı doludur (uygulamamızda, gerçekçi olarak asla 20 satırdan fazla değildir).

Ek avantaj, kodun, UITableView ile birlikte gelen tüm delege bok ve ileri geri inanılmaz derecede basit olmasıdır. ViewOnLoad'da zarif görünen ve yönetilmesi kolay tek bir kod döngüsü.

İşte nasıl yapılacağına dair bazı ipuçları:

  1. Storyboard veya bir uç dosyası kullanarak, bir ViewController ve ilişkili kök görünümü oluşturun.

  2. Bir UIScrollView öğesini kök görünümünüze sürükleyin.

  3. Üst düzey görünüme üst, alt, sol ve sağ kısıtlamaları ekleyin, böylece UIScrollView tüm kök görünümünü doldurur.

  4. UIScrollView içine bir UIView ekleyin ve "kapsayıcı" olarak adlandırın. UIScrollView'a (üst öğesi) üst, alt, sol ve sağ kısıtlamaları ekleyin. KEY TRICK: Ayrıca UIScrollView ve UIView'i bağlamak için "Eşit genişlikler" kısıtlamaları ekleyin.

    NOT: "Kaydırma görünümünde belirsiz kaydırılabilir içerik yüksekliği var" ve kapsayıcı UIView'inizin 0 piksel yüksekliğinde olması gerekir. Her iki hata da uygulama çalışırken önemli değildir.

  5. "Hücrelerinizin" her biri için uç dosyaları ve denetleyiciler oluşturun. UITableViewCell değil UIView kullanın.

  6. Kök ViewController'ınızda, temelde tüm "satırları" kap UIView'e ekler ve programlı olarak sol ve sağ kenarlarını kap görünümüne, üst kenarlarını kap görünümü üst kısmına (ilk öğe için) veya öncekine bağlayan kısıtlamalar eklersiniz hücre. Daha sonra son hücreyi kabın tabanına bağlayın.

Bizim için her "satır" bir uç dosyasındadır. Yani kod şuna benzer:

class YourRootViewController {

    @IBOutlet var container: UIView! //container mentioned in step 4

    override func viewDidLoad() {

        super.viewDidLoad()

        var lastView: UIView?
        for data in yourDataSource {

            var cell = YourCellController(nibName: "YourCellNibName", bundle: nil)
            UITools.addViewToTop(container, child: cell.view, sibling: lastView)
            lastView = cell.view
            //Insert code here to populate your cell
        }

        if(lastView != nil) {
            container.addConstraint(NSLayoutConstraint(
                item: lastView!,
                attribute: NSLayoutAttribute.Bottom,
                relatedBy: NSLayoutRelation.Equal,
                toItem: container,
                attribute: NSLayoutAttribute.Bottom,
                multiplier: 1,
                constant: 0))
        }

        ///Add a refresh control, if you want - it seems to work fine in our app:
        var refreshControl = UIRefreshControl()
        container.addSubview(refreshControl!)
    }
}

Ve işte UITools.addViewToTop kodu:

class UITools {
    ///Add child to container, full width of the container and directly under sibling (or container if sibling nil):
    class func addViewToTop(container: UIView, child: UIView, sibling: UIView? = nil)
    {
        child.setTranslatesAutoresizingMaskIntoConstraints(false)
        container.addSubview(child)

        //Set left and right constraints so fills full horz width:

        container.addConstraint(NSLayoutConstraint(
            item: child,
            attribute: NSLayoutAttribute.Leading,
            relatedBy: NSLayoutRelation.Equal,
            toItem: container,
            attribute: NSLayoutAttribute.Left,
            multiplier: 1,
            constant: 0))

        container.addConstraint(NSLayoutConstraint(
            item: child,
            attribute: NSLayoutAttribute.Trailing,
            relatedBy: NSLayoutRelation.Equal,
            toItem: container,
            attribute: NSLayoutAttribute.Right,
            multiplier: 1,
            constant: 0))

        //Set vertical position from last item (or for first, from the superview):
        container.addConstraint(NSLayoutConstraint(
            item: child,
            attribute: NSLayoutAttribute.Top,
            relatedBy: NSLayoutRelation.Equal,
            toItem: sibling == nil ? container : sibling,
            attribute: sibling == nil ? NSLayoutAttribute.Top : NSLayoutAttribute.Bottom,
            multiplier: 1,
            constant: 0))
    }
}

Şimdiye kadar bu yaklaşımla bulduğum tek "gotcha" UITableView, kaydırma sırasında görünümün üst kısmında "kayan" bölüm üstbilgileri güzel bir özelliği olmasıdır. Yukarıdaki çözüm, daha fazla programlama eklemediğiniz sürece bunu yapmaz, ancak özel durumumuz için bu özellik% 100 gerekli değildi ve kimse ne zaman kaybolduğunu fark etmedi.

Hücreleriniz arasında bölücüler istiyorsanız, özel "hücrenizin" altına bir bölücü gibi görünen 1 piksel yüksekliğinde bir UIView ekleyin.

Yenileme denetiminin çalışması için "sekmeleri" ve "dikey olarak sekmeyi" açtığınızdan emin olun, böylece daha çok bir tablo görünümü gibi görünür.

TableView, bu çözümün olmadığı gibi tam ekranı doldurmuyorsa, içeriğinizin altında bazı boş satırları ve bölücüler gösterir. Ama kişisel olarak, bu boş satırlar zaten orada olmasaydı tercih ederim - değişken hücre yüksekliği ile orada her zaman boş satırlar olması için bana her zaman "buggy" görünüyordu.

İşte başka bir programcı kendi app Tablo Görünümü ile anlamaya çalışırken 20 + saat israf ÖNCE yazımı okuyor umuyoruz. :)


11

Dinamik görünümler (kurulum görünümleri ve kısıtlamaları koduna göre) kullanmak zorunda kaldım ve tercih edilenMaxLayoutWidth etiketinin genişliğini 0 olarak ayarlamak istediğimde yanlış hücre yüksekliğim var.

Sonra ekledim

[cell layoutSubviews];

çalıştırmadan önce

[cell setNeedsUpdateConstraints];
[cell updateConstraintsIfNeeded];

Bu etiketin genişliği beklendiği gibi oldu ve dinamik yükseklik sağ hesaplıyordu.


9

Diyelim ki alt görüntülemeye sahip bir hücreniz var ve hücrenin yüksekliğinin alt görünüm + dolgusunu kapsayacak kadar yüksek olmasını istiyorsunuz.

1) Alt görünümün alt sınırını cell.contentView eklentisini istediğiniz dolguya eşit olarak ayarlayın. Hücre veya hücre üzerinde kısıtlamalar ayarlamayın.

2) tableView rowHeightözelliğini veya tableView:heightForRowAtIndexPath:olarak ayarlayın UITableViewAutomaticDimension.

3) tableView'un estimatedRowHeightözelliğini veya tableView:estimatedHeightForRowAtIndexPath:yüksekliğin en iyi tahminini ayarlayın .

Bu kadar.


7

Programlı olarak düzenlerseniz, Swift'te çapa kullanarak iOS 10 için nelere dikkat etmeniz gerekir.

Üç kural / adım vardır

SAYI 1: viewDidLoad'da bu iki tablo görünümü özelliğini ayarlayın, birincisi hücrelerinde dinamik boyutlar beklemesi gereken tablo görünümüne anlatıyor, ikincisi sadece uygulamanın kaydırma çubuğu göstergesinin boyutunu hesaplamasına izin vermek, verim.

    tableView.rowHeight = UITableViewAutomaticDimension
    tableView.estimatedRowHeight = 100

2 NUMARASI: Bu, alt görünümleri görünüme değil hücrenin contentView öğesine eklemeniz ve alt görünümleri üste ve alta tutturmak için düzen düzeni marginguide'sini kullanmanız önemlidir, bu nasıl yapılacağına dair çalışan bir örnektir.

override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
    super.init(style: style, reuseIdentifier: reuseIdentifier)
    setUpViews()
}

private func setUpViews() {

    contentView.addSubview(movieImageView)
    contentView.addSubview(descriptionLabel)
    let marginGuide = contentView.layoutMarginsGuide

    NSLayoutConstraint.activate([
        movieImageView.heightAnchor.constraint(equalToConstant: 80),
        movieImageView.widthAnchor.constraint(equalToConstant: 80),
        movieImageView.leftAnchor.constraint(equalTo: marginGuide.leftAnchor),
        movieImageView.topAnchor.constraint(equalTo: marginGuide.topAnchor, constant: 20),

        descriptionLabel.leftAnchor.constraint(equalTo: movieImageView.rightAnchor, constant: 15),
        descriptionLabel.rightAnchor.constraint(equalTo: marginGuide.rightAnchor),
        descriptionLabel.bottomAnchor.constraint(equalTo: marginGuide.bottomAnchor, constant: -15),
        descriptionLabel.topAnchor.constraint(equalTo: movieImageView.topAnchor)

        ])
}

Alt görünümleri ekleyecek ve düzeni gerçekleştirecek bir yöntem oluşturun, init yönteminde çağırın.

3 NUMARA: YÖNTEMİ ARAMAYIN:

  override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
    }

Bunu yaparsanız uygulamanızı geçersiz kılacaksınız.

Tablo görünümlerinde dinamik hücreler için bu 3 kuralı izleyin.

İşte çalışan bir uygulama https://github.com/jamesrochabrun/MinimalViewController


Swift 5'te UITableViewAutomaticDimension, UITableView.automaticDimension olarak yeniden adlandırıldı
James Rochabrun

4

Eğer bir varsa uzun dize. satır sonu olmayan bir örnek . O zaman bazı sorunlarla karşılaşabilirsiniz.

"İddia edilen" düzeltme kabul edilen cevap ve diğer birkaç cevapla belirtilir. Sadece eklemelisin

cell.myCellLabel.preferredMaxLayoutWidth = tableView.bounds.width

Suragh'ın cevabını en eksiksiz ve özlü buluyorum , bu yüzden kafa karıştırıcı değil.

Yine de bu değişikliklerin neden gerekli olduğunu açıklamayın . Hadi bunu yapalım.

Aşağıdaki kodu bir projeye bırakın.

import UIKit

class ViewController: UIViewController {

    lazy var label : UILabel = {
        let lbl = UILabel()
        lbl.translatesAutoresizingMaskIntoConstraints = false
        lbl.backgroundColor = .red
        lbl.textColor = .black
        return lbl
    }()

    override func viewDidLoad() {
        super.viewDidLoad()
        // step0: (0.0, 0.0)
        print("empty Text intrinsicContentSize: \(label.intrinsicContentSize)")
        // ----------
        // step1: (29.0, 20.5)
        label.text = "hiiiii"
        print("hiiiii intrinsicContentSize: \(label.intrinsicContentSize)")
        // ----------
        // step2: (328.0, 20.5)
        label.text = "translatesAutoresizingMaskIntoConstraints"
        print("1 translate intrinsicContentSize: \(label.intrinsicContentSize)")
        // ----------
        // step3: (992.0, 20.5)
        label.text = "translatesAutoresizingMaskIntoConstraints translatesAutoresizingMaskIntoConstraints translatesAutoresizingMaskIntoConstraints"
        print("3 translate intrinsicContentSize: \(label.intrinsicContentSize)")
        // ----------
        // step4: (328.0, 20.5)
        label.text = "translatesAutoresizingMaskIntoConstraints\ntranslatesAutoresizingMaskIntoConstraints\ntranslatesAutoresizingMaskIntoConstraints"
        print("3 translate w/ line breaks (but the line breaks get ignored, because numberOfLines is defaulted to `1` and it will force it all to fit into one line! intrinsicContentSize: \(label.intrinsicContentSize)")
        // ----------
        // step5: (328.0, 61.0)
        label.numberOfLines = 0
        print("3 translate w/ line breaks and '0' numberOfLines intrinsicContentSize: \(label.intrinsicContentSize)")
        // ----------
        // step6: (98.5, 243.5)
        label.preferredMaxLayoutWidth = 100
        print("3 translate w/ line breaks | '0' numberOfLines | preferredMaxLayoutWidth: 100 intrinsicContentSize: \(label.intrinsicContentSize)")

        setupLayout()
    }
    func setupLayout(){
        view.addSubview(label)
        label.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
        label.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true
    }
}

Herhangi bir boyut kısıtlaması eklemediğimi unutmayın . Yalnızca centerX, centerY kısıtlamaları ekledim. Ancak yine de etiket doğru şekilde boyutlandırılacak Neden?

Nedeniyle contentSize.

Bunu daha iyi işlemek için, önce adım0'ı koruyun, ardından 1-6 arasındaki adımları not edin. Kalsın setupLayout(). Davranışı gözlemleyin.

Sonra 1. adımı kaldırın ve gözlemleyin.

Sonra 2. adımı kaldırın ve gözlemleyin.

6 adımı da kaldırıncaya ve davranışlarını gözlemleyene kadar bunu yapın.

Tüm bunlardan ne sonuç çıkarabilir? Hangi faktörler değişebilir contenSize?

  1. Metin Uzunluğu: Daha uzun bir metniniz varsa intrinsicContentSize öğenizin genişliği artar
  2. Satır kesmeleri: Eğer eklerseniz \nintrinsicContentSize öğesinin genişliği tüm satırların maksimum genişliğini oluşturur. Bir satırda 25 karakter, diğerinde 2 karakter ve diğerinde 21 karakter varsa, genişliğiniz 25 karaktere göre hesaplanır
  3. İzin verilen satır sayısı: seçeneğini ayarlamanız gerekir numberOfLines, 0aksi takdirde birden fazla satırınız olmaz. Sizin numberOfLinesiçin intrinsicContentSize en ayarlayacaktır yükseklik
  4. Ayarlamalar yapma: Metninize dayanarak, intrinsicContentSize öğenizin genişliğinin 200ve yüksekliğinin olduğunu 100, ancak genişliği etiketin kapsayıcısıyla sınırlamak istediğinizi düşünün, ne yapacaksınız? Çözüm, onu istenen genişliğe ayarlamaktır. Sen ayarlayarak bunu preferredMaxLayoutWidthiçin 130sonra yeni intrinsicContentSize kabaca bir genişliğe sahip olacaktır 130. Yükseklik, daha 100fazla çizgiye ihtiyacınız olacağından daha fazla olacaktır . Kısıtlamalarınız doğru bir şekilde ayarlanmışsa, bunu kullanmanıza gerek yoktur! Bununla ilgili daha fazla bilgi için bu cevaba ve yorumlarına bakınız. Yalnızca preferredMaxLayoutWidthgenişliği / yüksekliği sınırlayan kısıtlamalarınız yoksa "metni metni aşmadığı sürece metni kaydırmayın"preferredMaxLayoutWidth". Fakat% 100 kesinlikle sondaki ve / lider ayarlarsanız numberOfLinesiçin 0o zaman! Olman iyi kullanmaya tavsiye burada Uzun lafın kısası en cevapları YANLIŞ var! Sen buna ihtiyacı yoktur. Bunun bir işaret olduğunu ihtiyacı senin kısıtlamalar doğru ayarlanmadı ya da sadece kısıtlamaların olmadığı

  5. Yazı Tipi Boyutu: FontSize değerinizi artırırsanız intrinsicContentSize'ın yüksekliğinin artacağını unutmayın. Bunu kodumda göstermedim. Bunu kendi başınıza deneyebilirsiniz.

TablonuzunViewCell örneğine geri dönelim:

Tek yapmanız gereken:

  • set numberOfLinesTo0
  • etiketi kenar boşluklarıyla / kenarlarıyla doğru şekilde sınırlayın
  • Ayarlamaya gerek yoktur preferredMaxLayoutWidth.

1

Benim durumumda, sunucudan gelen ve herhangi bir genişlik ve yükseklikte olabilen bir görüntü ile özel bir hücre oluşturmak zorundayım. Ve dinamik boyutlu iki UILabel (hem genişlik hem de yükseklik)

Ben burada aynı Autolayout ile cevap ve programlı elde:

Temelde yukarıdaki @smileyBorg yanıtı yardımcı oldu ama systemLayoutSizeFittingSize benim için hiç işe yaramadı, Benim yaklaşımımda:

1. Otomatik satır yüksekliği hesaplama özelliği kullanılmaz. 2. tahmini yükseklik kullanımı yok 3. gereksiz güncelleme gerek yok. Otomatik Tercih Edilen Maksimum Yerleşim Genişliği kullanılmaz. 5. systemLayoutSizeFittingSize (kullanımı olmalı ama benim için çalışmıyor, i dahili olarak ne yaptığını bilmiyorum), ama benim yöntem - (float) getViewHeight çalışma ve dahili olarak ne yaptığını biliyorum.

Hücreyi görüntülemek için birkaç farklı yol kullandığımda UITableView Hücresinde farklı yüksekliklere sahip olmak mümkün mü?


1

Benim durumumda, dolgu, storyboard'un minimum 1 olarak değiştirmeme izin verdiği sectionHeader ve sectionFooter yükseklikleri yüzünden oldu. Yani viewDidLoad yönteminde:

tableView.sectionHeaderHeight = 0
tableView.sectionFooterHeight = 0

1

Ben sadece bazı aptal denemek ve hata 2 değerleri ile yaptım rowHeightve estimatedRowHeightve sadece bazı hata ayıklama içgörü sağlayabilir düşündüm:

Her ikisini de ayarlarsanız VEYA yalnızca istediğiniz ayarı estimatedRowHeightyaparsınız:

tableView.rowHeight = UITableViewAutomaticDimension
tableView.estimatedRowHeight = 1.00001 // MUST be greater than 1

Doğru tahmini almak için elinizden geleni yapmanız önerilir, ancak sonuç farklı değildir. Sadece performansınızı etkiler.

resim açıklamasını buraya girin


Yalnızca rowHeight değerini ayarlarsanız, yani yalnızca şunu yapın:

tableView.rowHeight = UITableViewAutomaticDimension

nihai sonucunuz istediğiniz gibi olmaz:

resim açıklamasını buraya girin


estimatedRowHeight1 veya daha küçük olarak ayarlarsanız, ne olursa olsun kilitleneceksinizrowHeight .

tableView.rowHeight = UITableViewAutomaticDimension
tableView.estimatedRowHeight = 1 

Aşağıdaki hata iletisiyle kilitlendim:

Terminating app due to uncaught exception
'NSInternalInconsistencyException', reason: 'table view row height
must not be negative - provided height for index path (<NSIndexPath:
0xc000000000000016> {length = 2, path = 0 - 0}) is -1.000000'
    ...some other lines...

libc++abi.dylib: terminating with uncaught exception of type
NSException

1

@Smileyborg tarafından kabul edilen cevap ile ilgili olarak,

[cell.contentView systemLayoutSizeFittingSize:UILayoutFittingCompressedSize]

kısıtlamaların belirsiz olduğu bazı durumlarda güvenilmez olmak. Aşağıdaki UIView'daki yardımcı kategoriyi kullanarak düzen motorunu yüksekliği bir yönde hesaplamaya zorlamak daha iyidir:

-(CGFloat)systemLayoutHeightForWidth:(CGFloat)w{
    [self setNeedsLayout];
    [self layoutIfNeeded];
    CGSize size = [self systemLayoutSizeFittingSize:CGSizeMake(w, 1) withHorizontalFittingPriority:UILayoutPriorityRequired verticalFittingPriority:UILayoutPriorityFittingSizeLevel];
    CGFloat h = size.height;
    return h;
}

Burada w: tablo görünümünün genişliği


0

Bu iki işlevi görünüm kontrolörünüze ekleyin, sorununuzu çözecektir. Burada liste, her satırdan oluşan dizenizi içeren bir dize dizisidir.

 func tableView(_ tableView: UITableView, 
   estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {
        tableView.rowHeight = self.calculateHeight(inString: list[indexPath.row])

    return (tableView.rowHeight) 
}

func calculateHeight(inString:String) -> CGFloat
{
    let messageString = input.text
    let attributes : [NSAttributedStringKey : Any] = [NSAttributedStringKey(rawValue: NSAttributedStringKey.font.rawValue) : UIFont.systemFont(ofSize: 15.0)]

    let attributedString : NSAttributedString = NSAttributedString(string: messageString!, attributes: attributes)

    let rect : CGRect = attributedString.boundingRect(with: CGSize(width: 222.0, height: CGFloat.greatestFiniteMagnitude), options: .usesLineFragmentOrigin, context: nil)

    let requredSize:CGRect = rect
    return requredSize.height
}

-1
swift 4

    @IBOutlet weak var tableViewHeightConstraint: NSLayoutConstraint!
    @IBOutlet weak var tableView: UITableView!
    private var context = 1
 override func viewDidLoad() {
        super.viewDidLoad()

        self.tableView.addObserver(self, forKeyPath: "contentSize", options: [.new,.prior], context: &context)
    }
  // Added observer to adjust tableview height based on the content

    override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
        if context == &self.context{
            if let size = change?[NSKeyValueChangeKey.newKey] as? CGSize{
                print("-----")
                print(size.height)
                tableViewHeightConstraint.constant = size.height + 50
            }
        }
    }

//Remove observer
 deinit {

        NotificationCenter.default.removeObserver(self)

    }

-1

Hücre yüksekliği içeriğe göre dinamikse, tam olarak saymalı ve ardından hücre oluşturulmadan önce yükseklik değerini döndürmelisiniz. Kolay bir yol, denetleyicinin tablo hücre yüksekliği delege yönteminde çağırması için tablo görünümü hücre kodunda sayma yöntemini tanımlamaktır. Yükseklik tablonun veya ekranın genişliğine bağlıysa , gerçek hücre çerçeve genişliğini (varsayılan 320) saymayı unutmayın . Yani, tablo hücre yüksekliği delege yönteminde, önce hücre genişliğini düzeltmek için cell.frame öğesini kullanın, ardından uygun değeri almak ve döndürmek için hücrede tanımlanan sayma yüksekliği yöntemini çağırın .

PS. Hücre nesnesi oluşturma kodu, farklı tablo görünümü hücre delege yönteminin çağırması için başka bir yöntemde tanımlanabilir.


-3

UITableView.automaticDimension Arayüz Oluşturucu ile ayarlanabilir:

Xcode> Film şeridi> Boyut Denetimi

Tablo Görünümü Hücresi> Satır Yüksekliği> Otomatik

Boyut Müfettişi


-4

Swift'te bir başka iOs7 + iOs8 çözümü

var cell2height:CGFloat=44

override func viewDidLoad() {
    super.viewDidLoad()
    theTable.rowHeight = UITableViewAutomaticDimension
    theTable.estimatedRowHeight = 44.0;
}

func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
    let cell =  tableView.dequeueReusableCellWithIdentifier("myTableViewCell", forIndexPath: indexPath) as! myTableViewCell
    cell2height=cell.contentView.height
    return cell
}

func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
    if #available(iOS 8.0, *) {
        return UITableViewAutomaticDimension
    } else {
        return cell2height
    }
}

not: systemLayoutSizeFittingSize benim durumumda çalışmıyor
djdance

hücre yüksekliği doğru değil cellForRowAtIndexPath, hücre henüz bu noktada yerleştirilmemiş.
Andrii Chernenko

iOs7'de sabit değerdir, yani çalışır. İsterseniz dışarıdaki cellForRowAtIndexPath'de ayarlayabilirsiniz
djdance
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.