Film şeridindeki Özel Hücre Satırı Yüksekliği ayarı yanıt vermiyor


213

Tablo görünümünde hücrelerden biri için hücre yüksekliğini ayarlamaya çalışıyorum. Boyutu, söz konusu hücrenin "boyut denetçisi" içindeki "satır yüksekliği" ayarından ayarlıyorum. Uygulamayı iPhone'umda çalıştırdığımda, hücrenin varsayılan boyutu tablo görünümünde "satır boyutu" ndan ayarlanmış.

Tablo görünümünün "satır boyutunu" değiştirirsem, tüm hücrelerin boyutu değişir. Sadece bir hücre için özel bir boyut istediğim için bunu yapmak istemiyorum. Soruna programatik bir çözümü olan birçok yazı gördüm, ancak mümkünse film şeridi ile yapmayı tercih ederim.

Yanıtlar:


295

Açık dinamik hücreler, rowHeightUITableView kümesi her zaman bireysel hücrelerin rowHeight geçersiz kılar.

Ancak statik hücrelerde, rowHeighttek tek hücrelere ayarlanmış UITableView'ları geçersiz kılabilir.

Bunun bir hata olup olmadığından emin değilim, Apple bunu bilerek yapıyor olabilir mi?


36
Doğru cevap # 3 ve özellikle bu cevap Arayüz Oluşturucu / Görsel Anlatım için geçerli olduğundan. Seçerseniz hücreyi IB, ardından Boyutu Müfettiş (bir "özel" onay kutusuyla) üstündeki gösterileri Satır Yüksekliği, ancak bütün seçerseniz görüntülemek tablo Boyut Müfettiş orada da üst (hayır "özel fuarlarında Satır Yüksekliği " bu durumda). Pixelfreak'in dediği gibi, dinamik hücreler için yalnızca tablo görünümü ayarı kullanılır. (Kasıtlı olup olmadığından emin değilim)
Rhubarb

8
Bu cevap, çözümün sadece UITableViewiçeriği değiştirmek yerine Dynamic Prototypesyapacağını Static Cells, bunu yaptım ve tüm projem patladığını ima ediyor ... neredeyse kendimi öldürüyordum.
abbood

4
Bu numarayı almanın bir yolu var mı? Derinlere inmenin tek yolu, film şeridine dalmak ve oradan dışarı çekmek mi?
Biclops

Tablonuz Dinamik olduğu için kesinlikle bir hata DEĞİLDİR, bu yüzden sistem nereye gittiğini bu hücrelerin her birini nasıl bilebilir? Ve her bir prototipin kaç kez kullanılacağı.
Vincent Bernier

Başlangıçta bir tablo görünümünü "statik hücreler" olarak ayarlayıp "dinamik prototipler" olarak değiştirirseniz de bir sorun var gibi görünüyor . RowHeight delege yönteminin bile yoksayıldığı bir sorun yaşadım. İlk önce doğrudan storyboard XML'sini düzenleyerek çözdüm, sonra nihayetinde başlangıçtan itibaren dinamik prototipler kullanarak storyboard sahnesini sıfırdan yeniden oluşturdum.
Eric Goldberg

84

UITableViewController kullanıyorsanız, bu yöntemi uygulayın:

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

Bir satırın işlevinde Yükseklik'i seçebilirsiniz. Örneğin,

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
    if (indexPath.row == 0) {
       return 100;
    } 
    else {
       return 60;
    }
}

Bu örnekte, ilk satır yüksekliği 100 piksel, diğerleri 60 pikseldir.

Umarım bu size yardımcı olabilir.


2
Beber, HER ZAMAN ikisinin de yapması gerekiyor mu (Özel'i işaretleyin ve film şeridindeki Satır Yüksekliği değerini düzenleyin ve & # heightForRowAtIndexPath'de belirtin)?
marciokoko

Bu konuda bana yardım eder misin? Dinamik yükseklikte dinamik hücrelere sahip olmalıyım, ancak bu yöntemi kullanırsam, tüm hücreleri ne şekilde döndürürsem değiştiririm. İPhone 5 dışında cihaz beklendiği gibi çalışıyor. Nedenini anlayabiliyor musun?
Ostmeistro

34

Dinamik hücreler rowHeightiçin UITableViewher zaman ayrı ayrı ayarlanan hücreleri geçersiz kılar ' rowHeight.

