2010-12-01 27 views
36

Je suis en train de créer exactement le même effet que dans l'application AppStore pour l'affichage des captures d'écran: l'intérieur d'une UITableView, j'ai sous-classes personnalisées de UITableViewCell de. L'un d'eux est conçu pour montrer des aperçus de certains produits, disons 4 images. Je veux qu'ils s'affichent de la même manière que l'AppStore présente des captures d'écran d'une application: à l'intérieur d'un UIScrollView horizontal avec son UIPageControl attaché.UIScrollView horizontale à l'intérieur d'un UITableViewCell

Je Référencer mon UIScrollView et mon UIPageControl à mon UITableViewCell, comme ça:

@implementation phVolumePreviewCell 
- (id)init { 
    if (self = [super initWithStyle:UITableViewCellStyleDefault reuseIdentifier:kVolumePreviewCellIdentifier]) { 
     [self setAccessoryType:UITableViewCellAccessoryDisclosureIndicator]; 
     [self setSelectionStyle:UITableViewCellSeparatorStyleNone]; 

     previews = [[NSMutableArray alloc] initWithCapacity:4]; 
     for (int i = 0; i < 4; i++) { 
      [previews addObject:@"dummy"]; 
     } 

     scrollView = [[UIScrollView alloc] initWithFrame:CGRectZero]; 
     [scrollView setPagingEnabled:YES]; 
     [scrollView setBackgroundColor:[UIColor grayColor]]; 
     [scrollView setIndicatorStyle:UIScrollViewIndicatorStyleBlack]; 
     [scrollView setShowsHorizontalScrollIndicator:YES]; 
     [scrollView setBounces:YES]; 
     [scrollView setScrollEnabled:YES]; 
     [scrollView setDelegate:self]; 
     [self.contentView addSubview:scrollView]; 
     [scrollView release]; 

     pageControl = [[UIPageControl alloc] initWithFrame:CGRectZero]; 
     [pageControl setNumberOfPages:[previews count]]; 
     [pageControl setBackgroundColor:[UIColor grayColor]]; 
     [self.contentView addSubview:pageControl]; 
     [pageControl release]; 
    } 
    return self; 
} 

(Note: Je peuplant « aperçus » avec des données factices ici, juste pour avoir un [prévisualisations count] qui fonctionne, je veux voir l'indicateur de défilement de scrollView à des fins de test seulement, je les cacherai plus tard).

Mon problème est que je peux faire défiler tout UITableView contenant ce phVolumePreviewCell (sous-classe de UITableViewCell), mais je ne peux pas faire défiler l'UIScrollView. Comment puis-je atteindre cet objectif? La seule information que j'ai trouvé est là: http://theexciter.com/articles/touches-and-uiscrollview-inside-a-uitableview.html Mais il parle d'anciens SDK (à savoir 2.2) et je suis sûr qu'il y a une approche plus "récente" pour cela.

Quelques precisions:

  • je peux faire défiler le UIScrollView avec deux doigts. Ce n'est pas ce que je veux, je veux qu'il soit capable de faire défiler avec un seul doigt.
  • Lorsque je défile avec deux doigts, le TableView intercepte encore les touches et fait défiler un peu vers le haut ou vers le bas. Je voudrais que le TableView colle à sa position quand je touche le ScrollView.

Je crois que je dois travailler comment intercepter des touches sur mon TableView, et si le contact est sur la phVolumePreviewCell (de la sous-classe UITableViewCell personnalisé), passer à la cellule au lieu de la manipulation sur le TableView.

Pour mémoire, mon TableView est créé par programme dans une sous-classe de UITableViewController:

@interface phVolumeController : UITableViewController <UITableViewDelegate> { 
    LocalLibrary *lib; 
     NSString *volumeID; 
     LLVolume *volume; 
} 

- (id)initWithLibrary:(LocalLibrary *)newLib andVolumeID:(NSString *)newVolumeID; 
@end 

@implementation phVolumeController 

#pragma mark - 
#pragma mark Initialization 

- (id)initWithLibrary:(LocalLibrary *)newLib andVolumeID:(NSString *)newVolumeID { 
    if (self = [super initWithStyle:UITableViewStylePlain]) { 
     lib   = [newLib retain]; 
     volumeID  = newVolumeID; 
     volume  = [(LLVolume *)[LLVolume alloc] initFromLibrary:lib forID:volumeID]; 
     [[self navigationItem] setTitle:[volume title]]; 
    } 
    return self; 
} 

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { 
    return 1; 
} 

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { 
    return 1; 
} 

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { 
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:kVolumePreviewCellIdentifier]; 
    if (cell == nil) { 
     cell = [[[phVolumePreviewCell alloc] init] autorelease]; 
    } 

    [(phVolumePreviewCell *)cell setVolume:volume]; 
    return (UITableViewCell *)cell; 
} 

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath { 
    return kVolumePreviewCellHeight; 
} 

