iOS 探探首頁(yè)的卡片切換效果

效果圖:

tantan.gif

最近公司要求寫一個(gè)類似于探探的項(xiàng)目,在網(wǎng)上找了半天也沒(méi)有找到合適的dome,所以就自己寫了一個(gè)dome,希望能夠幫到大家

步驟:
1.實(shí)現(xiàn)左右滑動(dòng)
2.實(shí)現(xiàn)刪除或者還原
3.實(shí)現(xiàn)左右旋轉(zhuǎn)
4.實(shí)現(xiàn)卡片的替換
5.實(shí)現(xiàn)實(shí)現(xiàn)卡片的跟隨

首先自定義view實(shí)現(xiàn)1、2、3功能

這里用到了UIView的類別的方法

//UIView類別里的方法
-(void)addPanAction:(SEL)action{
    UIPanGestureRecognizer *pan = [[UIPanGestureRecognizer alloc]initWithTarget:self action:action];
    [self addGestureRecognizer:pan];
}

自定義UIView

moreView.h

@protocol moreViewdelegate <NSObject>

//移動(dòng)的距離
-(void)moreVolue:(CGFloat)volue;
//視圖是否被移除
-(void)moreisRemove:(BOOL)isRemove;

@optional

@end

@interface moreView : UIView{
    CGPoint point;//保存點(diǎn)擊初始位置
    CGRect rect;//保存視圖初始位置
}

//喜歡
@property (nonatomic, weak) UILabel * xh;
//不喜歡
@property (nonatomic, weak) UILabel * bxh;
//協(xié)議
@property(weak ,nonatomic)id<moreViewdelegate>delegates;

兩個(gè)協(xié)議方法是后面實(shí)現(xiàn)4、5需要用到的方法
兩個(gè)UIlabel是在視圖上面的子控件(看需求添加)
point成員變量是保存初始點(diǎn)擊的位置(用于實(shí)現(xiàn)讓圖片跟隨手指滑動(dòng))
rect成員變量是保存視圖的初始位置(用于還原到原來(lái)的位置)

華麗的分割線==================================

moreView.m

- (instancetype)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self) {
//        self.backgroundColor = [UIColor whiteColor];
        
        //布局UI
        [self LayoutUI];
        
        
        //添加拖動(dòng)按鈕
        self.userInteractionEnabled = NO;

        //這里是一個(gè)UIView的類別添加滑動(dòng)的方法
        [self addPanAction:@selector(panAction:)];
    }
    return self;
}

-(void)panAction:(UIPanGestureRecognizer *)pan{
    UIView * view = (UIView *)pan.view;
    
    if (pan.state == UIGestureRecognizerStateBegan) {
        
        //存儲(chǔ)準(zhǔn)備開(kāi)始滑動(dòng)的坐標(biāo)
        
        point = [pan locationInView: [view superview] ];
        
        rect = view.frame;
        
        
    }else if (pan.state == UIGestureRecognizerStateChanged){
        //監(jiān)聽(tīng)滑動(dòng)的距離并改變view的位置
        
        CGRect rects = rect;
        
        CGFloat x = [pan locationInView:[view superview]].x - point.x;
        
        CGFloat y = [pan locationInView:[view superview]].y - point.y;
        
        rects.origin = CGPointMake(rect.origin.x + x, rect.origin.y + y);
        
        view.frame = rects;
        
        //判斷是否劃出制定區(qū)域
        
        if (view.center.x > YBJ_ScreenW || view.center.x < 0 || view.center.y > YBJ_ScreenH || view.center.y < 0){
            if (view.center.x > YBJ_ScreenW) {
                self.xh.alpha = 1;
            }
            if (view.center.x < 0) {
                self.bxh.alpha = 1;
            }
            return;
        }
        
        //監(jiān)聽(tīng)滑動(dòng)的比例控制動(dòng)畫以及喜歡
        
        CGFloat xx = (view.center.x-(view.width/2))/(view.width/2);
        
        if (xx<0) {
            self.bxh.alpha = fabs(xx);
        }else{
            self.xh.alpha = fabs(xx);
        }
        
        [self viewAnimationfloat:(xx * 0.05)];
        
        [self.delegates moreVolue:xx];
        
        
    }else if (pan.state == UIGestureRecognizerStateEnded || pan.state == UIGestureRecognizerStateFailed){
        
        
        //判斷是松手時(shí)是否劃出制定區(qū)域
        if (view.center.x > YBJ_ScreenW || view.center.x < 0 || view.center.y > YBJ_ScreenH || view.center.y < 0) {
            [self removeFromSuperview];
            [self.delegates moreisRemove:YES];
        }else{
            
            [self.delegates moreisRemove:NO];
            [UIView animateWithDuration:0.2 animations:^{
                self.xh.alpha = 0;
                self.bxh.alpha = 0;
                view.frame = self->rect;
                [self viewAnimationfloat:0];
            }];
        }
    }
}

