Swift轉(zhuǎn)場動畫

源碼Github地址

  • 系統(tǒng)模態(tài)跳轉(zhuǎn)
// 
open func present(_ viewControllerToPresent: UIViewController, animated flag: Bool, completion: (() -> Void)? = nil)

// 動畫風(fēng)格
public enum UIModalTransitionStyle : Int {

    // 默認,從底部劃入
    case coverVertical
    // 切換正反面效果
    case flipHorizontal
    // 漸變效果
    case crossDissolve
    @available(iOS 3.2, *)
    // 翻頁效果
    case partialCurl
}
  • 模態(tài)跳轉(zhuǎn)退回上一層控制器
 open func dismiss(animated flag: Bool, completion: (() -> Void)? = nil)
  • push動畫轉(zhuǎn)場,支持右滑返回,當(dāng)前控制器不是navigationController的子控制器時無效
open func pushViewController(_ viewController: UIViewController, animated: Bool)
  • push動畫轉(zhuǎn)場退回上一層控制器
open func popViewController(animated: Bool) -> UIViewController?
  • push動畫轉(zhuǎn)場退回根控制器
 open func popToRootViewController(animated: Bool) -> [UIViewController]? 
  • push動畫轉(zhuǎn)場退回指定控制器
open func popToViewController(_ viewController: UIViewController, animated: Bool) -> [UIViewController]? 


以上轉(zhuǎn)場動畫為系統(tǒng)提供竿滨,可以滿足我們大部分使用場景蘸吓,但是有時候我們可能會遇到特殊的需求琳疏,需要我們自定義轉(zhuǎn)場動畫

/// 創(chuàng)建一個動畫管理類怒允,這個類可以作為所有自定義轉(zhuǎn)場動畫的基類
class ZQBaseAninatedTranistion: UIPercentDrivenInteractiveTransition, UIViewControllerAnimatedTransitioning {
    /**動畫時長*/
    var animateDuration:TimeInterval = 0.5
    /**判斷是否已經(jīng)彈出*/
    var isPopup:Bool = false
    /**交互狀態(tài)*/
    var isInteraction:Bool = false
    /**轉(zhuǎn)場上下文*/
    var context:UIViewControllerContextTransitioning?
    /**視圖*/
    var containerView:UIView?
    /**當(dāng)前view*/
    var fromView:UIView?
    /**目標(biāo)view*/
    var toView:UIView?
    /**當(dāng)前控制器*/
    var fromViewController:UIViewController?
    /**目標(biāo)控制器*/
    var toViewController:UIViewController?
    
    /// 設(shè)置動畫時長
    func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval {
        context = transitionContext
        return animateDuration
    }
    
    /// 執(zhí)行動畫過程
    func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
        context = transitionContext
        //容器
        containerView = transitionContext.containerView
        //目標(biāo)控制器
        fromViewController = transitionContext.viewController(forKey: .from)
        toViewController = transitionContext.viewController(forKey: .to)
        fromView = fromViewController?.view
        toView = toViewController?.view
        isPopup ? dismiss():present()
    }
    
    /// 彈出轉(zhuǎn)場動畫寫在這里
    func present(){
    
    }
    
   
    /// 退回轉(zhuǎn)場動畫寫在這里
    func dismiss(){
    }
}

實現(xiàn)從微信進入小程序的轉(zhuǎn)場動畫及右滑返回動畫

class ZQFullCoverAnimatedTranistion: ZQBaseAninatedTranistion {
    //最大偏移位置
    var maxOffset:CGFloat = 0.0
    //最右臨界值
    var rightCritcal:CGFloat = 20.0
    //手勢
    var leftPanGesture:UIScreenEdgePanGestureRecognizer?
    
