我有一个UITableViewCell
链接到一个对象的,我需要判断单元格是否可见。根据我所做的研究,这意味着我需要以某种方式访问UITableView
包含它的内容(从那里,有几种方法可以检查它是否可见)。所以我想知道是否UITableViewCell
有指向 的指针UITableView
,或者是否有任何其他方法可以从单元格中获取指针?
21 回答
为了避免检查 iOS 版本,从单元格的视图迭代地向上遍历超级视图,直到找到 UITableView:
Objective-C
id view = [cellInstance superview];
while (view && [view isKindOfClass:[UITableView class]] == NO) {
view = [view superview];
}
UITableView *tableView = (UITableView *)view;
迅速
var view = cellInstance.superview
while (view != nil && (view as? UITableView) == nil) {
view = view?.superview
}
if let tableView = view as? UITableView {
tableView.beginUpdates()
tableView.endUpdates()
}
在 iOS7 beta 5UITableViewWrapperView
中是一个UITableViewCell
. 也是UITableView
a的superview UITableViewWrapperView
。
所以对于iOS 7,解决方案是
UITableView *tableView = (UITableView *)cell.superview.superview;
所以对于 iOS 到 iOS 6 的解决方案是
UITableView *tableView = (UITableView *)cell.superview;
斯威夫特 5 扩展
递归
extension UIView {
func parentView<T: UIView>(of type: T.Type) -> T? {
guard let view = superview else {
return nil
}
return (view as? T) ?? view.parentView(of: T.self)
}
}
extension UITableViewCell {
var tableView: UITableView? {
return parentView(of: UITableView.self)
}
}
使用循环
extension UITableViewCell {
var tableView: UITableView? {
var view = superview
while let v = view, v.isKind(of: UITableView.self) == false {
view = v.superview
}
return view as? UITableView
}
}
在 iOS7 之前,cell 的 superview 是UITableView
包含它的。从 iOS7 GM 开始(大概也将在公开版本中),单元格的超级视图是 a UITableViewWrapperView
,其超级视图是UITableView
. 该问题有两种解决方案。
解决方案 #1:创建一个UITableViewCell
类别
@implementation UITableViewCell (RelatedTable)
- (UITableView *)relatedTable
{
if ([self.superview isKindOfClass:[UITableView class]])
return (UITableView *)self.superview;
else if ([self.superview.superview isKindOfClass:[UITableView class]])
return (UITableView *)self.superview.superview;
else
{
NSAssert(NO, @"UITableView shall always be found.");
return nil;
}
}
@end
这是一个很好的替代 using cell.superview
,可以轻松重构现有代码 - 只需搜索和替换 with [cell relatedTable]
,并输入一个断言以确保如果视图层次结构在未来发生更改或恢复,它将立即显示在你的测试中。
解决方案#2:添加一个弱UITableView
引用UITableViewCell
@interface SOUITableViewCell
@property (weak, nonatomic) UITableView *tableView;
@end
这是一个更好的设计,尽管它需要更多的代码重构才能在现有项目中使用。在您tableView:cellForRowAtIndexPath
使用 SOUITableViewCell 作为您的单元格类或确保您的自定义单元格类从子类SOUITableViewCell
化并将 tableView 分配给单元格的 tableView 属性。在单元格内,您可以使用self.tableView
.
如果它是可见的,那么它有一个超级视图。而且......惊喜......超级视图是一个 UITableView 对象。
但是,拥有超级视图并不能保证出现在屏幕上。但是 UITableView 提供了确定哪些单元格可见的方法。
不,没有从单元格到表格的专用引用。但是当你继承 UITableViewCell 时,你可以引入一个并在创建时设置它。(在我想到子视图层次结构之前,我自己做了很多。)
iOS7 更新: Apple 在此处更改了子视图层次结构。像往常一样,在处理没有详细记录的事情时,总是存在事情发生变化的风险。在最终找到 UITableView 对象之前,“爬上”视图层次结构要省事得多。
无论您最终通过调用超级视图或通过响应者链设法完成的工作都将非常脆弱。做到这一点的最好方法,如果细胞想知道一些事情,就是将一个对象传递给细胞,该对象响应某种方法来回答细胞想问的问题,并让控制器实现确定要回答什么的逻辑(从你的问题我猜细胞想知道某些东西是否可见)。
在单元格中创建一个委托协议,将单元格的委托设置为 tableViewController 并将所有 ui“控制”逻辑移动到 tableViewCotroller 中。
表格视图单元格应该是只显示信息的虚拟视图。
斯威夫特 2.2 解决方案。
UIView 的扩展,它递归地搜索具有特定类型的视图。
import UIKit
extension UIView {
func lookForSuperviewOfType<T: UIView>(type: T.Type) -> T? {
guard let view = self.superview as? T else {
return self.superview?.lookForSuperviewOfType(type)
}
return view
}
}
或更紧凑(感谢 kabiroberai):
import UIKit
extension UIView {
func lookForSuperviewOfType<T: UIView>(type: T.Type) -> T? {
return superview as? T ?? superview?.superviewOfType(type)
}
}
在您的牢房中,您只需将其称为:
let tableView = self.lookForSuperviewOfType(UITableView)
// Here we go
请注意 UITableViewCell 仅在 cellForRowAtIndexPath 执行后才添加到 UITableView 上。
我在 UITableViewCell 上创建了一个类别来获取其父 tableView:
@implementation UITableViewCell (ParentTableView)
- (UITableView *)parentTableView {
UITableView *tableView = nil;
UIView *view = self;
while(view != nil) {
if([view isKindOfClass:[UITableView class]]) {
tableView = (UITableView *)view;
break;
}
view = [view superview];
}
return tableView;
}
@end
最好的,
这是基于上述答案的Swift版本。我已经概括ExtendedCell
为以后使用。
import Foundation
import UIKit
class ExtendedCell: UITableViewCell {
weak var _tableView: UITableView!
func rowIndex() -> Int {
if _tableView == nil {
_tableView = tableView()
}
return _tableView.indexPathForSelectedRow!.row
}
func tableView() -> UITableView! {
if _tableView != nil {
return _tableView
}
var view = self.superview
while view != nil && !(view?.isKindOfClass(UITableView))! {
view = view?.superview
}
self._tableView = view as! UITableView
return _tableView
}
}
希望这有帮助:)
我基于 Gabe 的建议UITableViewWrapperView
object is the superview of UITableViewCell
object in iOS7 beta5 这个解决方案。
子类UITableviewCell
:
- (UITableView *)superTableView
{
return (UITableView *)[self findTableView:self];
}
- (UIView *)findTableView:(UIView *)view
{
if (view.superview && [view.superview isKindOfClass:[UITableView class]]) {
return view.superview;
}
return [self findTableView:view.superview];
}
我从上面的答案中借用和修改了一点,并提出了以下片段。
- (id)recursivelyFindSuperViewWithClass:(Class)clazz fromView:(id)containedView {
id containingView = [containedView superview];
while (containingView && ![containingView isKindOfClass:[clazz class]]) {
containingView = [containingView superview];
}
return containingView;
}
传入类提供了在某些其他情况下遍历和获取 UITableView 以外的视图的灵活性。
我对这个问题的解决方案与其他解决方案有些相似,但使用了优雅的 for 循环并且很短。它也应该是面向未来的:
- (UITableView *)tableView
{
UIView *view;
for (view = self.superview; ![view isKindOfClass:UITableView.class]; view = view.superview);
return (UITableView *)view;
}
UITableView *tv = (UITableView *) self.superview.superview;
BuyListController *vc = (BuyListController *) tv.dataSource;
尝试使用 ["UItableViewvariable" visibleCells],而不是 superview。
我在 foreach 循环中使用它来遍历应用程序看到的单元格并且它工作。
for (UITableView *v in [orderItemTableView visibleCells])//visibleCell is the fix.
{
@try{
[orderItemTableView reloadData];
if ([v isKindOfClass:[UIView class]]) {
ReviewOrderTableViewCell *cell = (ReviewOrderTableViewCell *)v;
if (([[cell deleteRecord] intValue] == 1) || ([[[cell editQuantityText] text] intValue] == 0))
//code here
}
}
}
奇迹般有效。
最低限度的测试,但这个非通用 Swift 3 示例似乎有效:
extension UITableViewCell {
func tableView() -> UITableView? {
var currentView: UIView = self
while let superView = currentView.superview {
if superView is UITableView {
return (superView as! UITableView)
}
currentView = superView
}
return nil
}
}
此代码`UITableView *tblView=[cell superview];
将为您提供 UItableview 的实例,其中包含 tabe 视图单元
我建议你以这种方式遍历视图层次结构来找到父 UITableView:
- (UITableView *) findParentTableView:(UITableViewCell *) cell
{
UIView *view = cell;
while ( view && ![view isKindOfClass:[UITableView class]] )
{
#ifdef DEBUG
NSLog( @"%@", [[view class ] description] );
#endif
view = [view superview];
}
return ( (UITableView *) view );
}
否则,当 Apple再次更改视图层次结构时,您的代码将中断。
另一个遍历层次结构的答案是递归的。
UITableViewCell Internal View Hierarchy Change in iOS 7
Using iOS 6.1 SDK
<UITableViewCell>
| <UITableViewCellContentView>
| | <UILabel>
Using iOS 7 SDK
<UITableViewCell>
| <UITableViewCellScrollView>
| | <UIButton>
| | | <UIImageView>
| | <UITableViewCellContentView>
| | | <UILabel>
The new private UITableViewCellScrollView class is a subclass of UIScrollView and is what allows this interaction:
![enter image description here][1]
[1]: http://i.stack.imgur.com/C2uJa.gif
你可以用一行代码得到它。
UITableView *tableView = (UITableView *)[[cell superview] superview];
extension UIView {
func parentTableView() -> UITableView? {
var viewOrNil: UIView? = self
while let view = viewOrNil {
if let tableView = view as? UITableView {
return tableView
}
viewOrNil = view.superview
}
return nil
}
}
from @idris answer I wrote an expansion for UITableViewCell in Swift
extension UITableViewCell {
func relatedTableView() -> UITableView? {
var view = self.superview
while view != nil && !(view is UITableView) {
view = view?.superview
}
guard let tableView = view as? UITableView else { return nil }
return tableView
}