1. 程式人生 > >iOS之卡片模式設計和實現

iOS之卡片模式設計和實現

卡片效果花樣很多,每個人都有自己的想法來實現更好的動態效果,從而達到更好的使用者體驗;以下就是寫出的卡片翻頁效果要求:
(1).靜態的頁面有三張卡片遞進疊加;
(2).當手勢向下滑動卡片時,當前卡片向下滑出,上一層卡片遞進滑到上一層;
(3).當手勢向上滑卡片時,當前卡片向上一層滑入底層檢視,底部滑出卡片進入當前頁(不為第一張卡片時)。

程式碼實現過程

1.手勢滑動部分:通過新增UIScrollView類實現,只在UIScrollView檢視上新增一個卡片檢視,用於視覺化滑動效果,並且通過協議UIScrollViewDelegate的代理方法捕獲滑動事件

(1)設定UIScrollView控制元件

//設定滑動檢視的頁數
_mainScrollView.contentSize = _cardDataArray.count>1 ? CGSizeMake(width, viewSize.height*_cardDataArray.count):CGSizeMake(width, viewSize.height*_cardDataArray.count+1);

//這裡需要注意一點,數組裡的第一個卡片資料,應該放在UIScrollView類的最後一頁
_mainScrollView.contentOffset = CGPointMake(0, (_cardDataArray.count-1)* viewSize.height
);

(2)新增卡片檢視到UIScrollView類,第一張卡片放在最後一頁,向下滑彈出第二頁,類推…

//座標(第一張卡片放在最後一頁)
CGPoint point = CGPointMake(0, (_cardDataArray.count-1)*viewSize.height);

//例項化CardView
CardView *card = [[NSBundle mainBundle] loadNibNamed:@"CardView" owner:self options:nil].firstObject;
card.frame=CGRectMake(point.x, point.y, viewSize.width
, viewSize.height-58); card.backgroundColor = [UIColor whiteColor]; card.layer.masksToBounds = YES; card.layer.cornerRadius = 5.0;//設定圓角 [card loadCardViewWithDictionary:_cardDataArray[0]]; //新增點選事件(用於判定選中卡片事件) UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(showSelectCardViewAction)]; [card addGestureRecognizer:tap]; //新增到檢視與陣列中(_slideCardViewArray用於儲存當前滑動的檢視) [_slideCardViewArray insertObject:card atIndex:0]; [_mainScrollView addSubview:card];

2.卡片疊加檢視部分,採用三張卡片依次疊加在一起,在通過監聽滑動事件來跟隨的改變座標的縮放效果

(1)新增底部檢視,設定特定重疊引數

//初始化底部檢視
_bottomView = [[UIView alloc]initWithFrame:frame];
_bottomView.backgroundColor = [UIColor clearColor];
_bottomView.layer.cornerRadius = 5.0;

//設定疊加檢視的透視投影(這一步很重要)
CATransform3D sublayerTransform = CATransform3DIdentity;//單位矩陣
sublayerTransform.m34 = -0.002;
[_bottomView.layer setSublayerTransform:sublayerTransform];

CATransform3D引數詳解

(2)在底部檢視上新增卡片(預設新增十張)

#pragma mark- 初始化卡片疊加檢視
-(void)loadBottomView
{
    //新增卡片資料時不再初始化底部疊加檢視
    if (_cardDataArray.count>10) {
        return;
    }

    float width = self.frame.size.width;
    float height = self.frame.size.height;

    //初始化四張卡片(如果要顯示的卡片>4,否則就初始化顯示的卡片張數)
    for(int i=0; i<(_cardDataArray.count<4?_cardDataArray.count:4); i++)
    {
        //設定CardView的座標,z值和透明度
        CGPoint point = CGPointMake(0, -i*height/_xMarginValue);
        float zPosition = -i*height/_zMarginValue;

        //例項化CardView
        CardView *card = [[NSBundle mainBundle] loadNibNamed:@"CardView" owner:self options:nil].firstObject;
        card.frame=CGRectMake(point.x, point.y, width,height-58);
        card.backgroundColor = [UIColor whiteColor];
        card.layer.masksToBounds = YES;
        card.layer.cornerRadius = 5.0;
        [card loadCardViewWithDictionary:_cardDataArray[i]];

        if (i<3) {
            card.layer.zPosition = zPosition; // Z座標
            card.alpha = 1;
        }
        else{
            card.layer.zPosition = -288; // Z座標
            card.alpha = 0;
        }

        //新增到檢視與陣列中
        if(i == 0){
            card.hidden = YES;
        }

        [_cardViewArray insertObject:card atIndex:0];
        [_bottomView addSubview:card];
    }
}

