简体   繁体   English

如何从 UITableViewCell 获取 UITableView?

[英]How to get UITableView from UITableViewCell?

I have a UITableViewCell which is linked to an object and I need to tell if the cell is visible.我有一个链接到对象的UITableViewCell ,我需要判断该单元格是否可见。 From the research I've done, this means I need to somehow access the UITableView that contains it (from there, there are several ways to check if it's visible).根据我所做的研究,这意味着我需要以某种方式访问​​包含它的UITableView (从那里,有几种方法可以检查它是否可见)。 So I'm wondering if UITableViewCell has a pointer to the UITableView , or if there was any other way to get a pointer from the cell?所以我想知道如果UITableViewCell有一个指针UITableView ,或是否有任何其他的方式来获得小区的指针?

To avoid checking the iOS version, iteratively walk up the superviews from the cell's view until a UITableView is found:为了避免检查 iOS 版本,从单元格的视图中迭代地向上走超级视图,直到找到 UITableView:

id view = [tableViewCellInstance superview];

while (view && [view isKindOfClass:[UITableView class]] == NO) {
    view = [view superview]; 
}

UITableView *tableView = (UITableView *)view;

In iOS7 beta 5 UITableViewWrapperView is the superview of a UITableViewCell .在iOS7的β5 UITableViewWrapperView是一个的上海华UITableViewCell Also UITableView is superview of a UITableViewWrapperView .此外UITableView是的上海华UITableViewWrapperView

So for iOS 7 the solution is所以对于 iOS 7 的解决方案是

UITableView *tableView = (UITableView *)cell.superview.superview;

So for iOSes up to iOS 6 the solution is所以对于 iOS 到 iOS 6 的解决方案是

UITableView *tableView = (UITableView *)cell.superview;

Swift 5 extension斯威夫特 5 扩展

Recursively递归地

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)
    }
}

Using loop使用循环

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
    }
}

Before iOS7, the cell's superview was the UITableView that contained it.在 iOS7 之前,cell 的 superview 是包含它的UITableView As of iOS7 GM (so presumably will be in the public release as well) the cell's superview is a UITableViewWrapperView with its superview being the UITableView .从 iOS7 GM 开始(所以大概也会在公开版本中),单元格的超级视图是UITableViewWrapperView ,其超级视图是UITableView There are two solutions to the problem.该问题有两种解决方案。

Solution #1: Create a UITableViewCell category解决方案#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

This is a good drop-in replacement to using cell.superview , makes it easy to refactor your existing code -- just search and replace with [cell relatedTable] , and throw in an assert to ensure that if the view hierarchy changes or reverts in the future it will show up immediately in your tests.这是使用cell.superview一个很好的替代品,可以轻松重构现有代码——只需搜索并替换为[cell relatedTable] ,并抛出断言以确保视图层次结构发生变化或恢复将来它会立即出现在你的测试中。

Solution #2: Add a Weak UITableView reference to UITableViewCell解决方案#2:添加对UITableViewCell的弱UITableView引用

@interface SOUITableViewCell

   @property (weak, nonatomic) UITableView *tableView;

@end

This is a much better design, though it will require a bit more code refactoring to use in existing projects.这是一个更好的设计,尽管它需要更多的代码重构才能在现有项目中使用。 In your tableView:cellForRowAtIndexPath use SOUITableViewCell as your cell class or make sure your custom cell class is subclassed from SOUITableViewCell and assign the tableView to the cell's tableView property.在您的tableView:cellForRowAtIndexPath使用 SOUITableViewCell 作为您的单元格类,或者确保您的自定义单元格类是从SOUITableViewCell子类SOUITableViewCell ,并将 tableView 分配给单元格的 tableView 属性。 Inside the cell you can then refer to the containing tableview using self.tableView .在单元格内,您可以使用self.tableView引用包含的 tableview。

If it is visible then it has a superview.如果它是可见的,那么它有一个超级视图。 And ... surprise ... the superview is an UITableView object.并且......惊喜...... superview 是一个 UITableView 对象。

However, having a superview is no guarantee for being on screen.但是,拥有超级视图并不能保证出现在屏幕上。 But UITableView provides methods to determine which cells are visible.但是 UITableView 提供了确定哪些单元格可见的方法。

And no, there is no dedicated reference from a cell to a table.不,没有从单元格到表格的专用引用。 But when you subclass UITableViewCell you may introduce one and set it upon creation.但是当您继承 UITableViewCell 时,您可能会引入一个并在创建时设置它。 (I did that myself a lot before I thought of the subview hierarchy.) (在我想到子视图层次结构之前,我自己做了很多。)

