关于UIScrollView嵌套UITableView冲突问题

scrollview 嵌套tableview 会导致手势冲突这在苹果官方文档已声明。我也做了尝试(本例是tableview作为列加入到scrollview中,如下图),发现用一个scrollview作为控制器的view时,滑动手势无法识别。但做了一次另外的有趣尝试发现,如果将tableview的父视图scrollview作为一个子视图插入到控制器的view中时,竟然可以识别毫无影响!!!在进一步测试发现,scrollview的宽度至少要小于他的父视图2px,才能不导致手势冲突,否则,即比如scrollview的宽度和view的宽度相同,仍然会冲突。分析了半天也没有头绪,看看大家有何看法。另外我还发现更有趣的困惑相信,由于无法用言语表达,在这里不做论述了。大家一起讨论下哈!我想这是很多人关注的问题,刚才还看到有人提问,额。




问题由来:项目需要做类似网易新闻的那种UIScrollView上放多个UITableView的效果,其中UITableView还要有下拉刷新效果。


一开始的思路,也是最直观的思路就是一个UIScrollView上放多个UITableView,然后发现UITableView的滑动和UIScrollView的滑动产生冲突,用户体验不好。主要原因在于UIScrollView的滑动原理。


基础知识看这里:

http://snorlax.sinaapp.com/?p=178

http://www.devdiv.com/forum.php?mod=viewthread&tid=197496

总结这两篇,问题在于如果想让UITableView可以下拉,并且显示下拉刷新组件,那么就不能让UIScrollView滚动(scrollEnabled=NO),如果想左右滑动显示并列的其他UITableView,那么就需要让UIScrollView可以滚动,但是,怎么知道用户想如何操作?所以此路不通。(即使可以滑动,但效果远远达不到产品需求)



与是就有了下面的想法:用一个UITableView作为背景,但这个UITableView仅有一个cell,然后在这个cell上放一个横着的UITableView,然后在这个横着的UITableView上放N个View,这样也达到了“UIScrollView上放多个UITableView的效果”。


上代码:


背景UITableView:

