国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 系統(tǒng) > iOS > 正文

iOS實(shí)現(xiàn)日歷翻頁動(dòng)畫

2020-07-26 03:17:25
字體:
供稿:網(wǎng)友

本文我主要描述兩方面:

    1.日歷(簡單描述原理)

    2.翻頁動(dòng)畫(重點(diǎn))

最終的效果如下圖:

    圖中沿四個(gè)對角的翻頁動(dòng)畫,代表對應(yīng)方向手勢的滑動(dòng)

1. 日歷

要實(shí)現(xiàn)一個(gè)日歷,其實(shí)原理很簡單,我們只要知道三個(gè)數(shù)據(jù):

    1.今天是哪一天

    2.這個(gè)月的第一天是星期幾(哪天)

    3.這個(gè)月總共有多少天

根據(jù)這個(gè)三個(gè)數(shù)據(jù),就可以把得到的日期顯示在日歷上了,至于日歷用什么來顯示,我個(gè)人比較喜歡用UICollectionView,一個(gè)cell代表一天,當(dāng)然也可以用很多個(gè)label,button來顯示。

1.獲取今天是哪一天

這個(gè)應(yīng)該是最簡單的: NSDate() , 就可以獲取當(dāng)前的日期

2.獲取這個(gè)月的第一天是星期幾(哪天)

下面的方法都是作為NSDateextension擴(kuò)展的

//當(dāng)前月第一天func firstDateOfCurrentMonth() ->NSDate{  let calendar = NSCalendar(identifier:NSCalendarIdentifierGregorian )  let currentDateComponents = calendar!.components([.Year,.Month], fromDate: self)  let startOfMonth = calendar!.dateFromComponents(currentDateComponents)  let date = startOfMonth?.dateByAddingTimeInterval(8*60*60)  return date!}//當(dāng)前月的第一天是星期幾func firstDayOfCurrentMonth() -> Int {  let calendar = NSCalendar.currentCalendar()  let components = calendar.components(.Weekday, fromDate: firstDateOfCurrentMonth())  return components.weekday-1}

3.獲取這個(gè)月總共有多少天

根絕上面這些數(shù)據(jù),就可以得到日歷里面每個(gè)格子應(yīng)該顯示的日期,具體的顯示和有關(guān)日期的三個(gè)主要的類: NSDate, NSCalendar, NSDateComponents 由于不是本文的重點(diǎn),我這里就不詳細(xì)說了,如果有不明白的可以去看一下文檔,或者如果我下次寫一個(gè)詳細(xì)的關(guān)于這三個(gè)類的(又挖一個(gè)坑。。)。

2. 翻頁動(dòng)畫

動(dòng)畫思路:

上面的動(dòng)畫屬于轉(zhuǎn)場動(dòng)畫的一種,所以我們可以利用CATrasition進(jìn)行動(dòng)畫,CATransition的使用非常簡單,只要設(shè)置動(dòng)畫時(shí)長,時(shí)間函數(shù),fillMode等,就可以得到想要的動(dòng)畫,CATransitiontype代表的是過渡時(shí)候的動(dòng)畫效果,subType一般代表動(dòng)畫的方向,但是查看了一下CATransitiontype屬性,官方文檔里面只描述了下面四種預(yù)定義的轉(zhuǎn)場動(dòng)畫效果:

NSString * const kCATransitionFade;NSString * const kCATransitionMoveIn;NSString * const kCATransitionPush;NSString * const kCATransitionReveal;

我們需要的翻頁動(dòng)畫并不在里面,在google了一下之后,找到了一個(gè)比較理想的效果,通過直接設(shè)置CATransitiontype為"pageCurl"或"pangeUnCurl"進(jìn)行動(dòng)畫,這兩個(gè)值官方文檔沒有提供,我也不知道為啥這些大神能找到。。。

但是默認(rèn)的朝上翻頁只有左上角方向的動(dòng)畫,朝下翻頁只有右下角方向的動(dòng)畫

做出來的效果如下圖:

無法達(dá)到四個(gè)對角都能進(jìn)行翻頁動(dòng)畫的效果。

為了得到可以沿著四個(gè)對角方向翻頁的效果,我們可以先在最底部添加一個(gè)containerView,然后在containerView中添加dayView(下面提到的dayView和代碼中的dayView都代表的是作為日歷的collectionView)。

如果要進(jìn)行朝右上角翻頁,我們只要把containerViewlayer先沿y軸翻轉(zhuǎn)M_PI,這樣,最開始的右下角就變成左下角了,翻頁時(shí)就會(huì)變成向右上角翻頁

但是為了日歷顯示正確,我們需要把dayViewlayer重新翻轉(zhuǎn)過來,這樣,containerView是反的,但是我們看到的日期顯示是正的

左下角翻頁也是同樣的道理。

具體代碼如下:

