[セットトップ]IOS開発~UIsCrollViewとUItableViewネストによる究極のソリューションの使用

7180 ワード

質問の由来:プロジェクトは網易ニュースのようなUIscrollViewに複数のUItableViewを置く効果が必要で、UItableViewにはドロップダウン・リフレッシュ効果もあります.
最初の構想は、最も直感的な構想であり、UIscrollViewに複数のUItableViewを配置し、UItableViewのスライドとUIscrollViewのスライドが衝突し、ユーザー体験が悪いことを発見した.主な原因はUIscrollViewのスライド原理にある.
基礎知識はここを見てください.
http://snorlax.sinaapp.com/?p=178
http://www.devdiv.com/forum.php?mod=viewthread&tid=197496
この2つをまとめると、UITAbleViewをドロップダウンしてリフレッシュコンポーネントを表示させるにはUIscrollViewをスクロールさせることはできない(scrollEnabled=NO)、並べて表示されている他のUITAbleViewを左右にスライドさせるにはUIscrollViewをスクロールさせる必要があるが、ユーザーがどのように操作したいのか、どうやって知るのかという問題がある.だからこの道は通じない.(スライド可能でも、製品のニーズにははるかに及ばない)
一つのUItableViewを背景にしていますが、このUItableViewには1つのcellしかありません.そして、このcellに横のUItableViewを1つ、そしてこの横の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

これで最初の問題が解決しました!
最上位レベルのTable Viewドロップダウン・リフレッシュに問題がある場合は、オフセットを修正する必要があります.次のコードを参照してください.
- (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))             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;
    }
}
今までほぼ完璧に近い~