IOS开发~UISCrollView与UITableView嵌套使用终极解决方案

论坛 期权论坛 脚本     
匿名技术用户   2020-12-21 13:32   34   0

问题由来:项目需要做类似网易新闻的那种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:

//实现Table
CGRect scrollRect = CGRectMake(0, 0, 320, 460);
self.tableBgScroll = [[[UITableView alloc] initWithFrame:scrollRect style:UITableViewStylePlain] autorelease];
[self.tableBgScroll setDelegate:self];
[self.tableBgScroll setDataSource:self];

//Table的数据源方法
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    return 1;
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
 static NSString *cellname = @"cell";
    InfoCell *cell = (InfoCell *)[tableView dequeueReusableCellWithIdentifier:cellname];
    if (cell == nil)
    {
        cell = [[[InfoCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellname]autorelease];
 }
    cell.selectionStyle = UITableViewCellSelectionStyleNone;
    return cell;
}

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



InfoCell实现:

#import <UIKit/UIKit.h>

@interface InfoCell : UITableViewCell<UITableViewDataSource, UITableViewDelegate>
{
    UITableView *hortable;
}

@end

@implementation InfoCell

- (void)dealloc
{
    [super dealloc];
}
- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
    self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
    if (self)
    {
        hortable = [[UITableView alloc]initWithFrame:CGRectMake(22, -22, 276, 320) style:UITableViewStylePlain];//由于使用了仿射变换,所以这里的frame显得很诡异,慢慢调吧~
        hortable.delegate = self;
        hortable.dataSource = self;
        hortable.layer.borderColor = [UIColor blackColor].CGColor;
        hortable.layer.borderWidth = 1;
        hortable.transform = CGAffineTransformMakeRotation(M_PI / 2 *3);
        hortable.separatorColor = [UIColor redColor];
        hortable.decelerationRate = UIScrollViewDecelerationRateFast;
        hortable.showsHorizontalScrollIndicator = NO;
        hortable.showsVerticalScrollIndicator = NO;
  [self addSubview:hortable];
   }
    return self;
}

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


- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
 
    NSString *CellIdentifier = [NSString stringWithFormat:@"cell%d",indexPath.row];
 UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
 if (cell == nil)
    {
        cell = [[[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier]autorelease];
        cell.transform = CGAffineTransformMakeRotation(M_PI/2);
    } 
    
       //在这里添加你的view,就是那些UITableView,注意,关键在这里:如果添加到cell上的table需要下拉刷新,如果不想滑动时间出现冲突,要保证cell上的UITableView的contentoffset 不等于0和不便宜到最底部,这样下拉刷新才没有问题,例如 当contentoffset.y = 0时候,使其等于1。不然背景的table就会跟着一起滚动,达不到下拉刷新的效果

    return cell;
}

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

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
    NSLog(@"点击%d",[indexPath row]);
}

- (void)setSelected:(BOOL)selected animated:(BOOL)animated
{
    [super setSelected:selected animated:animated];
}

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

}

}


到现在为止几乎接近完美了~
分享到 :
0 人收藏
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

积分:7942463
帖子:1588486
精华:0
期权论坛 期权论坛
发布
内容

下载期权论坛手机APP