Bu davranış, IMO, bir hata. Kullanıcı arayüzünüzü her zaman hataya açık iki yerde yönetmeniz gerekir. Örneğin, film şeridindeki hücre boyutunuzu değiştirirseniz, bunları da değiştirmeyi hatırlamanız gerekir heightForRowAtIndexPath:. Apple hatayı düzeltene kadar, mevcut en iyi çözüm geçersiz kılmaktır heightForRowAtIndexPath:, ancak sihirli sayıları kullanmak yerine yüksekliği belirlemek için film şeridindeki gerçek prototip hücrelerini kullanın . İşte bir örnek:

- (CGFloat)tableView:(UITableView *)tableView 
           heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
    /* In this example, there is a different cell for
       the top, middle and bottom rows of the tableView.
       Each type of cell has a different height.
       self.model contains the data for the tableview 
    */
    static NSString *CellIdentifier;
    if (indexPath.row == 0) 
        CellIdentifier = @"CellTop";
    else if (indexPath.row + 1 == [self.model count] )
        CellIdentifier = @"CellBottom";
    else
        CellIdentifier = @"CellMiddle";

    UITableViewCell *cell = 
              [self.tableView dequeueReusableCellWithIdentifier:CellIdentifier];

    return cell.bounds.size.height;
}

Bu, prototip hücre yüksekliklerinizdeki değişikliklerin çalışma zamanında otomatik olarak alınmasını sağlar ve kullanıcı arayüzünüzü tek bir yerde yönetmeniz gerekir: film şeridi.


2
Önbellek dahil tam kod ile bir cevap gönderdim; bkz. stackoverflow.com/a/16881312/292166
JosephH

1
Vay vay vay! Cevabı iptal ettim, ama FARKLI OLUN! Bu yöntem, yorumlarda @Brennan'ın söylediği gibi sadece performans cezasına neden olmaz, aynı zamanda her reloadData'da artan bellek ayırmaya neden olur Bellek sızıntısı gibi bir şey! Lensovet'in yukarıdaki geçici çözümü kullanmanız gerekiyor! Bu bellek sızıntısını yakalamak için bir gün geçirin!
skywinder

Swift'te çalışmaz, çünkü cell.bounds.size.height her zaman 0.0 döndürür
King-Wizard

1
Hücreler henüz sistemin tableView: heightForRowAtIndexPath yöntemini çağırdığı sırada mevcut değildir. Veri modelinize dizine eklemek ve orada ne tür bir hücre kullanılacağını görmek ve sonra bu hücrenin yüksekliğini hesaplamak ve döndürmek için size iletilen indexPath'i kullanabilmeniz gerekir. Bu, sistemin hücreleri oluşturmadan önce tablodaki hücreleri düzenlemesini sağlar.
Kral Sihirbazı

1
Ayrıca, kendi cellForRowAtIndexPath yönteminizi çağırmamalısınız. Tablo görünümleri, o anda ekranda görünür durumdaysa bu dizin yolu için bir hücre döndürecek bir cellForRowAtIndexPath yöntemine sahiptir, ancak genellikle bu dizin yolunun kendisiyle ilişkilendirilmiş bir hücresi yoktur.
King-Wizard

22

Ben bu prototip hücreleri kullanan hikaye tahtaları için çalışır böylece kod çeşitli cevaplar / yorum ipucu inşa ettik.

Bu kod:

  • Hücre yüksekliğinin film şeridindeki belirgin yerden başka bir yere ayarlanmasını gerektirmez
  • Performans nedenleriyle yüksekliği önbelleğe alır
  • Çoğaltılmış mantığı önlemek için bir dizin yolunun hücre tanımlayıcısını almak için ortak bir işlev kullanır

Answerbot, Brennan ve lensovet'e teşekkürler.

- (NSString *)cellIdentifierForIndexPath:(NSIndexPath *)indexPath
{
    NSString *cellIdentifier = nil;

    switch (indexPath.section)
    {
        case 0:
            cellIdentifier = @"ArtworkCell";
            break;
         <... and so on ...>
    }

    return cellIdentifier;
}

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
    NSString *cellIdentifier = [self cellIdentifierForIndexPath:indexPath];
    static NSMutableDictionary *heightCache;
    if (!heightCache)
        heightCache = [[NSMutableDictionary alloc] init];
    NSNumber *cachedHeight = heightCache[cellIdentifier];
    if (cachedHeight)
        return cachedHeight.floatValue;

    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
    CGFloat height = cell.bounds.size.height;
    heightCache[cellIdentifier] = @(height);
    return height;
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    NSString *cellIdentifier = [self cellIdentifierForIndexPath:indexPath];

    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier forIndexPath:indexPath];

    <... configure cell as usual...>