//為dayView(代表日歷的collectionview)添加一個(gè)滑動(dòng)手勢func addPanGestureToDayView() {  let swipe = UIPanGestureRecognizer(target: self, action: #selector(self.panOnDayView(_:)))  dayView.addGestureRecognizer(swipe)}//當(dāng)在dayView上滑動(dòng)時(shí)觸發(fā)func panOnDayView(pan: UIPanGestureRecognizer) {  //如果手勢的狀態(tài)是結(jié)束狀態(tài)  //或者當(dāng)前動(dòng)畫已經(jīng)結(jié)束(防止上一個(gè)翻頁動(dòng)畫還沒結(jié)束,就開始下一個(gè))  //添加翻頁的轉(zhuǎn)場動(dòng)畫到dayView上  if pan.state == .Ended && !animatiing{    addAnimationToDayView(pan)  }}let pageCurlDuration = 0.5  //動(dòng)畫時(shí)間let kPageCurlKey = "pageCurl"   //往上翻頁的的typelet kPageUnCurlKey = "pageUnCurl"  //往下翻頁的type//添加動(dòng)畫到日歷func addAnimationToDayView(pan: UIPanGestureRecognizer) {  let translation = pan.translationInView(dayView)  //創(chuàng)建一個(gè)轉(zhuǎn)場動(dòng)畫  let transitioin = CATransition()  transitioin.duration = pageCurlDuration  transitioin.timingFunction = CAMediaTimingFunction(name: "default")  //在動(dòng)畫結(jié)束之后保證狀態(tài)不被移除(這個(gè)兩個(gè)屬性得同時(shí)設(shè)置)  transitioin.fillMode = kCAFillModeForwards  transitioin.removedOnCompletion = false  //設(shè)置代理,在動(dòng)畫開始和結(jié)束的代理方法中可以處理一些事情  transitioin.delegate = self  if translation.y < 0 {//手勢向上  *  *    if translation.x > 0 {//手勢朝右上角滑動(dòng),朝右上翻頁      //沿y軸對containerView進(jìn)行M_PI角度翻轉(zhuǎn),使containerView的右下角變?yōu)樽笙陆?     animationContainerView.layer.transform = CATransform3DMakeRotation(CGFloat(M_PI), 0, 1, 0)      //因?yàn)閐ayView是加在containerView上面的,如果不把dayView重新翻轉(zhuǎn)回去,顯示出來的界面都是反的      dayView.layer.transform = CATransform3DMakeRotation(CGFloat(-M_PI), 0, 1, 0)    }    //轉(zhuǎn)場動(dòng)畫的效果    transitioin.type = kPageCurlKey    //轉(zhuǎn)場動(dòng)畫方向    transitioin.subtype = kCATransitionFromBottom    //設(shè)置一個(gè)month的key,為了在動(dòng)畫結(jié)束時(shí)判斷動(dòng)畫代表的是上一個(gè)月,還是下一個(gè)月    transitioin.setValue("next", forKey: "month")  }else{//下    if translation.x < 0 {//手勢朝左下角滑動(dòng),朝左下翻頁      animationContainerView.layer.transform = CATransform3DMakeRotation(CGFloat(M_PI), 0, 1, 0)      dayView.layer.transform = CATransform3DMakeRotation(CGFloat(-M_PI), 0, 1, 0)    }    transitioin.type = kPageUnCurlKey    transitioin.subtype = kCATransitionFromTop    transitioin.setValue("pre", forKey: "month")  }  dayView.layer.addAnimation(transitioin, forKey: "pageCurl")}

動(dòng)畫開始和停止時(shí),進(jìn)行一些處理:

//因?yàn)樯厦嬖O(shè)置了 transitioin.delegate = self,這兩個(gè)代理方法會(huì)自動(dòng)調(diào)用override func animationDidStart(anim: CAAnimation) {  //動(dòng)畫開始時(shí),判斷當(dāng)前動(dòng)畫是代表往上翻頁,還是往下翻頁,來刷新日歷時(shí)間  animatiing = true  let components = GregorianCalendar?.components([.Year,.Month,.Day], fromDate: date)  if anim.valueForKey("month") as! String == "next" {    components?.month += 1  }else if anim.valueForKey("month") as! String == "pre"{    components?.month -= 1  }  date = (GregorianCalendar?.dateFromComponents(components!))!  dateDidChaged!(date: date)}//動(dòng)畫結(jié)束時(shí),將layer的transform屬性設(shè)置為初始值,并移除dayView的layer上翻頁的動(dòng)畫override func animationDidStop(anim: CAAnimation, finished flag: Bool) {  if flag {    animatiing = false    animationContainerView.layer.transform = CATransform3DIdentity    dayView.layer.transform = CATransform3DIdentity    dayView.layer.removeAnimationForKey("pageCurl")  }}

總結(jié):

這篇文章沒有介紹太多詳細(xì)的內(nèi)容,其實(shí)翻頁的動(dòng)畫實(shí)現(xiàn)還有別的方法,但是因?yàn)槲蚁雽?shí)現(xiàn)的是可以沿著四個(gè)對角進(jìn)行動(dòng)畫的效果,所以最終選擇了這個(gè)方法,上面說的好像不是很具體,如果不是很明白,可以先查看一下CATranstion的使用方法。以上就是本文的全部內(nèi)容,希望對大家開發(fā)IOS動(dòng)畫的時(shí)候能有所幫助。

發(fā)表評論 共有條評論
用戶名: 密碼:
驗(yàn)證碼: 匿名發(fā)表
主站蜘蛛池模板: 溧阳市| 罗源县| 江阴市| 梨树县| 芦山县| 新河县| 阳曲县| 宝兴县| 新民市| 托克托县| 巴楚县| 佛冈县| 梧州市| 呼图壁县| 曲阳县| 黔江区| 庆安县| 白水县| 阳江市| 灵宝市| 安西县| 什邡市| 扬中市| 正阳县| 崇州市| 隆德县| 建德市| 浮梁县| 邢台县| 墨脱县| 淮北市| 威宁| 共和县| 灵山县| 霞浦县| 佛学| 嫩江县| 吉安县| 昭平县| 抚州市| 常熟市|