iOS利用余弦函數(shù)實(shí)現(xiàn)卡片瀏覽工具
本文實(shí)例為大家分享了iOS利用余弦函數(shù)實(shí)現(xiàn)卡片瀏覽工具的具體代碼,供大家參考,具體內(nèi)容如下
一、實(shí)現(xiàn)效果
通過拖拽屏幕實(shí)現(xiàn)卡片移動,左右兩側(cè)的卡片隨著拖動變小,中間的變大。效果如下:
二、原理說明
1、上面的動畫效果是根據(jù)余弦函數(shù)的曲線特性實(shí)現(xiàn)的,先看一下函數(shù)曲線y=cos(x),在區(qū)間-π/2 到 π/2的范圍內(nèi),y的值在x的0的是后是最大的,左右則越來越小。
2、可以將被滾動的卡片的高度按照0.0~1.0的比例放大縮小,效果如下:
3、放置到手機(jī)屏幕上的效果如下:
三、代碼
封裝每個(gè)卡片為Card.h
卡片顯示在CardSwitchView.h上
代碼思路是假設(shè)控件的中心為原點(diǎn),中軸線為x軸和y軸,當(dāng)卡片的中心為距離y軸越近時(shí),卡片長度縮短的比例越趨近1.0,當(dāng)卡片中線距離y軸越遠(yuǎn)時(shí),卡片長度縮短的比例越趨近0;
如下圖所示假設(shè)方塊從位置1到位置2向左移動了長度a(寫代碼時(shí)需要做角度和長度的轉(zhuǎn)換),那么在曲線上b的值為cos(a),假設(shè)b=0.8,那么就在位置2的時(shí)候把高度縮短為原來的0.8倍,以此類推越趨近于控件中軸線的位置卡片越長。(這里角度和長度的轉(zhuǎn)換倍數(shù)依情況而定)
// // CardSwitchView.m // CardSwitchDemo // // Created by Apple on 2016/11/9. // Copyright © 2016年 Apple. All rights reserved. // #import "CardSwitchView.h" #import "Card.h" //播放器界面的的寬度所占的比例 static float viewScale = 0.70f; @interface CardSwitchView ()<UIScrollViewDelegate> { //用于切換的ScrollView UIScrollView *_scrollView; //用于保存各個(gè)視圖 NSMutableArray *_cards; //滾動之前的位置 CGFloat _startPointX; //滾動之后的位置 CGFloat _endPointX; //需要居中顯示的index NSInteger _currentIndex; } @end @implementation CardSwitchView -(instancetype)initWithFrame:(CGRect)frame { if (self = [super initWithFrame:frame]) { [self buildLayout]; } return self; } -(void)buildLayout { //初始化ScrollView _scrollView = [[UIScrollView alloc] initWithFrame:self.bounds]; _scrollView.delegate = self; _scrollView.showsHorizontalScrollIndicator = false; [self addSubview:_scrollView]; //初始化其他參數(shù) _cards = [[NSMutableArray alloc] init]; _currentIndex = 0; } #pragma mark - #pragma mark 視圖Frame配置 //卡片寬度 -(float)cardWidth { return viewScale*self.bounds.size.width; } //卡片間隔 -(float)margin { return (self.bounds.size.width - [self cardWidth])/4; } //卡片起始位置 -(float)startX { return (self.bounds.size.width - [self cardWidth])/2.0f; } #pragma mark - #pragma mark 配置輪播圖片 -(void)setCardNumber:(NSInteger)cardNumber { _cardNumber = cardNumber; //初始化各個(gè)播放器位置 for (NSInteger i = 0; i<cardNumber; i++ ) { //第一步 在ScrollView上添加卡片 float viewX = [self startX] + i*([self cardWidth] + [self margin]); Card* card = [[Card alloc] initWithFrame:CGRectMake(viewX, 0, [self cardWidth], self.bounds.size.height)]; card.layer.borderWidth = 1.0f; card.index = i; [_scrollView addSubview:card]; [_cards addObject:card]; [_scrollView setContentSize:CGSizeMake(card.frame.origin.x + [self cardWidth] + 2*[self margin], 0)]; } //更新卡片的大小 [self updateCardTransform]; } #pragma mark - #pragma mark ScrollView代理方法 //開始拖動時(shí)保存起始位置 -(void)scrollViewWillBeginDragging:(UIScrollView *)scrollView { _startPointX = scrollView.contentOffset.x; } //當(dāng)ScrollView拖動時(shí) 變換每個(gè)view的大小,并保證居中屏幕的view高度最高 -(void)scrollViewDidScroll:(UIScrollView *)scrollView { [self updateCardTransform]; } //滾動結(jié)束,自動回彈到居中卡片 -(void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate { //滾動到視圖中間位置 dispatch_async(dispatch_get_main_queue(), ^{ [self scrollToCurrentCard]; }); } //卡片自動居中 -(void)scrollToCurrentCard { _endPointX = _scrollView.contentOffset.x; //設(shè)置滾動最小生效范圍,滾動超過scrollMiniDistance 即視為有切換卡片的意向 float scrollMiniDistance = self.bounds.size.width/30.0f; if (_startPointX - _endPointX > scrollMiniDistance) { NSLog(@"向右滑動屏幕"); if (_currentIndex != 0) { _currentIndex -= 1; } }else if (_endPointX - _startPointX > scrollMiniDistance) { NSLog(@"向左滑動屏幕"); if (_currentIndex != _cards.count - 1) { _currentIndex += 1; } } float viewX = [self startX] + _currentIndex*([self cardWidth] + [self margin]); float needX = viewX - [self startX]; [_scrollView setContentOffset:CGPointMake(needX, 0) animated:true]; } //更新每個(gè)卡片的大小 -(void)updateCardTransform { for (Card *card in _cards) { //獲取卡片所在index //獲取ScrollView滾動的位置 CGFloat scrollOffset = _scrollView.contentOffset.x; //獲取卡片中間位置滾動的相對位置 CGFloat cardCenterX = card.center.x - scrollOffset; //獲取卡片中間位置和父視圖中間位置的間距,目標(biāo)是間距越大卡片越短 CGFloat apartLength = fabs(self.bounds.size.width/2.0f - cardCenterX); //移動的距離和屏幕寬度的的比例 CGFloat apartScale = apartLength/self.bounds.size.width; //把卡片移動范圍固定到 -π/4到 +π/4這一個(gè)范圍內(nèi) CGFloat scale = fabs(cos(apartScale * M_PI/4)); //設(shè)置卡片的縮放 card.transform = CGAffineTransformMakeScale(1.0, scale); } } @end
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
iOS實(shí)現(xiàn)的多條折線圖封裝實(shí)例
這篇文章主要跟大家分享了關(guān)于利用iOS實(shí)現(xiàn)多條折線圖的封裝實(shí)例,文中給出了詳細(xì)的示例代碼供大家參考學(xué)習(xí),對大家具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來一起看看吧。2017-07-07UITextView實(shí)現(xiàn)只允許鏈接交互不允許選擇圖片的方法
這篇文章主要介紹了UITextView實(shí)現(xiàn)只允許鏈接交互不允許選擇圖片的方法,文中介紹的非常詳細(xì),相信對大家具有一定的參考價(jià)值,需要的朋友們下面來一起看看吧。2017-03-03使用IOS AirPrint實(shí)現(xiàn)打印功能詳解
這篇文章主要介紹了使用IOS AirPrint實(shí)現(xiàn)打印功能詳解,想了解無線打印的同學(xué),一定要看一下2021-04-04詳解iOS中多線程app開發(fā)的GCD隊(duì)列的使用
這篇文章主要介紹了詳解iOS中多線程app開發(fā)的GCD隊(duì)列的使用,代碼基于傳統(tǒng)的Objective-C,需要的朋友可以參考下2015-12-12iOS TableView頭視圖根據(jù)偏移量下拉縮放效果
這篇文章主要為大家詳細(xì)介紹了iOS TableView頭視圖根據(jù)偏移量下拉縮放效果,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-05-05iOS開發(fā)APP跳轉(zhuǎn)到設(shè)置或系統(tǒng)頁面詳解
這篇文章主要為大家介紹了iOS開發(fā)APP跳轉(zhuǎn)到設(shè)置或系統(tǒng)頁面詳解,<BR>有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-06-06