Merci pour toute aide!

Répondre

21

J'ai trouvé une solution de contournement.

Recréer à partir de zéro une UITableView très simple (8 lignes), et l'insertion d'une UIScrollView en seulement la deuxième rangée, fonctionne parfaitement. Les vues de défilement imbriquées (TableView et ScrollView) défilent indépendamment comme prévu. Tout cela a été fait dans un projet de test à un seul fichier, dans AppDelegate.

Alors ... je pensais d'abord « cela pourrait être un problème de délégation », donc je dit au ScrollView que son délégué était le TableView, pas ma sous-classe TableViewCell personnalisée. En vain.

Ensuite, au lieu de recourir à une sous-classe TableViewCell propre et personnalisée qui ajoute simplement ScrollView et PageControl, j'ai eu recours à la méthode TableViewCell dans la méthode cellForRowAtIndexPath: de TableView. Ensuite, je crée un UIScrollView juste après l'initialisation de TableViewCell, puis je l'ajoute à TableViewCell, et shazam ... ça marche!

Avant:

UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:kVolumePreviewCellIdentifier]; 
if (cell == nil) { 
    cell = [[[phVolumePreviewCell alloc] init] autorelease]; 
} 

[(phVolumePreviewCell *)cell setVolume:volume]; 
// That does the job of creating the cell's scrollView and pageControl 

return (UITableViewCell *)cell 

Après:

UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:kvcPreviewRowIdentifier]; 
if (cell == nil) { 
    cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:kvcPreviewRowIdentifier] autorelease]; 

    previewScrollView = [[UIScrollView alloc] initWithFrame:CGRectMake(0, 0, tableView.frame.size.width, kvcPreviewScrollViewHeight)]; 
    [previewScrollView setContentSize:CGSizeMake(1000, kvcPreviewScrollViewHeight)]; 
    [[cell contentView] addSubview:previewScrollView]; 

    previewPageControl = [[UIPageControl alloc] initWithFrame:CGRectMake(0, kvcPreviewScrollViewHeight, tableView.frame.size.width, kvcPreviewPageControlHeight)]; 
    [previewPageControl setNumberOfPages:4]; 
    [[cell contentView] addSubview:previewPageControl]; 
} 

return (UITableViewCell *)cell; 

Comment diable vient que quand je crée mon ScrollView de la sous-classe TVCell, il ne joue pas bien; mais quand je crée le scrollView à partir du TableView juste après avoir créé un TVCell "classique", cela fonctionne?

J'aurais peut-être trouvé une solution, mais je suis toujours perplexe devant la raison.

+0

Merci Cyrille !! Même problème ici. Votre solution m'a sauvé beaucoup d'heures en désespoir de cause !! :-) –

+0

Bonjour Cyrille - Je sais que c'est une vieille question SO, mais je me demandais si vous aviez un exemple d'application pour cette solution? Merci .. – Craig

+0

@Craig: pas d'exemple d'application, désolé. Ce code a évolué depuis et je ne l'utilise plus. Mais vraiment, tout le code dont vous avez besoin pour reproduire cette situation est ici dans mes messages. – Cyrille