//CABasicAnimation動(dòng)畫
-(void)viewAnimationfloat:(CGFloat)f{
    
    //根據(jù)z軸旋轉(zhuǎn)
    CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"transform.rotation.z"];
    animation.toValue = [NSNumber numberWithFloat: M_PI * f];
    animation.duration = 0.2f;
    animation.autoreverses = NO;
    animation.removedOnCompletion = NO;
    animation.fillMode = kCAFillModeForwards;
    animation.repeatCount = 0;
    [self.layer addAnimation:animation forKey:nil];
    
}

1、LayoutUI這個(gè)方法是用于UI布局子控件用的。
2、因?yàn)橹荒芤苿?dòng)一張視圖所以我們先將view的用戶交互關(guān)掉。
3、在panAction:方法中先獲取到自身(用于對(duì)自身做相應(yīng)的處理)。
4、state剛點(diǎn)擊下來(lái)我們就存儲(chǔ)point 和 rect。
5、state開(kāi)始滑動(dòng)時(shí)需要通過(guò)point實(shí)現(xiàn)圖片跟隨。
6、設(shè)置指定范圍用于控制喜歡和不喜歡控件(如果超出范圍就return)。
7、沒(méi)有超出范圍就通過(guò)滑動(dòng)的比例控制喜歡喝不喜歡的透明度
8、并且讓view有左右旋轉(zhuǎn)的功能。
9、viewAnimationfloat:這個(gè)方法是通過(guò)比例決定旋轉(zhuǎn)的角度。
10、并且通過(guò)moreVolue:這個(gè)協(xié)議方法傳遞移動(dòng)的比例(用于5的處理)。
11、state松手時(shí)可通過(guò)制定的區(qū)域來(lái)決定還原還是刪除。
12、當(dāng)滑動(dòng)區(qū)域超過(guò)制定范圍就刪除該視圖(這里可以添加一個(gè)往左移動(dòng)的動(dòng)畫)。
13、并且通過(guò)moreisRemove:這個(gè)協(xié)議方法傳遞是否劃出制定范圍(用于4的處理)。
14、沒(méi)有超過(guò)就還原到初始狀態(tài)。
15、并且通過(guò)moreisRemove:這個(gè)協(xié)議方法傳遞是否劃出制定范圍(用于4的處理)。

華麗的分割線==============================

調(diào)用moreView實(shí)現(xiàn)4、5功能

Frame(x,y,width,height)這個(gè)宏是本人用于適配的(請(qǐng)自行改為自己的CGRectMake)

moreView調(diào)用

moreViewController.m

#import "moreViewController.h"

#import "moreView.h"

#define baseFrame Frame(38,Height_NavBar + YBJ_ScreenW6(25),300,425)

#define Frame1 Frame(0,0,300,400)

#define Frame2 Frame(3,8,300-6,400)

#define Frame3 Frame(6,16,300-12,400)

#define Frame4 Frame(9,24,300-18,400)


@interface moreViewController ()<moreViewdelegate>
//背景視圖
@property (weak , nonatomic)UIView * baseView;
//數(shù)據(jù)數(shù)組
@property (strong ,nonatomic)NSMutableArray * dataArr;
//more數(shù)組(視圖)
@property (strong ,nonatomic)NSMutableArray * moreArr;
//位置數(shù)組(ps:因?yàn)槲恢貌荒艽娴綌?shù)組需要轉(zhuǎn)換,就沒(méi)有用到)
@property (strong ,nonatomic)NSMutableArray * FrameArr;

@end

@implementation moreViewController

