- 系統(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
}
}
如果有幫到您判莉,請點個喜歡