Update for iOS7: Apple has changed the subview hierarchy here. iOS7 更新: Apple 在此处更改了子视图层次结构。 As usual when working with things that are not detailled documented, there is always a risk that things change.像往常一样,在处理没有详细记录的事情时,总是有事情发生变化的风险。 It is far saver to "crawl up" the view hierarchy until a UITableView object is eventually found.在最终找到 UITableView 对象之前,“爬上”视图层次结构会节省很多。

Whatever you may end up managing to do by calling super view or via the responder chain is going to be very fragile.无论您最终通过调用超级视图还是通过响应者链设法做的事情都将非常脆弱。 The best way to do this, if the cells wants to know something, is to pass an object to the cell that responds to some method that answers the question the cell wants to ask, and have the controller implement the logic of determining what to answer (from your question I guess the cell wants to know if something is visible or not).如果单元格想要知道某事,最好的方法是将一个对象传递给单元格,该对象响应某个方法来回答单元格想要问的问题,并让控制器实现确定要回答什么的逻辑(从你的问题我猜细胞想知道某些东西是否可见)。

Create a delegate protocol in the cell, set the delegate of the cell the tableViewController and move all the ui "controlling" logic in the tableViewCotroller.在单元格中创建一个委托协议,将单元格的委托设置为 tableViewController 并在 tableViewCotroller 中移动所有 ui“控制”逻辑。

The table view cells should be dum view that will only display information.表格视图单元格应该是只显示信息的哑视图。

Swift 2.2 solution. Swift 2.2 解决方案。

An extension for UIView that recursively searches for a view with a specific type.递归搜索具有特定类型的视图的 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
    }
}

or more compact (thanks to kabiroberai):或更紧凑(感谢 kabiroberai):

import UIKit

extension UIView {
    func lookForSuperviewOfType<T: UIView>(type: T.Type) -> T? {
        return superview as? T ?? superview?.superviewOfType(type)
    }
}

In your cell you just call it:在您的单元格中,您只需调用它:

let tableView = self.lookForSuperviewOfType(UITableView)
// Here we go

Mind that UITableViewCell is added on the UITableView only after cellForRowAtIndexPath execution.注意 UITableViewCell 仅在 cellForRowAtIndexPath 执行后添加到 UITableView 上。

I created a category on UITableViewCell to get its parent tableView:我在 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

Best,最好,

Here is the Swift version based on above answers.这是基于上述答案的Swift版本。 I have generalized into ExtendedCell for later usage.我已经概括为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
    }
}

Hope this help :)希望这有帮助:)

I based this solution on Gabe's suggestion that UITableViewWrapperView object is the superview of UITableViewCell object in iOS7 beta5 .我的这个解决方案基于 Gabe 的建议,即UITableViewWrapperView对象是 iOS7 beta5 中UITableViewCell对象的超级视图。

Subclass UITableviewCell :子类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];
}

I Borrowed and modified a little bit from the above answer and come up with the following snippet.我从上面的答案中借用并修改了一点,并提出了以下代码段。

- (id)recursivelyFindSuperViewWithClass:(Class)clazz fromView:(id)containedView {
    id containingView = [containedView superview];
    while (containingView && ![containingView isKindOfClass:[clazz class]]) {
        containingView = [containingView superview];
    }
    return containingView;
}

Passing in class offers the flexibility for traversing and getting views other than UITableView in some other occasions.在类中传递提供了在其他一些情况下遍历和获取 UITableView 以外的视图的灵活性。

My solution to this problem is somewhat similar to other solutions, but uses an elegant for-loop and is short.我对这个问题的解决方案与其他解决方案有些相似,但使用了一个优雅的 for 循环并且很简短。 It should also be future-proof:它也应该是面向未来的:

- (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;

Instead of superview, try using ["UItableViewvariable" visibleCells].尝试使用 ["UItableViewvariable"visibleCells],而不是超级视图。

I used that in a foreach loops to loop through the cells that the app saw and it worked.我在 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 
    }
  }
}

Works like a charm.奇迹般有效。

Minimally tested but this non-generic Swift 3 example seems to work:最少测试,但这个非通用 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
    }
}

this code `UITableView *tblView=[cell superview];这段代码`UITableView *tblView=[cell superview]; will give you an instance of the UItableview which contains the tabe view cell会给你一个 UItableview 的实例,它包含 tabe 视图单元格

I suggest you traverse the view hierarchy this way to find the parent UITableView:我建议您以这种方式遍历视图层次结构以找到父 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 );
}

Otherwise your code will break when Apple changes the view hierarchy again .否则,当 Apple再次更改视图层次结构时,您的代码将中断。

Another answer that also traverses the hierarchy is recursive.另一个也遍历层次结构的答案是递归的。

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

http://www.curiousfind.com/blog/646 Thank You http://www.curiousfind.com/blog/646谢谢

你可以用一行代码得到它。

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来自@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
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM