ストーリーボードを使用せずに、単純にUIView
をキャンバスにドラッグし、レイアウトしてからtableView:viewForHeaderInSection
またはtableView:viewForFooterInSection
デリゲートメソッドに設定できます。
IViewをキャンバスにドラッグできないStoryBoardでこれをどのように実現しますか
この質問はiOS 5に関するものでしたが、将来の読者のために、効果的なiOS 6ではdequeueReusableHeaderFooterViewWithIdentifier
の代わりにdequeueReusableCellWithIdentifier
を使用できることに注意してください。
したがって、viewDidLoad
で、registerNib:forHeaderFooterViewReuseIdentifier:
またはregisterClass:forHeaderFooterViewReuseIdentifier:
を呼び出します。次に、viewForHeaderInSection
で、tableView:dequeueReusableHeaderFooterViewWithIdentifier:
を呼び出します。このAPI(NIBベースのビューまたはプログラムで作成されたビューのいずれか)でセルプロトタイプを使用しませんが、これはデキューされたヘッダーおよびフッター用の新しいAPIです。
プロトタイプセルをセクションヘッダーおよび/またはフッターとして使用します。
tableView:viewForHeaderInSection:
メソッドまたはtableView:viewForFooterInSection:
メソッドを実装する[tableView dequeueReusableCellWithIdentifier:]
を使用してヘッダーを取得しますtableView:heightForHeaderInSection:
メソッドを実装します。-(UIView *) tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section {
static NSString *CellIdentifier = @"SectionHeader";
UITableViewCell *headerView = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (headerView == nil){
[NSException raise:@"headerView == nil.." format:@"No cells with matching CellIdentifier loaded from your storyboard"];
}
return headerView;
}
編集:ヘッダーのタイトルを変更する方法(コメント付きの質問):
tableView:viewForHeaderInSection:
メソッドで、次を呼び出してラベルを取得します。 UILabel *label = (UILabel *)[headerView viewWithTag:123];
[label setText:@"New Title"];
IOS 6.0以降では、新しいdequeueReusableHeaderFooterViewWithIdentifier
APIによって状況が変わりました。
ガイド (iOS 9でテスト済み)を作成しました。これは次のように要約できます。
UITableViewHeaderFooterView
viewDidLoad
に登録しますviewForHeaderInSection
を実装し、dequeueReusableHeaderFooterViewWithIdentifier
を使用してヘッダー/フッターを取得しますストーリーボードのプロトタイプセルを使用して、iOS7で動作するようにしました。カスタムセクションのヘッダービューに、ストーリーボードに設定されているセグエをトリガーするボタンがあります。
Tiemeのソリューション で開始
Pedro.mが指摘しているように、これに関する問題は、セクションヘッダーをタップすると、セクションの最初のセルが選択されることです。
Paul Vonが指摘しているように、これはセル全体ではなくセルのcontentViewを返すことで修正されます。
ただし、Honsが指摘しているように、セクションヘッダーを長押しするとアプリがクラッシュします。
解決策は、contentViewからジェスチャーRecognizersを削除することです。
-(UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section {
static NSString *CellIdentifier = @"SectionHeader";
UITableViewCell *sectionHeaderView = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
while (sectionHeaderView.contentView.gestureRecognizers.count) {
[sectionHeaderView.contentView removeGestureRecognizer:[sectionHeaderView.contentView.gestureRecognizers objectAtIndex:0]];
}
return sectionHeaderView.contentView; }
セクションヘッダービューでジェスチャを使用していない場合は、この小さなハックで完了したようです。
ストーリーボードを使用する場合、TableViewのプロトタイプセルを使用してヘッダービューをレイアウトできます。一意のidとviewForHeaderInSectionを設定すると、そのIDを持つセルをデキューしてUIViewにキャストできます。
Swiftの実装が必要な場合は、受け入れられた回答の指示に従ってください。その後、UITableViewControllerで次のメソッドを実装します。
override func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
return tableView.dequeueReusableCell(withIdentifier: "CustomHeader")
}
override func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
return 75
}
私が思いついた解決策は、基本的に、ストーリーボードの導入前に使用したものと同じ解決策です。
新しい空のインターフェイスクラスファイルを作成します。 UIViewをキャンバスにドラッグし、必要に応じてレイアウトします。
Nibを手動でロードし、viewForHeaderInSectionまたはviewForFooterInSectionデリゲートメソッドで適切なヘッダー/フッターセクションに割り当てます。
Appleがストーリーボードでこのシナリオを単純化し、より良いまたはよりシンプルなソリューションを探し続けることを望んでいました。たとえば、カスタムテーブルのヘッダーとフッターは簡単に追加できます。
セルのcontentViewを返すと、2つの問題が発生します。
viewForHeaderInSection
呼び出しのたびに、新しいセルを作成する)溶液:
テーブルheader\footerのラッパークラス。 UITableViewHeaderFooterView
から継承されたコンテナで、セルを内部に保持します
https://github.com/Magnat12/MGTableViewHeaderWrapperView.git
UITableViewにクラスを登録します(たとえば、viewDidLoad)
- (void)viewDidLoad {
[super viewDidLoad];
[self.tableView registerClass:[MGTableViewHeaderWrapperView class] forHeaderFooterViewReuseIdentifier:@"ProfileEditSectionHeader"];
}
UITableViewDelegateで:
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section {
MGTableViewHeaderWrapperView *view = [tableView dequeueReusableHeaderFooterViewWithIdentifier:@"ProfileEditSectionHeader"];
// init your custom cell
ProfileEditSectionTitleTableCell *cell = (ProfileEditSectionTitleTableCell * ) view.cell;
if (!cell) {
cell = [tableView dequeueReusableCellWithIdentifier:@"ProfileEditSectionTitleTableCell"];
view.cell = cell;
}
// Do something with your cell
return view;
}
ヘッダー/フッタービューを遅延的に作成するために、次のことを実行していました。
[NSNull null]
が再入力されたセクションヘッダー/フッターにView Controllerの可変配列を提供しますヘッダーが適切な手順をすべて実行しても再利用されないというシナリオで、私は問題を抱えていました。
したがって、空のセクション(0行)を表示する状況を達成したいすべての人へのヒントとして、次の点に注意してください。
dequeueReusableHeaderFooterViewWithIdentifierは、少なくとも1行を返すまでヘッダーを再利用しません
それが役に立てば幸い
Damonの提案 をフォローアップするために、開示インジケータのある通常の行のようにヘッダーを選択可能にした方法を次に示します。
UIButtonからサブクラス化されたボタン(サブクラス名「ButtonWithArgument」)をヘッダーのプロトタイプセルに追加し、タイトルテキストを削除しました(太字の「タイトル」テキストはプロトタイプセル内の別のUILabelです)
次に、ボタンをヘッダービュー全体に設定し、 Avarioのトリック で開示インジケーターを追加しました
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section
{
static NSString *CellIdentifier = @"PersonGroupHeader";
UITableViewCell *headerView = (UITableViewCell *) [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if(headerView == nil)
{
[NSException raise:@"headerView == nil, PersonGroupTableViewController" format:[NSString stringWithFormat:@"Storyboard does not have prototype cell with identifier %@",CellIdentifier]];
}
// https://stackoverflow.com/a/24044628/3075839
while(headerView.contentView.gestureRecognizers.count)
{
[headerView.contentView removeGestureRecognizer:[headerView.contentView.gestureRecognizers objectAtIndex:0]];
}
ButtonWithArgument *button = (ButtonWithArgument *)[headerView viewWithTag:4];
button.frame = headerView.bounds; // set tap area to entire header view
button.argument = [[NSNumber alloc] initWithInteger:section]; // from ButtonWithArguments subclass
[button addTarget:self action:@selector(headerViewTap:) forControlEvents:UIControlEventTouchUpInside];
// https://stackoverflow.com/a/20821178/3075839
UITableViewCell *disclosure = [[UITableViewCell alloc] init];
disclosure.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
disclosure.userInteractionEnabled = NO;
disclosure.frame = CGRectMake(button.bounds.Origin.x + button.bounds.size.width - 20 - 5, // disclosure 20 px wide, right margin 5 px
(button.bounds.size.height - 20) / 2,
20,
20);
[button addSubview:disclosure];
// configure header title text
return headerView.contentView;
}
- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section
{
return 35.0f;
}
-(void) headerViewTap:(UIGestureRecognizer *)gestureRecognizer;
{
NSLog(@"header tap");
NSInteger section = ((NSNumber *)sender.argument).integerValue;
// do something here
}
ButtonWithArgument.h
#import <UIKit/UIKit.h>
@interface ButtonWithArgument : UIButton
@property (nonatomic, strong) NSObject *argument;
@end
ButtonWithArgument.m
#import "ButtonWithArgument.h"
@implementation ButtonWithArgument
@end
ヘッダーがビュー配列に基づいているソリューションについてはどうですか:
class myViewController: UIViewController {
var header: [UILabel] = myStringArray.map { (thisTitle: String) -> UILabel in
let headerView = UILabel()
headerView.text = thisTitle
return(headerView)
}
次にデリゲートで:
extension myViewController: UITableViewDelegate {
func tableView(tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
return(header[section])
}
}
Tieme's solution をベースとして使用する必要がありますが、viewWithTag:
およびその他の魚のようなアプローチを忘れて、代わりにヘッダーをリロードしてください(そのセクションをリロードしてください)。
したがって、カスタムのセルヘッダービューにすべての空想的なAutoLayout
を追加したら、次のようにキューから取り出して、設定後にcontentViewを返します。
-(UIView *) tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section {
static NSString *CellIdentifier = @"SectionHeader";
SettingsTableViewCell *sectionHeaderCell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
sectionHeaderCell.myPrettyLabel.text = @"Greetings";
sectionHeaderCell.contentView.backgroundColor = [UIColor whiteColor]; // don't leave this transparent
return sectionHeaderCell.contentView;
}
StoryBoard
にセルを追加し、reuseidentified
を設定します
コード
class TP_TaskViewTableViewSectionHeader: UITableViewCell{
}
そして
つかいます:
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let header = tableView.dequeueReusableCell(withIdentifier: "header", for: IndexPath.init(row: 0, section: section))
return header
}
これは @ Vitaliy Gozhenkoの答え 、Swiftにあります。
要約すると、UITableViewCellを含むUITableViewHeaderFooterViewを作成します。このUITableViewCellは「デキュー可能」になり、ストーリーボードで設計できます。
UITableViewHeaderFooterViewクラスを作成します
class CustomHeaderFooterView: UITableViewHeaderFooterView {
var cell : UITableViewCell? {
willSet {
cell?.removeFromSuperview()
}
didSet {
if let cell = cell {
cell.frame = self.bounds
cell.autoresizingMask = [UIViewAutoresizing.FlexibleHeight, UIViewAutoresizing.FlexibleWidth]
self.contentView.backgroundColor = UIColor .clearColor()
self.contentView .addSubview(cell)
}
}
}
ViewDidLoad関数でこのクラスを使用してテーブルビューを接続します。
self.tableView.registerClass(CustomHeaderFooterView.self, forHeaderFooterViewReuseIdentifier: "SECTION_ID")
セクションヘッダーの場合、CustomHeaderFooterViewをデキューし、セルを挿入します
func tableView(tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let view = self.tableView.dequeueReusableHeaderFooterViewWithIdentifier("SECTION_ID") as! CustomHeaderFooterView
if view.cell == nil {
let cell = self.tableView.dequeueReusableCellWithIdentifier("Cell")
view.cell = cell;
}
// Fill the cell with data here
return view;
}
Laszloの回答に似ていますが、テーブルセルとセクションヘッダーセルの両方に同じプロトタイプセルを再利用できます。以下の最初の2つの関数をUIViewControllerサブクラスに追加します
override func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let cell = tableView.dequeueReusableCell(withIdentifier: "DataCell") as! DataCell
cell.data1Label.text = "DATA KEY"
cell.data2Label.text = "DATA VALUE"
return cell
}
override func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
return 75
}
// Example of regular data cell dataDelegate to round out the example
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "DataCell", for: indexPath) as! PlayerCell
cell.data1Label.text = "\(dataList[indexPath.row].key)"
cell.data2Label.text = "\(dataList[indexPath.row].value)"
return cell
}