-(NSMutableArray *)dataArr{
    if (!_dataArr) {
        _dataArr = [NSMutableArray new];
        [_dataArr addObject:[UIColor redColor]];
        [_dataArr addObject:[UIColor orangeColor]];
        [_dataArr addObject:[UIColor grayColor]];
        [_dataArr addObject:[UIColor brownColor]];
        [_dataArr addObject:[UIColor greenColor]];
        [_dataArr addObject:[UIColor purpleColor]];
        [_dataArr addObject:[UIColor redColor]];
        [_dataArr addObject:[UIColor orangeColor]];
        [_dataArr addObject:[UIColor grayColor]];
        [_dataArr addObject:[UIColor brownColor]];
        [_dataArr addObject:[UIColor greenColor]];
        [_dataArr addObject:[UIColor purpleColor]];
    }
    return _dataArr;
}

-(NSMutableArray *)moreArr{
    if (!_moreArr) {
        _moreArr = [NSMutableArray new];
    }
    return _moreArr;
}

-(NSMutableArray *)FrameArr{
    if (!_FrameArr) {
        _FrameArr = [NSMutableArray new];
        
    }
    return _FrameArr;
}

- (void)viewDidLoad {
    [super viewDidLoad];
    
    //創(chuàng)建父視圖
    
    [self setBaseView];
//    [self addChildView];
}

/**
 創(chuàng)建父視圖
 */

-(void)setBaseView{
    
    UIView * baseView = [[UIView alloc]initWithFrame:baseFrame];
    [self.view addSubview:baseView];
    baseView.backgroundColor = [UIColor whiteColor];
    _baseView = baseView;
    
    for (int i = 0; i < 5 ; i++) {
        
        [self addChildView:i];
    }
}

/**
 添加子試圖
 */

-(void)addChildView:(NSInteger)i{
    
    if (self.dataArr.count == 0) {
        return;
    }
    
    moreView * more = [[moreView alloc]initWithFrame:CGRectMake(0+YBJ_ScreenW6(3*i), 0+8*i, YBJ_ScreenW6(300-(6*i)), YBJ_ScreenW6(400))];
    
    more.backgroundColor = self.dataArr[0];
    
    if (i == 0) {
        more.userInteractionEnabled = YES;
    }
    
    more.tag = i+10;
    
    switch (i) {
        case 0:
            more.frame = Frame1;
            break;
        case 1:
            more.frame = Frame2;
            break;
        case 2:
            more.frame = Frame3;
            break;
        case 3:
            more.frame = Frame4;
            break;
            
        default:
            more.frame = Frame4;
            break;
    }
    
    
    more.delegates = self;
    
    [self.baseView addSubview:more];
    
    [self.baseView sendSubviewToBack:more];
    
    [self.moreArr addObject:more];
    
    [self.dataArr removeObjectAtIndex:0];
    
}
/**
 moredelegates代理
 */
-(void)moreVolue:(CGFloat)volue{
    
    NSLog(@"%f",volue);
    
    for (UIView * tepView in self.moreArr) {
        
        moreView * more = (moreView *)tepView;
        
        CGRect rect = CGRectZero;
        
        switch (more.tag-10) {
            case 0:
                
                break;
            case 1:
                rect = Frame2;
                rect.origin.x -= YBJ_ScreenW6(3*fabs(volue));
                rect.origin.y -= YBJ_ScreenW6(8*fabs(volue));
                rect.size.width += YBJ_ScreenW6(6*fabs(volue));
                more.frame = rect;
                break;
            case 2:
                rect = Frame3;
                rect.origin.x -= YBJ_ScreenW6(3*fabs(volue));
                rect.origin.y -= YBJ_ScreenW6(8*fabs(volue));
                rect.size.width += YBJ_ScreenW6(6*fabs(volue));
                more.frame = rect;
                break;
            case 3:
                rect = Frame4;
                rect.origin.x -= YBJ_ScreenW6(3*fabs(volue));
                rect.origin.y -= YBJ_ScreenW6(8*fabs(volue));
                rect.size.width += YBJ_ScreenW6(6*fabs(volue));
                more.frame = rect;
                break;
                
            default:
                
                break;
        }
        
        
        
    }
    
}