    /// 啟用邊緣滑動返回
    func usingLeftSwipDismiss(view:UIView){
        //監(jiān)聽邊緣滑動
        leftPanGesture  = UIScreenEdgePanGestureRecognizer(target: self, action: #selector(self.onEdgeSlide))
        //左側(cè)邊緣滑動
        leftPanGesture!.edges = .left
        //添加事件
        view.addGestureRecognizer(leftPanGesture!)
    }
    
    /// 當(dāng)邊緣滑動
    @objc func onEdgeSlide(reco:UIScreenEdgePanGestureRecognizer){
        let point = reco.location(in: reco.view)
        //執(zhí)行動畫轉(zhuǎn)場
        let progress = point.x / reco.view!.bounds.width
        if reco.state == .began {
            //變更狀態(tài)
            isInteraction = true
            //當(dāng)開始谋旦,復(fù)位
            maxOffset = 0.0
            //---------這行很關(guān)鍵-----------
            fromViewController?.dismiss(animated: true, completion: nil)
        } else if reco.state == .changed {
            maxOffset = max(point.x, maxOffset)
            update(progress)
        } else {
            //當(dāng)結(jié)束后
            if point.x >= maxOffset && point.x > rightCritcal {
                //完成退出
                finish()
            }else {
                //取消后恢復(fù)
                cancel()
            }
            //變更狀態(tài)
            isInteraction = false
        }
    }
    
    /// 彈出動畫恕刘,你可以在這這個方法里面實現(xiàn)你想要的任意動畫
    override func present(){
        //目標(biāo)視圖
        let toFrame = context!.finalFrame(for: toViewController!)
        //添加視圖
        containerView!.addSubview(toView!)
        let rect = containerView!.bounds
        //設(shè)置動畫
        toView!.frame = CGRect(x: 0, y: rect.height * 2, width: rect.width, height: rect.height)
        UIView.animate(withDuration: animateDuration, animations: { [weak self] in
            self!.toView!.frame.origin.y = 0
            self!.fromView!.transform = CGAffineTransform(scaleX: 0.95, y: 0.95)
        }) {[weak self] (r) in
            if self!.context!.transitionWasCancelled {
                //操作失敗了
                self!.context!.completeTransition(false)
                //移除視圖
                self!.toView?.removeFromSuperview()
            }else{
                self!.isPopup = true
                self!.toView?.frame = toFrame
                self!.context!.completeTransition(true)
            }
        }
    }
    
    /// 彈回動畫必尼,你可以在這這個方法里面實現(xiàn)你想要的任意動畫
    override func dismiss(){
        //添加toView到底部一層
        containerView!.addSubview(toView!)
        containerView!.sendSubviewToBack(toView!)
        //添加視圖
        let rect = containerView!.bounds
        //設(shè)置動畫
        UIView.animate(withDuration: animateDuration, animations: { [weak self] in
            self!.fromView?.frame.origin.y = rect.height * 2
            self!.toView?.transform = .identity
        }) { [weak self] (r) in
            //取消
            if self!.context!.transitionWasCancelled {
                //操作失敗
                self!.context?.completeTransition(false)
                self!.toView?.removeFromSuperview()
            }else{
                self!.isPopup = false
                //將原始視圖移除
                self!.fromView?.removeFromSuperview()
                //通知系統(tǒng)是否被取消蒋搜,用于記錄動畫是否完成
                self!.context!.completeTransition(true)
                //移除手勢
                if self!.leftPanGesture != nil && self!.fromView != nil{
                    self!.fromView?.removeGestureRecognizer(self!.leftPanGesture!)
                }
            }
        }
    }
}

調(diào)用

class ViewController: UIViewController {
    // 動畫
    let tranistionHandler = ZQFullCoverAnimatedTranistion()
    override func viewDidLoad() {
        super.viewDidLoad()

    }

    
    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        let vc = ZQFullCoverToViewController()
        /// 設(shè)置動畫代理
        vc.transitioningDelegate = self
        // 開啟右滑返回
        tranistionHandler.usingLeftSwipDismiss(view: vc.view)
        present(vc, animated: true, completion: nil)
    }
}

extension ViewController:UIViewControllerTransitioningDelegate{
    
    /// 彈出
    ///
    /// - Parameters:
    ///   - presented: 目標(biāo)
    ///   - presenting: 當(dāng)前
    ///   - source: 資源
    /// - Returns: 自定義的動畫
    func animationController(forPresented presented: UIViewController, presenting: UIViewController, source: UIViewController) -> UIViewControllerAnimatedTransitioning? {
        return tranistionHandler
    }
    