[cpp]  view plain copy print ?
  1. //实现Table  
  2. CGRect scrollRect = CGRectMake(0, 0, 320, 460);  
  3. self.tableBgScroll = [[[UITableView alloc] initWithFrame:scrollRect style:UITableViewStylePlain] autorelease];  
  4. [self.tableBgScroll setDelegate:self];  
  5. [self.tableBgScroll setDataSource:self];  
  6.   
  7. //Table的数据源方法  
  8. - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section  
  9. {  
  10.     return 1;  
  11. }  
  12.   
  13. - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath  
  14. {  
  15.     static NSString *cellname = @"cell";  
  16.     InfoCell *cell = (InfoCell *)[tableView dequeueReusableCellWithIdentifier:cellname];  
  17.     if (cell == nil)  
  18.     {  
  19.         cell = [[[InfoCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellname]autorelease];  
  20.     }  
  21.     cell.selectionStyle = UITableViewCellSelectionStyleNone;  
  22.     return cell;  
  23. }  
  24.   
  25. - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath  
  26. {  
  27.     return 460;  
  28. }  



InfoCell实现:

[cpp]  view plain copy print ?
  1. #import   
  2.   
  3. @interface InfoCell : UITableViewCell  
  4. {  
  5.     UITableView *hortable;  
  6. }  
  7.   
  8. @end  
  9.   
  10. @implementation InfoCell  
  11.   
  12. - (void)dealloc  
  13. {  
  14.     [super dealloc];  
  15. }  
  16. - (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier  
  17. {  
  18.     self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];  
  19.     if (self)  
  20.     {  
  21.         hortable = [[UITableView alloc]initWithFrame:CGRectMake(22, -22, 276, 320) style:UITableViewStylePlain];//由于使用了仿射变换,所以这里的frame显得很诡异,慢慢调吧~  
  22.         hortable.delegate = self;  
  23.         hortable.dataSource = self;  
  24.         hortable.layer.borderColor = [UIColor blackColor].CGColor;  
  25.         hortable.layer.borderWidth = 1;  
  26.         hortable.transform = CGAffineTransformMakeRotation(M_PI / 2 *3);  
  27.         hortable.separatorColor = [UIColor redColor];  
  28.         hortable.decelerationRate = UIScrollViewDecelerationRateFast;  
  29.         hortable.showsHorizontalScrollIndicator = NO;  
  30.         hortable.showsVerticalScrollIndicator = NO;  
  31.         [self addSubview:hortable];  
  32.    }  
  33.     return self;  
  34. }  
  35.   
  36. - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section  
  37. {  
  38.         return 5;  
  39.  }  
  40.   
  41.   
  42. - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath  
  43. {  
  44.       
  45.     NSString *CellIdentifier = [NSString stringWithFormat:@"cell%d",indexPath.row];  
  46.     UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];  
  47.     if (cell == nil)  
  48.     {  
  49.         cell = [[[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier]autorelease];  
  50.         cell.transform = CGAffineTransformMakeRotation(M_PI/2);  
  51.     }   
  52.       
  53.        //在这里添加你的view,就是那些UITableView,注意,关键在这里:如果添加到cell上的table需要下拉刷新,如果不想滑动时间出现冲突,要保证cell上的UITableView的contentoffset 不等于0和不便宜到最底部,这样下拉刷新才没有问题,例如 当contentoffset.y = 0时候,使其等于1。不然背景的table就会跟着一起滚动,达不到下拉刷新的效果  
  54.   
  55.     return cell;  
  56. }  
  57.   
  58. - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath  
  59. {  
  60.     return 320;  
  61. }  
  62.   
  63. - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath  
  64. {  
  65.     NSLog(@"点击%d",[indexPath row]);  
  66. }  
  67.   
  68. - (void)setSelected:(BOOL)selected animated:(BOOL)animated  
  69. {  
  70.     [super setSelected:selected animated:animated];  
  71. }  
  72.   
  73. @end  

这样就解决了开始的问题了!

最上层的TableView如果下拉刷新有问题,需要修复偏移量,可以参考如下代码:

- (void) correctOffSetForDownPull

{

    if (self.tableView.contentOffset.y ==0) {

        self.tableView.contentOffset =CGPointMake(0,1);

    }

    if (self.tableView.contentOffset.y == (self.tableView.contentSize.height -self.tableView.frame.size.height)) {

        self.tableView.contentOffset =CGPointMake(0, (self.tableView.contentSize.height -self.tableView.frame.size.height) -1);

    }

}


其中横向UITableView需要pageEnable效果,如下方法可以实现:

-(void)scrollViewWillEndDragging:(UIScrollView*)scrollView withVelocity:(CGPoint)velocity targetContentOffset:(inoutCGPoint*)targetContentOffset {

    // Variables

    CGPoint offset              = (*targetContentOffset);

    NSIndexPath* indexPath      = [hortableindexPathForRowAtPoint:(*targetContentOffset)];  // Get index path for target row

    int numberOfRow = [selftableView:(UITableView *)scrollViewnumberOfRowsInSection:(NSInteger)indexPath.section];

    

    /* Find closest row at *targetContentOffset */

    

    // Row at *targetContentOffset

    CGRect rowRect      = [hortablerectForRowAtIndexPath:indexPath];

    

    // temporary assign

    selectedIndexPath = indexPath;

    CGRect targetRect   = rowRect;

    

    

    // Next Row

    if (indexPath.row < numberOfRow -1 ){

        NSIndexPath *nextPath   = [NSIndexPathindexPathForRow: indexPath.row +1 inSection: indexPath.section];

        CGRect nextRowRect      = [hortablerectForRowAtIndexPath: nextPath];

        

        // Compare distance

        // if next row is closer, set target rect

        if (fabs(offset.y -CGRectGetMinY(nextRowRect)) <fabs(offset.y -CGRectGetMinY(rowRect))){

            targetRect          = nextRowRect;

            selectedIndexPath   = nextPath;

        }

    }

    

    /* Centering */

    offset = targetRect.origin;

    if (self.centering){

        offset.y -= (hortable.bounds.size.height *0.5 - targetRect.size.height *0.5);

    }

    

    // Assign return value

    (*targetContentOffset) = offset;

    

    // Snap speed

    // it seems it's better set it slow when the distance of target offset and current offset is small to avoid abrupt jumps

    float currentOffset = hortable.contentOffset.y;

    float rowH = targetRect.size.height;

    static const float thresholdDistanceCoef  = 0.25;

    if (fabs(currentOffset - (*targetContentOffset).y) > rowH * thresholdDistanceCoef){

        hortable.decelerationRate =UIScrollViewDecelerationRateFast;

    } else {

        hortable.decelerationRate =UIScrollViewDecelerationRateNormal;

    }


到现在为止几乎接近完美了~

你可能感兴趣的:(ios)