web-dev-qa-db-ja.com

ストーリーボードのカスタムセル行の高さ設定が応答しない

テーブルビューのセルの1つのセルの高さを調整しようとしています。問題のセルの「サイズインスペクター」内の「行の高さ」設定からサイズを調整しています。 iPhoneでアプリを実行すると、セルのデフォルトサイズは、テーブルビューの「行サイズ」から設定されます。

テーブルビューの「行サイズ」を変更すると、すべてのセルのサイズが変更されます。 1つのセルのみにカスタムサイズが必要なため、これを行いたくありません。私は問題に対するプログラム的な解決策を持っている多くの投稿を見てきましたが、可能であれば、ストーリーボードを通してそれを行うことを望みます。

210
zirinisp

動的セル​​では、UITableViewで設定されたrowHeightは常に個々のセルのrowHeightをオーバーライドします。

しかしstaticセル​​では、個々のセルに設定されたrowHeightはUITableViewをオーバーライドできます。

それがバグかどうかわからない、Appleが意図的にこれを行っている可能性がありますか?

292
pixelfreak

UITableViewControllerを使用する場合、このメソッドを実装します。

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

行の機能では、高さを選択できます。例えば、

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

この例では、最初の行の高さは100ピクセルで、その他は60ピクセルです。

これがあなたのお役に立てば幸いです。

84
Beber

動的セルの場合、rowHeightに設定されたUITableViewは、個々のセルのrowHeightを常にオーバーライドします。

この動作は、IMOのバグです。 UIを2か所で管理する必要があるときはいつでも、エラーが発生しやすくなります。たとえば、ストーリーボードでセルサイズを変更する場合は、heightForRowAtIndexPath:でもセルを変更することを忘れないでください。 Appleがバグを修正するまで、現在の最善の回避策はheightForRowAtIndexPath:をオーバーライドすることですが、 magic numbers ではなく、ストーリーボードの実際のプロトタイプセルを使用して高さを決定します。以下に例を示します。

- (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;
}

これにより、プロトタイプセルの高さの変更が実行時に自動的に取得され、UIをストーリーボードという1か所で管理するだけで済みます。

34
memmons

これは、プロトタイプセルを使用するストーリーボードで機能するように、さまざまな回答/コメントのヒントでコードを作成しました。

このコード:

  • ストーリーボードの明白な場所以外の場所にセルの高さを設定する必要はありません
  • パフォーマンス上の理由で高さをキャッシュします
  • 共通の関数を使用して、インデックスパスのセル識別子を取得し、ロジックの重複を回避します

Answerbot、Brennan、lensovetに感謝します。

- (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...>
22
JosephH

実際には、行の高さを変更する必要がある2つの場所があります。最初にセル(既に変更しました)、そしてテーブルビューを選択し、サイズインスペクターをチェックします。

20
Kristjan H.

これはバグだと思います。

ユーティリティインスペクターではなく、ストーリーボード上でマウスを直接ドラッグして高さを調整してみてください。

この方法でこの問題を解決しました。

11
Fogni

Swiftを使用している場合、次のように使用します。ストーリーボードを使用して行の高さを選択しないでください。このようにテーブルの行の高さをプログラムで設定し、

 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
    }

}
10

次の行を使用して、ストーリーボードからUITableviewCell(UITableviewController-静的セル内)の高さを取得できます。

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

    return height;
}
7
Hiren Panchal

XMLビューでストーリーボードを開き、必要な要素のrowHeight属性を編集してみてください。

プロトタイプの行にカスタムのrowHeightを設定しようとしたときにうまくいきました。インスペクター経由では機能しませんが、XML経由では機能します。

6
Shtirlic

プロトタイプcellsをカスタムheightとともに使用してから、cellForRowAtIndexPath:を呼び出して、そのframe.height .:を返すことができます。

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

私は最近これに取り組んでいます。私の問題は、heightForRowAtIndexPath:メソッドを使用して上記で投稿されたソリューションがシミュレータのiOS 7.1で機能するが、iOS 8.1に切り替えるだけで結果が完全に台無しになることでした。

セルの自己サイズ変更に関する詳細を読み始めました(iOS 8で導入されました こちらをご覧ください )。 UITableViewAutomaticDimensionの使用がiOS 8で役立つことは明らかでした。そのテクニックを使用してみて、heightForRowAtIndexPath:とvoilaの使用を削除しました。これはiOS 8で完璧に機能していました。しかし、iOS 7はそうではありませんでした。私は何をすべきか? iOS 8ではなくiOS 7にheightForRowAtIndexPath:が必要でした。

上記の@JosephHの回答から借用した私のソリューション(簡潔にするためにトリミングされています)は次のとおりです。

- (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")は、実際にどこかで見つけた(非常に役立つ)私が使用している一連のマクロ定義からのものです。それらは次のように定義されます:

#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)
4
speby

静的な行の高さを設定する場合、次のようなことができます。

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

XCode 9を使用したSwift 4で作業しているときに同じ問題が発生しました。

AutoLayoutの追加 Cell内のUI要素の場合、カスタムセル行の高さは指定どおりに機能します。

1
Murari Varma

ダイナミックセルの場合、UITableViewで設定されたrowHeightは常に個々のセルのrowHeightをオーバーライドします。行内のコンテンツの場合、動的な高さを計算するだけです。

1
Aks

Interface Builderでこの問題の解決策が見つからなかったため、Swift2つの動的セルを使用して、問題のプログラムによる解決策を投稿することにしました、最初の質問ではInterface Builderを使用して解決策を求めましたが。とにかく、Stack Overflowコミュニティにとって役立つと思います。

    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)]!
   }

   ...

  }
0
King-Wizard

コメントとして追加されましたが、可視性の回答として投稿します。

初期テーブルビューを「静的セル」として設定し、それを「動的プロトタイプ」に変更した場合にも問題があるようです。 heightForRowAtIndexPathのデリゲートメソッドでさえ無視されるという問題がありました。最初にストーリーボードXMLを直接編集して解決し、最後に最初からダイナミックプロトタイプを使用してストーリーボードシーンをゼロから再構築しました。

0
Eric Goldberg

私が見つけることができる唯一の本当の解決策はこれです

- (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;
}

これは機能し、恐ろしいスイッチを持たないようにします/ StoryBoardに既にロジックを複製している場合。パフォーマンスについてはわかりませんが、cellForRow:に到着すると、セルはすでに初期化されているので、同じくらい高速です。もちろん、ここにはおそらく付随的な損害がありますが、私にとってはうまく機能しているようです。

こちらも投稿しました: https://devforums.Apple.com/message/772464

編集: Ortwin Gentz TableViewのセル(表示されているセルだけでなく)に対してallheightForRowAtIndexPath:が呼び出されることを思い出しました。 iOSは正しいスクロールバーを表示できるように全体の高さを知る必要があるため、論理的に聞こえます。これはおそらく、小さなTableView(20個のセルなど)では問題ありませんが、1000セルのTableViewでは忘れることを意味します。

また、XMLを使用した以前のトリック:私にとって最初のコメントと同じです。正しい値はすでにそこにありました。

0
StuFF mc

他にできることの1つは、ドキュメントアウトラインに移動し、プロトタイプセルがネストされているテーブルビューを選択することです。次に、サイズインスペクターで、テーブルビューの行の高さを目的の値に変更し、[自動]ボックスをオフにします。

0
Amin Rezapour