iOS之卡片模式設計和實現
阿新 • • 發佈:2019-02-02
卡片效果花樣很多,每個人都有自己的想法來實現更好的動態效果,從而達到更好的使用者體驗;以下就是寫出的卡片翻頁效果要求:
(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];
(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&¤tIndex-3<i){
moveCardView.alpha = alpha;
}
else{
moveCardView.alpha = 0;
}
}
//代理滾動時回撥函式
if([self.delegate respondsToSelector:@selector(slideCardViewDidScrollAllPage:AndIndex:)])
[self.delegate slideCardViewDidScrollAllPage:_cardDataArray.count-1 AndIndex:_index];
}