Bunun eski bir cevap olduğunu biliyorum, ama başka kimse bunun bir yığın taşmasına neden olduğunu fark ediyor mu? Görünüm yüklendiğinde, IQIsimeRowData refreshWithSection: tableViewRowData: hangi tableView: heightForRowAtIndexPath: çağıran dequeueReusableCellWithIdentifier: çağıran, böylece tekrarlayan yığın taşması var. Bu çözümü gerçekten kullanmak istedim, ancak iOS7 ile çalışmıyor gibi görünüyor.
Bakıcı

Swift'te çalışmaz, çünkü cell.bounds.size.height her zaman 0.0 döndürür
King-Wizard

Hücreler henüz sistemin tableView: heightForRowAtIndexPath yöntemini çağırdığı sırada mevcut değildir. Veri modelinize dizine eklemek ve orada ne tür bir hücre kullanılacağını görmek ve sonra bu hücrenin yüksekliğini hesaplamak ve döndürmek için size iletilen indexPath'i kullanabilmeniz gerekir. Bu, sistemin hücreleri oluşturmadan önce tablodaki hücreleri düzenlemesini sağlar.
King-Wizard

Ayrıca, kendi cellForRowAtIndexPath yönteminizi çağırmamalısınız. Tablo görünümleri, o anda ekranda görünür durumdaysa bu dizin yolu için bir hücre döndürecek bir cellForRowAtIndexPath yöntemine sahiptir, ancak genellikle bu dizin yolunun kendisiyle ilişkilendirilmiş bir hücresi yoktur.
King-Wizard

@ snow-tiger Bunu çabucak denemedim, ama yorumlarınızı anlamıyorum. '[Kendi] kendi cellForRowAtIndexPath yöntemini çağırmıyorum ve bunu yapmam kasıtlı. Ayrıca hücrelerin time tableView: heightForRowAtIndexPath denir, bu kodun bütün noktası ve neden bir hücre almak için dequeueReusableCellWithIdentifier kullanır farkında değilim. Bu yanıta gönderilen kod çalışır. Hızlı bir şekilde devam eden ekstra bir şey var, hızlı dönüşümde doğru olmayan bir şey var ya da bu soru / cevapın hedeflediği farklı bir sorunu çözmeye çalışıyorlar.
JosephH

19

Aslında satır yüksekliğine değiştirmeniz gereken iki yer var, önce hücre (bunu zaten değiştirdiniz) ve şimdi Tablo Görünümünü seçin ve Boyut Denetçisini kontrol edin


in tableview (cellview değil)> boyut denetçisi sekmesinde> satır yüksekliği
iman kazemayni

Bu ayrıntıyı her unuttuğumda beni deli ediyor. Öykü tablolarını kullanırken hücrenin ayarlanmasının neden tabloyu güncellemediğini bilmiyorum!
Scooter

11

Bence bu bir hata.

Yüksekliği, Yardımcı müfettiş tarafından değil, doğrudan film şeridinde fareyle sürükleyerek ayarlamayı deneyin.

Bu sorunu bu yöntemle çözdüm.


10

Hızlı kullanıyorsanız, böyle kullanın. Satır yüksekliğini seçmek için film şeridi kullanmayın. Programsal olarak tablo satır yüksekliğini şu şekilde ayarlayın,

 func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
    if indexPath.row == 0 || indexPath.row == 1{
        let cell = self.tableView.dequeueReusableCellWithIdentifier("section1", forIndexPath: indexPath) as! Section1TableViewCell
        self.tableView.rowHeight = 150
        cell.label1.text = "hiiiiii"
        cell.label2.text = "Huiiilllllll"
        return cell

    } else {

        let cell = self.tableView.dequeueReusableCellWithIdentifier("section2", forIndexPath: indexPath) as! Section2TableViewCell
        self.tableView.rowHeight = 60
        cell.label3.text = "llll"
        return cell
    }

}

Bu işe yarar, ancak daha genel olarak şunları yapabilirsiniz:cell.sizeToFit(); self.tableView.rowHeight = cell.frame.height
Andy Chou

7

Aşağıdaki satırların yardımıyla film şeridinden UITableviewCell yüksekliğini (UITableviewController - statik hücrelerde) alabilirsiniz.

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
   CGFloat height = [super tableView:tableView heightForRowAtIndexPath:indexPath];

    return height;
}

6

Film şeridini XML görünümünde açın ve rowHeightistenen öğenin niteliğini düzenlemeye çalışın .

Prototip satırım için özel rowHeight ayarlamaya çalıştığımda benim için çalıştı. Müfettiş aracılığıyla çalışmıyor, ancak XML aracılığıyla çalışıyor.


