Ich habe eine UITableViewCell
, die mit einem Objekt verknüpft ist, und ich muss feststellen, ob die Zelle sichtbar ist. Nach den Recherchen, die ich durchgeführt habe, muss ich auf die UITableView
zugreifen, die sie enthält (von dort gibt es mehrere Möglichkeiten, um zu überprüfen, ob sie sichtbar ist). Ich frage mich also, ob UITableViewCell
einen Zeiger auf die UITableView
hat oder ob es einen anderen Weg gab, einen Zeiger aus der Zelle zu bekommen?
So vermeiden Sie iOS-Versionsprüfungen
id view = [tableViewCellInstance superview];
while (view && [view isKindOfClass:[UITableView class]] == NO) {
view = [view superview];
}
UITableView *tableView = (UITableView *)view;
In iOS7 Beta 5 ist UITableViewWrapperView
der Überblick über eine UITableViewCell
. Auch UITableView
ist eine Übersicht über eine UITableViewWrapperView
.
Also für iOS 7 ist die Lösung
UITableView *tableView = (UITableView *)cell.superview.superview;
Also für iOS bis iOS 6 ist die Lösung
UITableView *tableView = (UITableView *)cell.superview;
extension UIView {
func parentView<T: UIView>(of type: T.Type) -> T? {
guard let view = self.superview else {
return nil
}
return (view as? T) ?? view.parentView(of: T.self)
}
}
extension UITableViewCell {
var tableView: UITableView? {
return self.parentView(of: UITableView.self)
}
}
extension UITableViewCell {
var tableView: UITableView? {
var view = self.superview
while (view != nil && view!.isKind(of: UITableView.self) == false) {
view = view!.superview
}
return view as? UITableView
}
}
Vor iOS7 war der Überblick der Zelle die UITableView
, die sie enthielt. Ab iOS7 GM (so wird es vermutlich auch in der öffentlichen Veröffentlichung sein) ist der Superview der Zelle eine UITableViewWrapperView
, wobei der Superview die UITableView
ist. Es gibt zwei Lösungen für das Problem.
UITableViewCell
-Kategorie@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
Dies ist ein guter Ersatz für die Verwendung von cell.superview
. Erleichtert die Umgestaltung Ihres vorhandenen Codes. Suchen und ersetzen Sie ihn mit [cell relatedTable]
, und geben Sie eine Bestätigung ein, um sicherzustellen, dass sich die Ansichtshierarchie ändert oder in Zukunft rückgängig macht sofort in Ihren Tests.
UITableView
-Referenz zu UITableViewCell
hinzu.@interface SOUITableViewCell
@property (weak, nonatomic) UITableView *tableView;
@end
Dies ist ein viel besseres Design, obwohl für die Verwendung in vorhandenen Projekten etwas mehr Code-Refactoring erforderlich ist. Verwenden Sie in Ihrem tableView:cellForRowAtIndexPath
SOUITableViewCell als Zellklasse oder stellen Sie sicher, dass Ihre benutzerdefinierte Zellklasse von SOUITableViewCell
subclassed ist, und weisen Sie tableView der tableView-Eigenschaft der Zelle zu. Innerhalb der Zelle können Sie dann mit self.tableView
auf die enthaltende Tabellenansicht verweisen.
Was auch immer Sie durch das Aufrufen von Super View oder über die Responder-Kette erledigen können, wird sehr zerbrechlich sein .. Der beste Weg, dies zu tun, wenn die Zellen etwas wissen wollen, ist, ein Objekt an die Zelle zu übergeben Dies antwortet auf eine Methode, die die Frage beantwortet, die die Zelle stellen möchte, und der Controller muss die Logik implementieren, die bestimmt, was zu beantworten ist (aus Ihrer Frage schätze ich, die Zelle möchte wissen, ob etwas sichtbar ist oder nicht).
Erstellen Sie ein Delegatenprotokoll in der Zelle, setzen Sie den Delegaten der Zelle tableViewController und verschieben Sie die gesamte "Steuerungs" -Logik der UI im tableViewCotroller.
Die Zellen der Tabellensicht sollten eine Dum-Ansicht sein, in der nur Informationen angezeigt werden.
Schnelle 2.2 Lösung.
Eine Erweiterung für UIView, die rekursiv nach einer Ansicht mit einem bestimmten Typ sucht.
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
}
}
oder kompakter (dank kabiroberai):
import UIKit
extension UIView {
func lookForSuperviewOfType<T: UIView>(type: T.Type) -> T? {
return superview as? T ?? superview?.superviewOfType(type)
}
}
In Ihrer Zelle nennen Sie es einfach:
let tableView = self.lookForSuperviewOfType(UITableView)
// Here we go
Beachten Sie, dass UITableViewCell nur nach der Ausführung von cellForRowAtIndexPath in UITableView hinzugefügt wird.
Wenn es sichtbar ist, hat es einen Überblick. Und ... Überraschung ... der Überblick ist ein UITableView-Objekt.
Ein Überblick zu haben ist jedoch keine Garantie für die Anzeige auf dem Bildschirm. UITableView bietet jedoch Methoden, um festzustellen, welche Zellen sichtbar sind.
Und nein, es gibt keine dedizierte Referenz von einer Zelle zu einer Tabelle. Wenn Sie jedoch die UITableViewCell-Unterklasse definieren, können Sie eine einfügen und bei der Erstellung festlegen. (Ich habe das selbst oft gemacht, bevor ich an die Subview-Hierarchie dachte.)
Update für iOS7: Apple hat hier die Unteransichtshierarchie geändert. Beim Arbeiten mit Dingen, die nicht detailliert dokumentiert sind, besteht immer die Gefahr, dass sich Dinge ändern. Es ist weitaus sicherer, die Ansichtshierarchie "nach oben zu durchsuchen", bis schließlich ein UITableView-Objekt gefunden wird.
Ich habe eine Kategorie in UITableViewCell erstellt, um die übergeordnete tableView abzurufen:
@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
Beste,
Hier ist die Swift Version basierend auf den obigen Antworten. Ich habe mich zur späteren Verwendung in ExtendedCell
verallgemeinert.
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
}
}
Ich hoffe das hilft :)
UITableView *tv = (UITableView *) self.superview.superview;
BuyListController *vc = (BuyListController *) tv.dataSource;
Ich habe etwas von der obigen Antwort geborgt und modifiziert und mir das folgende Snippet ausgedacht.
- (id)recursivelyFindSuperViewWithClass:(Class)clazz fromView:(id)containedView {
id containingView = [containedView superview];
while (containingView && ![containingView isKindOfClass:[clazz class]]) {
containingView = [containingView superview];
}
return containingView;
}
Die Weitergabe in der Klasse bietet die Flexibilität, andere Ansichten als UITableView zu verwenden und andere Ansichten zu erhalten.
Diese Lösung basierte auf Gabes Vorschlag, dass UITableViewWrapperView
object der Überblick über UITableViewCell
in iOS7 beta5 ist.
Unterklasse 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];
}
Meine Lösung für dieses Problem ähnelt anderen Lösungen, verwendet jedoch eine elegante for-Schleife und ist kurz. Es sollte auch zukunftssicher sein:
- (UITableView *)tableView
{
UIView *view;
for (view = self.superview; ![view isKindOfClass:UITableView.class]; view = view.superview);
return (UITableView *)view;
}
Versuchen Sie anstelle von Superview, ["UItableViewvariable" visibleCells] zu verwenden.
Ich habe das in einer foreach-Schleife verwendet, um die Zellen zu durchlaufen, die die App gesehen hat, und es hat funktioniert.
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
}
}
}
Klappt wunderbar.
Minimal getestet, aber dieses nicht generische Swift 3-Beispiel scheint zu funktionieren:
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
}
}
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
}
}
Sie können es mit einer Codezeile erhalten.
UITableView *tableView = (UITableView *)[[cell superview] superview];
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 Vielen Dank
Ich schlage vor, Sie durchlaufen die Ansichtshierarchie auf diese Weise, um das übergeordnete UITableView zu finden:
- (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 );
}
Andernfalls wird Ihr Code beschädigt, wenn Apple die Ansichtshierarchie erneut ändert.
Eine andere Antwort die auch die Hierarchie durchläuft, ist rekursiv.
dieser Code `UITableView *tblView=[cell superview];
gibt Ihnen eine Instanz der UItableview, die die angezeigte Ansichtszelle enthält
antwort von @idris Ich habe eine Erweiterung für UITableViewCell in Swift geschrieben
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
}