-(void)moreisRemove:(BOOL)isRemove{
    if (isRemove) {
        
        [self.moreArr removeObjectAtIndex:0];
        
        
        if (self.moreArr.count == 0) {
            NSLog(@"沒(méi)有了!");
        }
        
        for (UIView * tepView in self.moreArr) {
            
            moreView * more = (moreView *)tepView;
        
            more.tag -= 1;
            
            if (more.tag-10 == 0) {
                more.userInteractionEnabled = YES;
            }
            
        }
        [self addChildView:4];
        
    }else{
        for (UIView * tepView in self.moreArr) {
            
            moreView * more = (moreView *)tepView;
            
            switch (more.tag - 10) {
                case 0:
                    
                    break;
                case 1:
                    more.frame = Frame2;
                    break;
                case 2:
                    more.frame = Frame3;
                    break;
                case 3:
                    more.frame = Frame4;
                    break;
                    
                default:
                    break;
            }
        }
    }
}

1、上面一些宏定義分別為:背景、第一個(gè)、第二個(gè)、第三個(gè)、第四個(gè)~視圖的位置(請(qǐng)自行更改)。
2、上面一些屬性分別為:背景視圖、數(shù)據(jù)數(shù)組(這里添加了幾條顏色數(shù)據(jù))、more數(shù)組(視圖)、位置數(shù)組(ps:因?yàn)槲恢貌荒艽娴綌?shù)組需要轉(zhuǎn)換,就沒(méi)有用到)。
3、setBaseView是創(chuàng)建父視圖(用于做moreView的容器,設(shè)置屬性是劃完后能夠remove,并且重新加載視圖)。
4、利用for循環(huán)來(lái)創(chuàng)建moreView(這里用了5個(gè),因?yàn)橛兴膫€(gè)view的位置,所以留最后留一張墊底)。
5、addChildView:這個(gè)方法是利用傳遞的i來(lái)設(shè)定tag值,并且設(shè)置位置,用moreArr存儲(chǔ)moreView,sendSubviewToBack:這個(gè)方法將新添加的moreView放到最下面,然后刪除dataArr中的第一個(gè)數(shù)據(jù)(當(dāng)dataArr為空的時(shí)候就return)。
6、moreViewdelegate簽訂協(xié)議(分別為:moreisRemove: 和 moreVolue: )。
7、moreVolue: 通過(guò)這個(gè)協(xié)議方法實(shí)現(xiàn)5的效果,便利moreArr取出moreView,改變其frame實(shí)現(xiàn)跟隨效果。
8、moreisRemove: 通過(guò)這個(gè)協(xié)議4的效果。
isRemove為真:
moreArr刪除第一個(gè)元素,便利moreArr取出moreView,改變其tag,讓tag值-1,并且把第一個(gè)view改為可交互狀態(tài),再用addChildView:這個(gè)方法在底部添加一個(gè)moreView(當(dāng)moreArr為空時(shí)就可以刪除背景視圖執(zhí)行下一環(huán)節(jié)了)
isRemove為假:
便利moreArr取出moreView通過(guò)tag將其還原。

end

ps:因?yàn)閙oreView在滑動(dòng)的后有還原操作,所以不需要還原。

喜歡的小伙伴們可以點(diǎn)個(gè)??加個(gè)關(guān)注?。?!

有問(wèn)題的小伙伴私信我!GitHub/YBJTantan

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 1、通過(guò)CocoaPods安裝項(xiàng)目名稱項(xiàng)目信息 AFNetworking網(wǎng)絡(luò)請(qǐng)求組件 FMDB本地?cái)?shù)據(jù)庫(kù)組件 SD...
    陽(yáng)明AI閱讀 16,211評(píng)論 3 119
  • 026自我陶醉式的吹噓是沒(méi)有聽(tīng)眾的 老是自我陶醉式的吹噓、曬幸福。在優(yōu)秀的人眼里,這只等于"淺薄",身邊的人只會(huì)對(duì)...
    Muscle_4329閱讀 316評(píng)論 0 0
  • 雅思寫作怎樣體現(xiàn)邏輯性?聽(tīng)力最好的鍛煉方式是什么?閱讀怎么做?說(shuō)的部分怎么說(shuō)? ?呈現(xiàn)邏輯性的寫作 通過(guò)段與段之間...
    東日晨閱讀 242評(píng)論 0 0
  • 今天順利考完了英語(yǔ)A級(jí),心情有一種釋放的小感覺(jué),不過(guò)頭等戲還在前方,因?yàn)橄轮艿挠?jì)算機(jī)二級(jí)、普通話也很快奔駕而來(lái)。 ...
    慢就是快的追夢(mèng)女孩閱讀 535評(píng)論 3 3

友情鏈接更多精彩內(nèi)容