1
Sağ tıkladım ve "kaynak olarak aç" -> "kaynak kodu" nu seçtim. RowHeight zaten 120 olarak ayarlanmıştı. Film şeridinin orada bir hataya sahip olduğuna ve özel hücre yüksekliğini göz ardı ettiğine inanıyorum.
zirinisp

6

Prototipi cellsbir özel ile kullanabilir heightve ardından çağırıp cellForRowAtIndexPath:döndürebilirsiniz frame.height.:.

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
    UITableViewCell *cell = [self tableView:tableView
                    cellForRowAtIndexPath:indexPath];
    return cell.frame.size.height;
}

Bu yöntemin eklenmesi çok iyi çalıştı ve şimdi film şeridindeki tüm özelleştirmeleri ait olması gerektiği gibi tutuyor.
daspianist

Şimdiye kadar en iyi çözüm
TheJeff

4

Statik bir satır yüksekliği ayarlamak istiyorsanız, bunun gibi bir şey yapabilirsiniz:

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
    return 120;
}

4

Son zamanlarda bununla güreştim. Benim sorunum heightForRowAtIndexPath:Simulator iOS 7.1 için işe yarayacak yöntemi kullanarak yukarıda yayınlanan çözümler ancak daha sonra sadece iOS 8.1'e geçerek sonuçları tamamen berbat oldu.

Kendiliğinden boyutlanan hücreler hakkında daha fazla okumaya başladım (iOS 8'de tanıtıldı, burada okuyun ). Kullanımının UITableViewAutomaticDimensioniOS 8'de yardımcı olacağı belliydi. Bu tekniği kullanmayı denedim heightForRowAtIndexPath:ve voila kullanımını sildim, şimdi iOS 8'de mükemmel çalışıyordu. Ancak iOS 7 değildi. Ne yapmam gerekiyordu? heightForRowAtIndexPath:İOS 7 için değil iOS 7 için ihtiyacım vardı .

İşte benim yukarıdaki cevap @JosephH ödünç alınan benim çözüm (kısalık aşkına kesilmiş):

- (void)viewDidLoad {
    [super viewDidLoad];

    self.tableView.estimatedRowHeight = 50.;
    self.tableView.rowHeight = UITableViewAutomaticDimension;

    // ...
}

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
    if (SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(@"8.0")) {
        return UITableViewAutomaticDimension;

    } else {
        NSString *cellIdentifier = [self reuseIdentifierForCellAtIndexPath:indexPath];
        static NSMutableDictionary *heightCache;
        if (!heightCache)
            heightCache = [[NSMutableDictionary alloc] init];
        NSNumber *cachedHeight = heightCache[cellIdentifier];
        if (cachedHeight)
            return cachedHeight.floatValue;

    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
    CGFloat height = cell.bounds.size.height;
    heightCache[cellIdentifier] = @(height);
    return height;
    }
}

- (NSString *)reuseIdentifierForCellAtIndexPath:(NSIndexPath *)indexPath {
    NSString * reuseIdentifier;
    switch (indexPath.row) {
        case 0:
            reuseIdentifier = EventTitleCellIdentifier;
            break;
        case 2:
            reuseIdentifier = EventDateTimeCellIdentifier;
            break;
        case 4:
            reuseIdentifier = EventContactsCellIdentifier;
            break;
        case 6:
            reuseIdentifier = EventLocationCellIdentifier;
            break;
        case 8:
            reuseIdentifier = NotesCellIdentifier;
            break;
        default:
            reuseIdentifier = SeparatorCellIdentifier;
            break;
    }

    return reuseIdentifier;
}

SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO (@ "8.0") aslında bir yerde bulduğum makro tanımları kümesinden (çok yararlı). Bunlar şu şekilde tanımlanır:

#define SYSTEM_VERSION_EQUAL_TO(v)                  ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] == NSOrderedSame)
#define SYSTEM_VERSION_GREATER_THAN(v)              ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] == NSOrderedDescending)
#define SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(v)  ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] != NSOrderedAscending)
#define SYSTEM_VERSION_LESS_THAN(v)                 ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] == NSOrderedAscending)
#define SYSTEM_VERSION_LESS_THAN_OR_EQUAL_TO(v)     ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] != NSOrderedDescending)

2

Swift 4 kullanarak XCode 9 üzerinde çalışırken aynı sorun oluştu .

Hücre içindeki UI öğeleri için Otomatik Düzen ekleyin ve özel hücre satırı yüksekliği belirtildiği gibi çalışır.


1
Merhaba, lütfen bunu nasıl yaptın?
Geri Packer

