5

質問 - UITableViewController の「heightForRowAtIndexPath」メソッドで行の高さを計算するにはどうすればよいですか?

  1. カスタム サブクラス化された UITableViewCell を使用しています。サブビュー (UILabels など) の実際のサイズは実行時に計算され、ユーザーがフォント サイズを変更した場合などに依存します。
  2. セルは実際には準備されていないため、「heightForRowAtIndexPath」の前にあるように見えるため、特定のカスタムセルインスタントを呼び出してクエリを実行することに頼ることはできません

現時点で私が考えることができる唯一のことは次のとおりです。 1.カスタムUITableViewCellサブクラスで、UITableViewCellサブクラスにある各サブビュー(UILabelなど)の高さを計算するメソッドを作成します-次に、セルサブクラス内でこれを使用しますインスタンスの作成 2. また、カスタム サブクラスで、すべての UILabels を実行するクラス メソッドを作成し、上記のメソッドを呼び出して高さを合計し、行の高さの合計を計算します。渡されたデータを取得する必要があります (各 UILabels のテキストなど) 3. UITableViewController "heightForRowAtIndexPath" で、上記 (2) の "calRowHeight" タイプのメソッドを呼び出して、ラベル テキスト データを渡す必要があります。 . そのため、行の高さの合計を計算する方法を知っているカスタム セル サブクラスのクラス メソッドを効果的に呼び出しますが、'

これよりも簡単な方法はありますか?

4

2 に答える 2

14

UITableView が作成され、reloadData メッセージを送信するたびに、セルごとに 1 つの heightForRowAtIndexPath メッセージがデータソースに送信されます。したがって、テーブルに 30 個のセルがある場合、そのメッセージは 30 回送信されます。

これらの 30 個のセルのうち 6 個だけが画面に表示されているとします。その場合、作成時に reloadData メッセージを送信すると、UITableView は表示される行ごとに 1 つの cellForRowAtIndexPath メッセージを送信します。つまり、そのメッセージは 6 回送信されます。

なぜAppleはこのように実装するのですか? その理由の 1 つは、ほとんどの場合、セル全体を構築してデータを入力するよりも、行の高さを計算する方が安価だからです。また、多くのテーブルですべてのセルの高さが同じであることを考えると、多くの場合、はるかに安価です。その理由の一部は、iOS がテーブル全体のサイズを知る必要があるためです。これにより、スクロール バーを作成し、スクロール ビューなどに設定することができます。

テキストの量が異なるために行の高さが異なる場合は、関連する文字列に対していずれかの sizeWithFont: メソッドを使用して計算を行うことができます。これは、ビューを構築してから結果を測定するよりも高速です。セルの高さを変更する場合は、テーブル全体をリロードする必要があることに注意してください (reloadData を使用 - これはデリゲートにすべての高さを要求しますが、表示されるセルのみを要求します)、またはサイズが指定されている行を選択的にリロードする必要があります。かわった。

追加資料 コメントのフォローアップの質問を理解できれば、以下が役立つ場合があります。

編集モードを実装している場合、テーブルの行の高さを変更する必要があることは珍しくありません。たとえば、表の行にテキストがあり、セルの幅が狭くなった場合 (右側の削除円のためのスペースを確保するため)、テキストを収めるために一部のセルの高さを高くしたい場合があります。ここでの基本的なアプローチは次のとおりです。

  • tableView:heightForRowAtIndexPath: メソッドが、編集モードかどうかを認識していることを確認してください。(isEditing を使用して tableView に問い合わせることができます。)次に、編集モードかどうかに応じて、正しい高さを返すメソッドを取得します。

  • setEditing:animated: UITableViewController (または UIViewController のどちらを使用していても - 使用するものに応じていくつかの違いがあるため、ドキュメントを注意深く確認する価値があります) の setEditing:animated: メソッドで、状態を変更した後に tableView に reloadData メッセージを送信します。 . これにより、tableView はすべての行の高さを取得し、表示されている行のセルを再フェッチします。tableView は、編集モードに入ったときにセルを狭くする処理を行いますが、レイアウトでさらに作業を行いたい場合は、tableView:cellForRowAtIndex: で行います。前述のように、一般的な戦略は、高さをすばやく計算する方法を見つけることです。テキスト sizeWithFont: (およびそのバリアント) を使用すると、それを行うことができます。画像などがある場合は、それらの寸法を取得して合計することができます。

  • これらの手順に加えて、モードを切り替えた後に tableView を少しスクロールすることもできます。行の高さが異なる場合、モードを切り替えた後、テーブル内の間違った位置になります。ここで取ったアプローチは、テーブルをリロードした後に performSelector:withObject:afterDelay を使用して、スクロール調整を行うメソッドを呼び出すことです。tableView が新しい高さと新しいテーブル セルを収集する時間を確保するために、遅延を使用する必要があります。(これを行うよりスマートな方法があるかもしれません。) リロードの前後で画面に最初に表示されるセルの tableView:cellForRowAtIndexPath: の origin.y の差に基づいてスクロール調整を行うために、いくつかの合計を行います。たとえば、プリロード前の位置を取得するには、次のようにします。

    CGPoint offset = [[self tableView] contentOffset];
    NSIndexPath* indexPath = [[self tableView] indexPathForRowAtPoint:CGPointMake(0,offset.y)];
    CGFloat preCellOffset = [[[self tableView] cellForRowAtIndexPath:indexPath] origin].y;
    
于 2011-03-14T07:50:59.693 に答える
3

私が過去に行ったことは、最も効率的かどうかはわかりませんが、heightForRowAtIndexPathメソッド呼び出し内からcellForRowAtIndexPath、そのセルの高さをビューに尋ねます。ヘッダーとフッターの高さについても同様のことを行いました。このようにすると、セル、ヘッダー、またはフッターを変更した場合に、対応する高さのメソッドを更新することを覚えておく必要がなくなります。

于 2011-03-14T03:19:27.267 に答える