    /// 收起
    ///
    /// - Parameter dismissed: 目標(biāo)
    /// - Returns: 自定義的動畫
    func animationController(forDismissed dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning? {
        return tranistionHandler
    }
    
    /// 響應(yīng)手勢操作
    ///
    /// - Parameter animator: tranistionHandler
    /// - Returns: 自定義的動畫
    func interactionControllerForDismissal(using animator: UIViewControllerAnimatedTransitioning) -> UIViewControllerInteractiveTransitioning? {
        //避免手勢與顯示調(diào)用沖突,導(dǎo)致無法dismiss
        if !tranistionHandler.isInteraction {
            return nil
        }
        return tranistionHandler
    }
}

源碼Github地址

如果有幫到您判莉,請點個喜歡

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末豆挽,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子券盅,更是在濱河造成了極大的恐慌祷杈,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,817評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件渗饮,死亡現(xiàn)場離奇詭異但汞,居然都是意外死亡,警方通過查閱死者的電腦和手機互站,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,329評論 3 385
  • 文/潘曉璐 我一進店門私蕾,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人胡桃,你說我怎么就攤上這事踩叭。” “怎么了?”我有些...
    開封第一講書人閱讀 157,354評論 0 348
  • 文/不壞的土叔 我叫張陵容贝,是天一觀的道長自脯。 經(jīng)常有香客問我,道長斤富,這世上最難降的妖魔是什么膏潮? 我笑而不...
    開封第一講書人閱讀 56,498評論 1 284
  • 正文 為了忘掉前任,我火速辦了婚禮满力,結(jié)果婚禮上焕参,老公的妹妹穿的比我還像新娘。我一直安慰自己油额,他們只是感情好叠纷,可當(dāng)我...
    茶點故事閱讀 65,600評論 6 386
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著潦嘶,像睡著了一般涩嚣。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上掂僵,一...
    開封第一講書人閱讀 49,829評論 1 290
  • 那天航厚,我揣著相機與錄音,去河邊找鬼看峻。 笑死,一個胖子當(dāng)著我的面吹牛衙吩,可吹牛的內(nèi)容都是我干的互妓。 我是一名探鬼主播,決...
    沈念sama閱讀 38,979評論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼坤塞,長吁一口氣:“原來是場噩夢啊……” “哼冯勉!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起摹芙,我...
    開封第一講書人閱讀 37,722評論 0 266
  • 序言:老撾萬榮一對情侶失蹤灼狰,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后浮禾,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體交胚,經(jīng)...
    沈念sama閱讀 44,189評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,519評論 2 327
  • 正文 我和宋清朗相戀三年盈电,在試婚紗的時候發(fā)現(xiàn)自己被綠了蝴簇。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,654評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡匆帚,死狀恐怖熬词,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤互拾,帶...
    沈念sama閱讀 34,329評論 4 330
  • 正文 年R本政府宣布歪今,位于F島的核電站,受9級特大地震影響颜矿,放射性物質(zhì)發(fā)生泄漏寄猩。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,940評論 3 313
  • 文/蒙蒙 一或衡、第九天 我趴在偏房一處隱蔽的房頂上張望焦影。 院中可真熱鬧,春花似錦封断、人聲如沸斯辰。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,762評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽彬呻。三九已至,卻和暖如春柄瑰,著一層夾襖步出監(jiān)牢的瞬間闸氮,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,993評論 1 266
  • 我被黑心中介騙來泰國打工教沾, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留蒲跨,地道東北人。 一個月前我還...
    沈念sama閱讀 46,382評論 2 360
  • 正文 我出身青樓授翻,卻偏偏與公主長得像或悲,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子堪唐,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,543評論 2 349

推薦閱讀更多精彩內(nèi)容

  • 前言的前言 唐巧前輩在微信公眾號「iOSDevTips」以及其博客上推送了我的文章后巡语,我的 Github 各項指標(biāo)...
    VincentHK閱讀 5,349評論 3 44
  • 原文鏈接轉(zhuǎn)場動畫 需求: 點擊導(dǎo)航欄左上角,出現(xiàn)一個左側(cè)菜單 左側(cè)菜單覆蓋住 原控制器的一半 左側(cè)菜單的出現(xiàn)順序為...
    文瑤906閱讀 1,963評論 0 1
  • 轉(zhuǎn)場動畫 以我們常用的present淮菠、push轉(zhuǎn)場動畫為例男公,這種過渡性視圖展示效果被抽象成UIViewContro...
    Mcccc閱讀 2,779評論 1 3
  • “來說是非者枢赔,便是是非人”這句話出自增廣賢文,是呀拥知,大家是不是都有點感同身受糠爬,有時候自己莫名其妙就被牽扯進...
    monica梅閱讀 902評論 0 0
  • 前任到底是個什么樣的概念?假如有一天镀琉,她突然出現(xiàn)在你的面前峦嗤,然后要你陪她完成一場旅行,去一個地方屋摔,開一間大床房烁设,關(guān)...
    七天大圣閱讀 603評論 12 6