3.實現主要代理方法——scrollViewDidScroll:

#pragma mark- UIScrollViewDelegate
- (void) scrollViewDidScroll:(UIScrollView *)scrollView //滾動時處理
{
    CGFloat offset_y = scrollView.contentOffset.y;//scrollView所在位置
    CGFloat height = scrollView.frame.size.height;//高度
    CGFloat width = scrollView.frame.size.width;//檢視寬度
    CGFloat currentIndex = offset_y/height;//當前標籤

    //得到索引
    _index = currentIndex>(int)currentIndex?(int)currentIndex+1:(int)currentIndex;

    if (_index>_cardDataArray.count-1) {
        _index = (int)_cardDataArray.count-1;
    }

    //調整滾動檢視圖片的角度
    CardView* scrollCardView = [_slideCardViewArray firstObject];

    //表示處於當前檢視內
    if(scrollCardView.frame.origin.y<offset_y)
    {
        if(offset_y>_cardDataArray.count*height-height){
            scrollCardView.hidden = YES;
        }else{
            scrollCardView.hidden = NO;
            scrollCardView.frame = CGRectMake(0, _index*height, scrollCardView.frame.size.width, scrollCardView.frame.size.height);
            [scrollCardView loadCardViewWithDictionary:_cardDataArray[_cardDataArray.count-1-_index]];
        }
    }
    else if(scrollCardView.frame.origin.y-height<offset_y&&offset_y<=scrollCardView.frame.origin.y)
    {
        scrollCardView.hidden = NO;
    }
    else
    {
        scrollCardView.frame = CGRectMake(0, _index*height, scrollCardView.frame.size.width, scrollCardView.frame.size.height);
        [scrollCardView loadCardViewWithDictionary:_cardDataArray[_cardDataArray.count-1-_index]];
    }

    NSInteger _select = _index-3>0?(_index-3):0;

    for (NSInteger i=_select; i<=_index; i++) {
        //調整滾動檢視圖片的角度
        float currOrigin_y = i * height; //當前圖片的y座標

        //調整疊加檢視
        CardView* moveCardView = [_cardViewArray objectAtIndex:i-_select];
        [moveCardView loadCardViewWithDictionary:_cardDataArray[_cardDataArray.count-1-i]];

        float range_y = (currOrigin_y - offset_y)/(_xMarginValue) ;

        moveCardView.frame = CGRectMake(0, range_y, width, height-58);

        if(range_y >= 0) // 如果超過當前滑動檢視便隱藏
            moveCardView.hidden = YES;
        else
        {
            moveCardView.hidden = NO;
        }

        //調整彈壓檢視的z值
        float range_z = -(offset_y-currOrigin_y)/_zMarginValue;

        moveCardView.layer.zPosition = range_z;

        //調整彈壓檢視的透明度
        float alpha = 1.f + (currOrigin_y-offset_y)/_alphaValue;

        if (currentIndex-2<=i && i<=currentIndex) {
            moveCardView.alpha = 1;
        }else if(currentIndex-2>i&&currentIndex-3<i){
            moveCardView.alpha = alpha;
        }
        else{
            moveCardView.alpha = 0;
        }
    }

    //代理滾動時回撥函式
    if([self.delegate respondsToSelector:@selector(slideCardViewDidScrollAllPage:AndIndex:)])
        [self.delegate slideCardViewDidScrollAllPage:_cardDataArray.count-1 AndIndex:_index];
}

這裡寫圖片描述