各セルのアクセサリビューとしてUITableViewCell
とUISwitch
を使用しています。セルのスイッチの値を変更すると、スイッチがどの行にあるかをどのようにして知ることができますか?スイッチ値変更イベントの行番号が必要です。
タグ、サブクラス、またはビュー階層ナビゲーションはあまりに多くの作業!です。アクションメソッドでこれを行います。
CGPoint hitPoint = [sender convertPoint:CGPointZero toView:self.tableView];
NSIndexPath *hitIndex = [self.tableView indexPathForRowAtPoint:hitPoint];
送信者のOriginがセルのフレーム内にある限り(robに感謝!)、通常はそうである限り、あらゆる種類のビュー、マルチセクションテーブル、それに投げることができるもので動作します。
そして、これはUITableView Swift extension:
extension UITableView {
func indexPath(for view: UIView) -> IndexPath? {
let location = view.convert(CGPoint.zero, to: self)
return self.indexPathForRow(at: location)
}
}
tag
プロパティを行番号に設定すると(他の回答で提案されているように)、tableView:cellForRowAtIndexPath:
で毎回更新する必要があります(セルを別の行に再利用できるため)。
代わりに、行番号が必要な場合は、superview
(またはその他のビュー)からUISwitch
までUITableViewCell
チェーンをたどって、次にUITableView
とし、テーブルビューにセルのインデックスパスを要求します。
static NSIndexPath *indexPathForView(UIView *view) {
while (view && ![view isKindOfClass:[UITableViewCell class]])
view = view.superview;
if (!view)
return nil;
UITableViewCell *cell = (UITableViewCell *)view;
while (view && ![view isKindOfClass:[UITableView class]])
view = view.superview;
if (!view)
return nil;
UITableView *tableView = (UITableView *)view;
return [tableView indexPathForCell:cell];
}
tableView:cellForRowAtIndexPath:
には何も必要ありません。
cellForRowAtIndexPath:
で、コントロールのtag
プロパティをindexPath.row
に設定します
受け入れられた解決策は巧妙なハックです。
ただし、IViewですでに利用可能なtag
プロパティを利用できるのに、なぜヒットポイントを使用する必要があるのですか? タグは行またはセクションのいずれかのみを保存できますなので、単一のIntであると言えます。
ええと...ルーツを忘れないでください(CS101)。 1つのIntは、2倍小さいサイズの整数を2つ格納できます。そして、これはこれの拡張です:
_extension Int {
public init(indexPath: IndexPath) {
var marshalledInt: UInt32 = 0xffffffff
let rowPiece = UInt16(indexPath.row)
let sectionPiece = UInt16(indexPath.section)
marshalledInt = marshalledInt & (UInt32(rowPiece) << 16)
marshalledInt = marshalledInt + UInt32(sectionPiece)
self.init(bitPattern: UInt(marshalledInt))
}
var indexPathRepresentation: IndexPath {
let section = self & 0x0000ffff
let pattern: UInt32 = 0xffff0000
let row = (UInt32(self) & pattern) >> 16
return IndexPath(row: Int(row), section: Int(section))
}
}
_
tableView(_:, cellForRowAt:)
では、次のことができます。
_cell.yourSwitch.tag = Int(indexPath: indexPath)
_
そして、アクションハンドラで次のことができます。
_func didToogle(sender: UISwitch){
print(sender.tag.indexPathRepresentation)
}
_
ただし、その制限に注意してください:行とセクションは65535より大きくする必要はありません。(UInt16.max)
TableViewのインデックスがそれほど高くなることはないと思いますが、そうなった場合は、自分自身に挑戦して、より効率的なパッキングスキームを実装してください。たとえば、セクションが非常に小さい場合、セクションを表すために16ビットすべてを必要とするわけではありません。次のようなintレイアウトを使用できます。
_{section area length}{all remaining}[4 BITS: section area length - 1]
_
つまり、4 LSBsは、セクションに少なくとも1ビットを割り当てるとすると、セクション領域の長さ-1を示します。したがって、セクションが0の場合、行は最大27ビット([1] [27] [4])を占めることができ、これで十分です。
私はサブビューを使用することを好みますが、レイアウトがわかっている場合は、それが一般的に非常にシンプルで1行短いものです...
NSIndexPath *indexPath = [tableView indexPathForCell:(UITableViewCell *)[[sender superview] superview]];
それ以上、ネストされている場合は、スーパービューを追加します。
もう少し情報:
あなたがしているのは、セルである親ビューとその親ビューを要求することだけです。次に、取得したセルのインデックスパスをテーブルビューに要求します。
これを行う一般的な方法の1つは、コントロール(この場合はスイッチ)のtag
を、行または表現されたオブジェクトを識別するために使用できるものに設定することです。
たとえば、tableView:cellForRowAtIndexPath:
でスイッチのtag
プロパティをindexPath.row
に設定し、アクションメソッドで送信者からタグを取得できます。
個人的には、私はこのアプローチが好きではなく、UITableViewCellをサブクラス化することを好みます。また、他のビューのタグとの競合を防ぐために、タグに「オフセット」を追加することをお勧めします。
この投稿で受け入れられた答えは完全に問題ありません。この投稿の@robmayoffから派生した次のものも完全に問題ないことを読者に提案したいと思います。
- (NSIndexPath *)indexPathForView:(UIView *)view inTableView:(UITableView *)tableView {
while (view && ![view isKindOfClass:[UITableViewCell class]])
view = view.superview;
UITableViewCell *cell = (UITableViewCell *)view;
return [tableView indexPathForCell:cell];
}
一部の人は、whileループのために、このアプローチに含まれる計算作業が多すぎると主張しています。別の方法として、ビューの原点をテーブルビューの座標空間に変換してindexPathForRowAtPoint:
を呼び出すと、さらに多くの作業が非表示になります。
このアプローチはSDKの変更の可能性に比べて安全ではないと主張する人もいます。実際、Appleは、テーブルビューのセル階層をすでに1回変更しており、contentView
をセルに追加しています。このアプローチは、そのような変更の前後に機能します。ビューの祖先がchainのスーパービュー(UIKitの基本となるもの)で見つけることができます。これは優れたコードです。
同僚が次のことを提案し、それをUITableViewカテゴリに追加しました。
+(UITableViewCell*)findParentCellForSubview:(UIView*)view
{
while (([view isKindOfClass:[UITableViewCell class]] == NO) && ([view superview] != nil))
view = [view superview];
if ([view superview] != nil)
return (UITableViewCell*)view;
return nil;
}
まだひどいですが、動作します。
SuperViewを使用するもう1つの方法。 UIViewのカテゴリのように機能します。
- (UITableViewCell *)superCell
{
if (!self.superview) {
return nil;
}
if ([self.superview isKindOfClass:[UITableViewCell class]]) {
return (UITableViewCell *)self.superview;
}
return [self.superview superCell];
}
私は複数のセクションについては知りませんが、1つのセクションのためにあなたを与えることができます...
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
NSInteger index=indexPath.row;
NSString *string=[[NSString alloc]initWithFormat:@"%ld",(long)index];
}
これから行番号を取得し、文字列に保存できます。