Sadece hücrenin altına bir kısıtlama seti eklemeniz gerekir.
Justin

Bunu yaptığımda ve hücre yüksekliği için film şeridinde "otomatik" i seçtiğinizde, koştuğumda doğru görünse de, tüm yükseklikleri film şeridinde 44'e ayarlamak istiyor. Film şeridinin doğru bir şekilde görüntülenmesini nasıl sağlayabilirim?
David

1

Dinamik hücreler için, UITableView üzerinde ayarlanan rowHeight her zaman tek tek hücrelerin rowHeight değerini geçersiz kılar. Satır içindeki içerik varsa dinamik yüksekliği hesaplamanız yeterlidir.


0

Bulabildiğim tek gerçek çözüm şudur

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
    UITableViewCell *cell = ...; // Instantiate with a "common" method you'll use again in cellForRowAtIndexPath:
    return cell.frame.size.height;
}

Bu çalışır ve korkunç bir anahtarın olmamasına izin verir / eğer zaten StoryBoard'da mantık çoğaltılırsa. Performans hakkında emin değilim ama sanırım cellForRow:zaten initalized hücreye geldiğinde o kadar hızlı. Tabii ki burada muhtemelen teminat zararları var, ama burada benim için iyi çalışıyor gibi görünüyor.

Bunu buraya da gönderdim: https://devforums.apple.com/message/772464

EDIT: Ortwin Gentz bana sadece görünür olanlar değil, TableView tüm hücreleri heightForRowAtIndexPath:için çağrılacak hatırlattı . İOS'un doğru kaydırma çubuklarını gösterebilmesi için toplam yüksekliği bilmesi gerektiğinden mantıklı geliyor. Muhtemelen küçük TableView'lerde (20 Hücre gibi) iyi olduğu anlamına gelir, ancak 1000 Hücreli TableView'da unutun.

Ayrıca, XML ile önceki hile: Benim için ilk yorum ile aynı. Doğru değer zaten oradaydı.


0

Yorum olarak eklendi, ancak görünürlük için bir yanıt olarak yayınlayın:

Başlangıçta bir tablo görünümünü "statik hücreler" olarak ayarlayıp "dinamik prototipler" olarak değiştirirseniz de bir sorun var gibi görünüyor . Delege yönteminin bile heightForRowAtIndexPathgöz ardı edildiği bir sorun yaşadım . İlk önce doğrudan storyboard XML'sini düzenleyerek çözdüm, sonra nihayetinde başlangıçtan itibaren dinamik prototipler kullanarak storyboard sahnesini sıfırdan yeniden oluşturdum.


0

Arayüz Oluşturucu aracılığıyla bu soruna herhangi bir çözüm bulamadığım göz önüne alındığında , ilk soru Arayüz Oluşturucu aracılığıyla bir çözüm istemesine rağmen, Swift'te iki dinamik hücre kullanarak soruna programatik bir çözüm yayınlamaya karar verdim . Ne olursa olsun, Stack Overflow topluluğu için yararlı olabileceğini düşünüyorum:

    import UIKit

    enum SignInUpMenuTableViewControllerCellIdentifier: String {
       case BigButtonCell = "BigButtonCell"
       case LabelCell = "LabelCell"
    }

    class SignInUpMenuTableViewController: UITableViewController {
            let heightCache = [SignInUpMenuTableViewControllerCellIdentifier.BigButtonCell : CGFloat(50),
                              SignInUpMenuTableViewControllerCellIdentifier.LabelCell : CGFloat(115)]

    private func cellIdentifierForIndexPath(indexPath: NSIndexPath) -> SignInUpMenuTableViewControllerCellIdentifier {
        if indexPath.row == 2 {
            return SignInUpMenuTableViewControllerCellIdentifier.LabelCell
        } else {
            return SignInUpMenuTableViewControllerCellIdentifier.BigButtonCell
        }
    }

   override func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
       return self.heightCache[self.cellIdentifierForIndexPath(indexPath)]!
   }

   ...

  }

Bu iyi ve güzel ama kodu yanlış okuduğum sürece, sadece sihirli sayılara dayanıyor ve dinamik hücreler için IB'de ayarladığınız değeri tamamen görmezden geliyor, bu yüzden OP'nin sorusuna tam bir çözüm değil
Danny

0

Yapabileceğiniz başka bir şey, Belge Anahattınıza gitmek, prototip hücrenizin iç içe yerleştirildiği tablo görünümünü seçmek. Ardından Boyut Denetçisinde, tablo görünümü Satır Yüksekliğini istediğiniz değere değiştirin ve Otomatik kutusunun işaretini kaldırın.

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.