回答:
で動的な細胞、rowHeight
のUITableViewのセットは常に、個々の細胞のrowHeightのを上書きします。
ただし、静的セルでrowHeight
は、個々のセルに設定するとUITableViewをオーバーライドできます。
それがバグかどうかわからない、Appleが意図的にこれを行っているのだろうか?
UITableView
コンテンツをからに変更することであることを意味Dynamic Prototypes
しStatic Cells
、私はそれを行いました、そして私のプロジェクト全体が爆発しました..ほとんど自殺しました。
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ピクセルです。
これがお役に立てば幸いです。
ダイナミックセルの場合、rowHeight
onを設定するとUITableView
、個々のセルが常にオーバーライドされますrowHeight
。
この動作はIMOのバグです。2つの場所でUIを管理する必要がある場合はいつでも、エラーが発生しやすくなります。たとえば、ストーリーボードでセルサイズを変更する場合は、セルでも変更することを忘れないでくださいheightForRowAtIndexPath:
。Appleがバグを修正するまで、現在の最善の回避策はオーバーライドheightForRowAtIndexPath:
することですが、マジックナンバーを使用するのではなく、ストーリーボードの実際のプロトタイプセルを使用して高さを決定します。次に例を示します。
- (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か所で管理するだけで済みます。
プロトタイプセルを使用するストーリーボードで機能するように、さまざまな回答/コメントのヒントとなるコードを作成しました。
このコード:
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...>
行の高さに変更する必要のある場所は実際には2つあります。最初にセル(既に変更済み)と、テーブルビューを選択し、サイズインスペクターを確認します。
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
}
}
cell.sizeToFit(); self.tableView.rowHeight = cell.frame.height
次の行を使用して、ストーリーボードからUITableviewCell(UITableviewController-静的セル内)の高さを取得できます。
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
CGFloat height = [super tableView:tableView heightForRowAtIndexPath:indexPath];
return height;
}
XMLビューでストーリーボードを開き、rowHeight
必要な要素の属性を編集してみます。
プロトタイプの行にカスタムのrowHeightを設定しようとしたときにうまくいきました。インスペクター経由では機能しませんが、XML経由では機能します。
cells
カスタムのプロトタイプを使用して、その。:をheight
呼び出しcellForRowAtIndexPath:
て返すことができますframe.height
。
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [self tableView:tableView
cellForRowAtIndexPath:indexPath];
return cell.frame.size.height;
}
私は最近これに取り組んでいます。私の問題は、上記のheightForRowAtIndexPath:
方法を使用したソリューションがシミュレーターのiOS 7.1で機能するが、iOS 8.1に切り替えるだけで結果が完全に台無しになったことでした。
セルフサイジングセルの詳細を読み始めました(iOS 8で導入されました。こちらをお読みください)。の使用がUITableViewAutomaticDimension
iOS 8で役立つことが明らかでした。そのテクニックを使用してみましたが、使用を削除しましたheightForRowAtIndexPath:
が、iOS 8では完全に機能していました。しかし、iOS 7はそうではありませんでした。私は何をしましたか?heightForRowAtIndexPath:
iOS 8ではなくiOS 7が必要でした。
上記の@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)
Swift 4を使用してXCode 9で作業しているときに同じ問題が発生しました。
Cell内のUI要素にAutoLayoutを追加すると、カスタムセルの行の高さが指定どおりに機能します。
私が見つけることができた唯一の本当の解決策はこれです
- (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
EDIT:Ortwin Gentzはそのことを思い出したheightForRowAtIndexPath:
ために呼び出されるすべての目に見えるものだけではなく、テーブルビューのセル。iOSは正しいスクロールバーを表示できるようにするために全体の高さを知る必要があるため、論理的に聞こえます。これは、小さなTableView(20セルなど)ではおそらく問題ないが、1000セルのTableViewではそれを忘れることを意味します。
また、XMLに関する以前のトリック:最初のコメントと同じです。正しい値はすでにそこにありました。
コメントとして追加されましたが、可視性のための回答として投稿します:
最初にテーブルビューを「静的セル」として設定し、それを「動的プロトタイプ」に変更した場合にも問題があるようです。のデリゲートメソッドでさえheightForRowAtIndexPath
無視されるという問題がありました。最初にストーリーボードXMLを直接編集して解決し、最後に最初から動的なプロトタイプを使用して、ストーリーボードシーンをゼロから再構築しました。
Interface Builderを介してこの問題の解決策が見つからなかったため、最初の質問でInterface Builderを介した解決策を求めていたとしても、2つの動的セルを使用してSwiftの問題にプログラムによる解決策を投稿することにしました。とにかく、スタックオーバーフローコミュニティに役立つと思います。
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)]!
}
...
}