J'ai une UITableViewCell
qui est liée à un objet et je dois dire si la cellule est visible. D'après les recherches que j'ai effectuées, cela signifie que je dois accéder d'une manière ou d'une autre à la UITableView
qui la contient (à partir de là, il existe plusieurs façons de vérifier si elle est visible). Je me demande donc si UITableViewCell
a un pointeur sur UITableView
ou s’il existe un autre moyen d’obtenir un pointeur de la cellule?
Pour éviter les vérifications de version iOS
id view = [tableViewCellInstance superview];
while (view && [view isKindOfClass:[UITableView class]] == NO) {
view = [view superview];
}
UITableView *tableView = (UITableView *)view;
Dans iOS7 bêta 5 UITableViewWrapperView
est la vue d'ensemble d'une UITableViewCell
.UITableView
est également superview d'un UITableViewWrapperView
.
Donc, pour iOS 7, la solution est
UITableView *tableView = (UITableView *)cell.superview.superview;
Donc, pour iOS jusqu'à iOS 6, la solution est
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
}
}
Avant iOS7, la superview de la cellule était la UITableView
qui la contenait. À partir de iOS7 GM (il est donc probable que la version publique le sera également), la superview de la cellule est une UITableViewWrapperView
, sa superview étant la UITableView
. Il y a deux solutions au problème.
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
C’est une bonne solution de remplacement immédiate à l’utilisation de cell.superview
, facilite la refactorisation de votre code existant - il suffit de chercher et de remplacer par [cell relatedTable]
et de lancer une assertion pour garantir que si la hiérarchie de la vue change ou revient à l’avenir, up immédiatement dans vos tests.
UITableView
faible à UITableViewCell
@interface SOUITableViewCell
@property (weak, nonatomic) UITableView *tableView;
@end
Cette conception est bien meilleure, mais elle nécessitera un peu plus de refactoring de code à utiliser dans les projets existants. Dans votre tableView:cellForRowAtIndexPath
, utilisez SOUITableViewCell comme classe de cellule ou assurez-vous que votre classe de cellule personnalisée est sous-classée à partir de SOUITableViewCell
et affectez la tableView à la propriété tableView de la cellule. Dans la cellule, vous pouvez ensuite vous référer à la table contenant en utilisant self.tableView
.
Quoi que vous réussissiez à faire en appelant super view ou via la chaîne de répondeurs, cela sera très fragile ... La meilleure façon de le faire, si les cellules veulent savoir quelque chose, est de passer un objet à la cellule cela répond à une méthode qui répond à la question que la cellule veut poser et demande au contrôleur de mettre en œuvre la logique de détermination de la réponse (d'après votre question, la cellule veut savoir si quelque chose est visible ou non).
Créez un protocole de délégué dans la cellule, définissez le délégué de la cellule sur tableViewController et déplacez toute la logique de "contrôle" de l'interface utilisateur dans tableViewCotroller.
Les cellules de la vue tableau doivent être une vue dum qui n’affiche que des informations.
Solution Swift 2.2.
Une extension pour UIView qui recherche de manière récursive une vue avec un type spécifique.
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
}
}
ou plus compact (grâce à kabiroberai):
import UIKit
extension UIView {
func lookForSuperviewOfType<T: UIView>(type: T.Type) -> T? {
return superview as? T ?? superview?.superviewOfType(type)
}
}
Dans votre cellulaire, vous appelez simplement cela:
let tableView = self.lookForSuperviewOfType(UITableView)
// Here we go
Notez que UITableViewCell est ajouté sur UITableView uniquement après l'exécution de cellForRowAtIndexPath.
Si c'est visible alors il y a un superview. Et ... surprise ... la superview est un objet UITableView.
Cependant, avoir un aperçu n'est pas une garantie d'être à l'écran. Mais UITableView fournit des méthodes pour déterminer quelles cellules sont visibles.
Et non, il n'y a pas de référence dédiée d'une cellule à une table. Mais lorsque vous sous-classez UITableViewCell, vous pouvez en introduire un et le définir lors de la création. (Je l'ai souvent fait moi-même avant de penser à la hiérarchie des sous-vues.)
Mise à jour pour iOS7: Apple a modifié la hiérarchie des sous-vues ici. Comme d'habitude lorsque vous travaillez avec des choses qui ne sont pas détaillées et documentées, il y a toujours un risque que les choses changent. Il est beaucoup plus économe de "parcourir" la hiérarchie des vues jusqu'à ce qu'un objet UITableView soit finalement trouvé.
J'ai créé une catégorie sur UITableViewCell pour obtenir sa tableView parent:
@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
Meilleur,
Voici la version Swift basée sur les réponses ci-dessus. J'ai généralisé en ExtendedCell
pour une utilisation ultérieure.
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
}
}
J'espère que cette aide :)
UITableView *tv = (UITableView *) self.superview.superview;
BuyListController *vc = (BuyListController *) tv.dataSource;
J'ai emprunté et modifié un peu la réponse ci-dessus pour arriver à l'extrait suivant.
- (id)recursivelyFindSuperViewWithClass:(Class)clazz fromView:(id)containedView {
id containingView = [containedView superview];
while (containingView && ![containingView isKindOfClass:[clazz class]]) {
containingView = [containingView superview];
}
return containingView;
}
Passer en classe offre la possibilité de parcourir et d’obtenir des vues autres que UITableView à d’autres occasions.
J'ai fondé cette solution sur la suggestion de Gabe selon laquelle l'objet UITableViewWrapperView
est la superview de l'objet UITableViewCell
dans iOS7 beta5.
Sous-classe 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];
}
Ma solution à ce problème est quelque peu similaire aux autres solutions, mais utilise une boucle for élégante et est courte. Il devrait également être à l'épreuve du temps:
- (UITableView *)tableView
{
UIView *view;
for (view = self.superview; ![view isKindOfClass:UITableView.class]; view = view.superview);
return (UITableView *)view;
}
Au lieu de superview, essayez d’utiliser ["UItableViewvariable" visibleCells].
J'ai utilisé cela dans une boucle foreach pour parcourir les cellules que l'application a vues et cela a fonctionné.
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
}
}
}
Fonctionne comme un charme.
Testé au minimum, mais cet exemple non générique de Swift 3 semble fonctionner:
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
}
}
Vous pouvez l'obtenir avec une ligne de code.
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
Je vous suggère de parcourir la hiérarchie des vues de cette manière pour trouver le UITableView parent:
- (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 );
}
Sinon, votre code se cassera lorsque Apple changera la hiérarchie des vues encore.
Une autre réponse qui traverse également la hiérarchie est récursive.
ce code `UITableView *tblView=[cell superview];
vous donnera une instance de UItableview qui contient la cellule de vue tab
de @idris answer J'ai écrit une extension pour UITableViewCell dans 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
}