我有一个UITableViewCell
链接到对象的对象,我需要确定单元格是否可见。根据我已经完成的研究,这意味着我需要以某种方式访问UITableView
包含它的对象(从那里,有几种方法可以检查它是否可见)。所以我想知道是否UITableViewCell
有指向的指针UITableView
,或者是否还有其他方法可以从单元格中获取指针?
[cell superView]
也许?
我有一个UITableViewCell
链接到对象的对象,我需要确定单元格是否可见。根据我已经完成的研究,这意味着我需要以某种方式访问UITableView
包含它的对象(从那里,有几种方法可以检查它是否可见)。所以我想知道是否UITableViewCell
有指向的指针UITableView
,或者是否还有其他方法可以从单元格中获取指针?
[cell superView]
也许?
Answers:
为了避免检查iOS版本,请从单元格视图迭代遍历超级视图,直到找到UITableView为止:
id view = [tableViewCellInstance superview];
while (view && [view isKindOfClass:[UITableView class]] == NO) {
view = [view superview];
}
UITableView *tableView = (UITableView *)view;
@property (weak, nonatomic) UITableView *tableView;
并在tableView:cellForRowAtIndexPath:
set中cell.tableView = tableView;
。
在iOS7 beta 5中UITableViewWrapperView
是的超级视图UITableViewCell
。也是UITableView
一个的监督UITableViewWrapperView
。
因此,对于iOS 7,解决方案是
UITableView *tableView = (UITableView *)cell.superview.superview;
因此,对于iOS 6以下的iOS,解决方案是
UITableView *tableView = (UITableView *)cell.superview;
UITableViewCell
使用新方法创建类别,该方法relatedTableView
将检查iOS版本并返回适当的superView。
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
}
}
view != nil
展开包装前先检查一下。尽管已更新为更清洁的代码
在iOS7之前,单元的超级视图就是其中的超级视图UITableView
。从iOS7 GM开始(大概也将在公共发行版中),该单元的超级视图为UITableViewWrapperView
,其超级视图为UITableView
。有两种解决方案。
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
这是使用的很好的直接替代品cell.superview
,可以轻松地重构现有代码-只需搜索并替换为[cell relatedTable]
,然后抛出一个断言,以确保如果视图层次结构将来发生更改或还原,它将立即显示出来。在您的测试中。
UITableView
引用添加到UITableViewCell
@interface SOUITableViewCell
@property (weak, nonatomic) UITableView *tableView;
@end
这是一个更好的设计,尽管需要更多的代码重构才能在现有项目中使用。在tableView:cellForRowAtIndexPath
使用SOUITableViewCell作为单元格类时,或确保自定义单元格类是该类的子类,SOUITableViewCell
并将tableView分配给该单元格的tableView属性。然后,您可以在单元格内部使用引用包含的tableview self.tableView
。
[self.superview.superview isKindOfClass:[UITableView class]]
应该是第一个,因为iOS 7越来越多。
如果可见,则具有超级视图。而且...令人惊讶...该超级视图是一个UITableView对象。
但是,拥有超级视图并不能保证能够在屏幕上显示。但是UITableView提供了确定哪些单元格可见的方法。
不,没有从单元格到表的专用引用。但是,当您继承UITableViewCell的子类时,可以引入一个并在创建时进行设置。(在想到子视图层次结构之前,我做了很多自己的事情。)
iOS7更新: Apple在这里更改了子视图层次结构。像往常一样,当处理未详细记录的内容时,始终存在更改的风险。“爬网”视图层次结构,直到最终找到UITableView对象,这是省钱的。
Swift 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
}
}
或更紧凑(感谢karobroberai):
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
请注意,只有在执行cellForRowAtIndexPath之后,才将UITableViewCell添加到UITableView上。
lookForSuperviewOfType:
方法主体压缩为一行,甚至可以快速查看:return superview as? T ?? superview?.superviewOfType(type)
通过调用超级视图或通过响应程序链最终可能要做的任何事情都将非常脆弱。如果单元格想知道某事,最好的方法是将一个对象传递给该单元格,该对象对可以回答该单元格要问的问题的某种方法做出响应,并使控制器执行确定要回答什么的逻辑(从您的问题中我猜想该单元想知道是否可见)。
在单元中创建委托协议,将单元的委托设置为tableViewController,并将所有ui“控制”逻辑移到tableViewCotroller中。
表格视图单元格应为仅显示信息的dum视图。
我在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
对象是UITableViewCell
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;
}
for (view = self.superview; view && ![view isKindOfClass:UITableView.class]; view = view.superview);
代替超级视图,尝试使用[“ UItableViewvariable” visibleCells]。
我在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
来自@idris的答案我在Swift中为UITableViewCell写了一个扩展
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
}