欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Swift4.1轉(zhuǎn)場(chǎng)動(dòng)畫(huà)實(shí)現(xiàn)側(cè)滑抽屜效果

 更新時(shí)間:2019年06月22日 14:56:58   作者:EugeneLaw  
這篇文章主要為大家詳細(xì)介紹了Swift4.1轉(zhuǎn)場(chǎng)動(dòng)畫(huà)實(shí)現(xiàn)側(cè)滑抽屜效果,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下

本文實(shí)現(xiàn)使用了Modal轉(zhuǎn)場(chǎng)動(dòng)畫(huà),原因是項(xiàng)目多由導(dǎo)航控制器和標(biāo)簽控制器作為基類(lèi),為了不影響導(dǎo)航控制器的代理,轉(zhuǎn)場(chǎng)動(dòng)畫(huà)使用模態(tài)交互。

代碼使用SnapKit進(jìn)行布局,能夠適應(yīng)屏幕旋轉(zhuǎn)。手勢(shì)速率大于300或進(jìn)度超過(guò)30%的時(shí)候直接完成動(dòng)畫(huà),否則動(dòng)畫(huà)回滾取消,具體數(shù)值可以修改對(duì)應(yīng)的常量。抽屜出現(xiàn)的時(shí)候,主控制有遮罩,對(duì)應(yīng)關(guān)鍵字是mask。

實(shí)現(xiàn)文件只有兩個(gè)

DrawerControl:控制抽屜出現(xiàn),一行代碼即可調(diào)用

Animator:負(fù)責(zé)動(dòng)畫(huà)實(shí)現(xiàn),包括了交互式的代理事件和非交互式的代理事件

//
// DrawerControl.swift
// PratiseSwift
//
// Created by EugeneLaw on 2018/7/31.
// Copyright © 2018年 EugeneLaw. All rights reserved.
//
 
import UIKit
 
enum DrawerSize {
 case Left
 case Right
}
 
class DrawerControl: NSObject {
 
 /**主頁(yè)面*/
 var base: UIViewController?
 /**抽屜控制器*/
 var drawer: UIViewController?
 /**抽屜在左邊還是右邊,默認(rèn)左邊,沒(méi)有實(shí)現(xiàn)右邊,要右邊自己去animator里面加判斷*/
 var whichSize = DrawerSize.Left
 /**拖拽手勢(shì)*/
 var panBase: UIPanGestureRecognizer?
 var panDrawer: UIPanGestureRecognizer?
 /**主頁(yè)面在抽屜顯示時(shí)保留的寬度*/
 var baseWidth: CGFloat {
 get {
 return self.animator!.baseWidth
 }
 set {
 self.animator?.baseWidth = newValue
 }
 }
 /**是否應(yīng)該響應(yīng)手勢(shì)*/
 var shouldResponseRecognizer = false
 /**效果響應(yīng)*/
 var animator: Animator?
 
 
 init(base: UIViewController, drawer: UIViewController) {
 super.init()
 self.base = base
 self.drawer = drawer
 animator = Animator(base: self.base!, drawer: self.drawer!)
 self.panBase = UIPanGestureRecognizer(target: self, action: #selector(panBaseAction(pan:)))
 base.view.addGestureRecognizer(self.panBase!)
 self.panDrawer = UIPanGestureRecognizer(target: self, action: #selector(panDrawerAction(pan:)))
 drawer.view.addGestureRecognizer(self.panDrawer!)
 self.drawer?.transitioningDelegate = self.animator
 }
 
 deinit {
 if self.panBase != nil {
 self.base?.view.removeGestureRecognizer(self.panBase!)
 self.panBase = nil
 }
 if self.panDrawer != nil {
 self.drawer?.view.removeGestureRecognizer(self.panDrawer!)
 self.panDrawer = nil
 }
 }
 
}
 
extension DrawerControl {
 
 ///顯示抽屜
 func show() {
 if (self.base?.view.frame.origin.x)! > SCREEN_WIDTH/2 {
 return
 }
 self.animator?.interative = false
 self.base?.present(self.drawer!, animated: true, completion: nil)
 }
 
 ///關(guān)閉抽屜,或直接dismiss即可
 func close() {
 self.animator?.interative = false
 self.drawer?.dismiss(animated: true, completion: nil)
 }
 
}
 
extension DrawerControl {
 
 @objc func panBaseAction(pan: UIPanGestureRecognizer) {
 let transition = pan.translation(in: self.drawer?.view)
 let percentage = CGFloat(transition.x/SCREEN_WIDTH)
 let velocity = CGFloat(fabs(pan.velocity(in: self.drawer?.view).x))
 switch pan.state {
 case .began:
 if transition.x < 0 {
 shouldResponseRecognizer = false
 }else {
 shouldResponseRecognizer = true
 }
 if shouldResponseRecognizer {
 self.beginAnimator(showDrawer: true)
 }
 case .changed:
 if shouldResponseRecognizer {
 self.updateAnimator(percentage)
 }
 default:
 if shouldResponseRecognizer {
 self.cancelAnimator(percentage, velocity: velocity)
 }
 }
 }
 
 @objc func panDrawerAction(pan: UIPanGestureRecognizer) {
 let transition = pan.translation(in: self.drawer?.view)
 let percentage = CGFloat(-transition.x/SCREEN_WIDTH)
 let velocity = CGFloat(fabs(pan.velocity(in: self.drawer?.view).x))
 switch pan.state {
 case .began:
 if transition.x > 0 {
 shouldResponseRecognizer = false
 }else {
 shouldResponseRecognizer = true
 }
 if shouldResponseRecognizer {
 self.beginAnimator(showDrawer: false)
 }
 case .changed:
 if shouldResponseRecognizer {
 self.updateAnimator(percentage)
 }
 default:
 if shouldResponseRecognizer {
 self.cancelAnimator(percentage, velocity: velocity)
 }
 }
 }
 
 func beginAnimator(showDrawer: Bool) {
 self.animator?.interative = true
 if showDrawer {
 self.base?.transitioningDelegate = self.animator
 self.base?.present(self.drawer!, animated: true, completion: nil)
 }else {
 self.drawer?.transitioningDelegate = self.animator
 self.drawer?.dismiss(animated: true, completion: nil)
 }
 }
 
 func updateAnimator(_ percentage: CGFloat) {
 self.animator?.update(percentage)
 }
 
 func cancelAnimator(_ percentage: CGFloat, velocity: CGFloat) {
 if percentage < 0.3 && velocity < 300 {
 self.animator?.cancel()
 }else {
 self.animator?.finish()
 }
 }
 
}
//
// Animator.swift
// PratiseSwift
//
// Created by EugeneLaw on 2018/7/31.
// Copyright © 2018年 EugeneLaw. All rights reserved.
//
 
import UIKit
 
let DRAWER_ANIMATION_TIME = 0.3
 
class Animator: UIPercentDrivenInteractiveTransition, UIViewControllerTransitioningDelegate, UIViewControllerAnimatedTransitioning {
 
 /**是否交互轉(zhuǎn)場(chǎng)*/
 var interative = false
 var showDrawer = false
 var base: UIViewController?
 var drawer:UIViewController?
 /**主頁(yè)面在抽屜顯示時(shí)保留的寬度*/
 var baseWidth: CGFloat = 100
 lazy var mask = { () -> UIButton in
 let mask = UIButton()
 mask.addTarget(self, action: #selector(maskClicked(_:)), for: .touchUpInside)
 return mask
 }()
 
 init(base: UIViewController, drawer: UIViewController) {
 super.init()
 self.base = base
 self.drawer = drawer
 UIDevice.current.beginGeneratingDeviceOrientationNotifications()
 NotificationCenter.default.addObserver(self, selector: #selector(observeDeviceOrientation(_:)), name: .UIDeviceOrientationDidChange, object: nil)
 }
 
 @objc func observeDeviceOrientation(_ notification: NSObject) {
 if let superView = self.base?.view.superview {
 if showDrawer {
 self.base?.view.snp.remakeConstraints({ (make) in
 make.width.equalTo(SCREEN_WIDTH)
 make.left.equalTo(superView.snp.right).offset(-self.baseWidth)
 make.top.bottom.equalTo(superView)
 })
 }else {
 self.base?.view.snp.remakeConstraints({ (make) in
 make.edges.equalTo(superView)
 })
 }
 superView.layoutIfNeeded()
 }
 }
 
 deinit {
 NotificationCenter.default.removeObserver(self)
 }
 
}
 
extension Animator {
 
 func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
 if showDrawer {
 let fromView = transitionContext.view(forKey: .from)
 addShadowToView(fromView!, color: .black, offset: CGSize(width: -1, height: 0), radius: 3, opacity: 0.1)
 let toView = transitionContext.view(forKey: .to)
 let containerView = transitionContext.containerView
 containerView.addSubview(toView!)
 containerView.addSubview(fromView!)
 fromView?.snp.remakeConstraints({ (make) in
 make.edges.equalTo(containerView)
 })
 toView?.snp.remakeConstraints({ (make) in
 make.edges.equalTo(containerView)
 })
 containerView.layoutIfNeeded()
 UIView.animate(withDuration: DRAWER_ANIMATION_TIME, animations: {
 fromView?.snp.remakeConstraints({ (make) in
 make.left.equalTo((toView?.snp.right)!).offset(-self.baseWidth)
 make.width.top.bottom.equalTo(toView!)
 })
 containerView.layoutIfNeeded()
 }) { (finish) in
 let cancel = transitionContext.transitionWasCancelled
 transitionContext.completeTransition(!cancel)
 if !cancel {//取消狀態(tài)下區(qū)分添加到哪一個(gè)父視圖,弄錯(cuò)會(huì)導(dǎo)致黑屏
 if self.drawer?.view.superview != nil {
 self.drawer?.view?.snp.remakeConstraints({ (make) in
 make.edges.equalTo((self.drawer?.view?.superview)!)
 })
 }
 self.showPartOfView()
 }else {
 fromView?.snp.remakeConstraints({ (make) in
 make.edges.equalTo((fromView?.superview)!)
 })
 }
 }
 }else {
 let fromView = transitionContext.view(forKey: .from)
 let toView = transitionContext.view(forKey: .to)
 addShadowToView(toView!, color: .black, offset: CGSize(width: -1, height: 0), radius: 3, opacity: 0.1)
 let containerView = transitionContext.containerView
 containerView.addSubview(fromView!)
 containerView.addSubview(toView!)
 fromView?.snp.remakeConstraints({ (make) in
 make.edges.equalTo(containerView)
 })
 toView?.snp.remakeConstraints({ (make) in
 make.left.equalTo(containerView.snp.right).offset(-self.baseWidth)
 make.width.equalTo(SCREEN_WIDTH)
 make.height.equalTo(SCREEN_HEIGHT)
 make.top.bottom.equalTo(containerView)
 })
 containerView.layoutIfNeeded()
 UIView.animate(withDuration: DRAWER_ANIMATION_TIME, animations: {
 toView?.snp.remakeConstraints({ (make) in
 make.edges.equalTo(containerView)
 })
 containerView.layoutIfNeeded()
 }) { (finish) in
 let cancel = transitionContext.transitionWasCancelled
 transitionContext.completeTransition(!cancel)
 toView?.snp.remakeConstraints({ (make) in
 make.edges.equalTo((toView?.superview)!)
 })
 if minX((self.base?.view)!) <= 0 {//判斷結(jié)束時(shí)候是否回到主視圖
 self.base?.view.isUserInteractionEnabled = true
 }
 }
 }
 }
 
 func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval {
 return DRAWER_ANIMATION_TIME
 }
 
 override func startInteractiveTransition(_ transitionContext: UIViewControllerContextTransitioning) {
 super.startInteractiveTransition(transitionContext)
 }
 
 func animationController(forPresented presented: UIViewController, presenting: UIViewController, source: UIViewController) -> UIViewControllerAnimatedTransitioning? {
 self.showDrawer = true
 return self
 }
 
 func animationController(forDismissed dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning? {
 self.showDrawer = false
 return self
 }
 
 func interactionControllerForPresentation(using animator: UIViewControllerAnimatedTransitioning) -> UIViewControllerInteractiveTransitioning? {
 if interative {
 return self
 }else {
 return nil
 }
 }
 
 func interactionControllerForDismissal(using animator: UIViewControllerAnimatedTransitioning) -> UIViewControllerInteractiveTransitioning? {
 if interative {
 return self
 }else {
 return nil
 }
 }
 
}
 
 
extension Animator {
 
 func showPartOfView() {
 self.drawer?.view.addSubview((self.base?.view)!)
 self.base?.view.snp.remakeConstraints({ (make) in
 make.left.equalTo((self.drawer?.view.snp.right)!).offset(-self.baseWidth)
 make.top.bottom.equalTo((self.drawer?.view)!)
 make.width.equalTo(SCREEN_WIDTH)
 })
 //遮罩
 self.drawer?.view.insertSubview(mask, aboveSubview: (self.base?.view)!)
 self.base?.view.isUserInteractionEnabled = false//阻止交互
 mask.snp.remakeConstraints { (make) in
 make.left.equalTo((mask.superview?.snp.right)!).offset(-baseWidth)
 make.top.width.bottom.equalTo(mask.superview!);
 }
 self.drawer?.view.superview?.layoutIfNeeded()
 }
 
 @objc func maskClicked(_ button: UIButton) {
 button.removeFromSuperview()
 self.drawer?.dismiss(animated: true, completion: nil)
 }
 
}

按鈕調(diào)用例子:(手勢(shì)控制已經(jīng)自動(dòng)添加到主控制器和抽屜控制器的view上)

創(chuàng)建推出抽屜的控制類(lèi),參數(shù)分別是主控制器和抽屜控制器。在我自己的練習(xí)工程中,把這個(gè)控制類(lèi)定義為總控制器(包括了導(dǎo)航控制器和標(biāo)簽控制器的控制類(lèi))的一個(gè)屬性。創(chuàng)建這個(gè)抽屜控制類(lèi)的時(shí)候,我把導(dǎo)航控制器(它的root是標(biāo)簽控制器)當(dāng)做主控制器傳給第一個(gè)參數(shù)。 

self.drawer = DrawerControl(base: self.navigation!, drawer: self.drawerPage) 

調(diào)用的時(shí)候只需要使用抽屜控制類(lèi)的show方法即可,練習(xí)工程中我把該按鈕封裝在導(dǎo)航菜單里面,它響應(yīng)的時(shí)候會(huì)調(diào)用總控制器的單例,調(diào)用單例記錄的抽屜控制器屬性。

@objc func btnMenuClicked(_ button: UIButton) {
 TotalControl.instance().drawer?.show()
}

附錄:用到的一些變量

//
// Headers.swift
// PratiseSwift
//
// Created by EugeneLaw on 2018/7/23.
// Copyright © 2018年 EugeneLaw. All rights reserved.
//
 
import UIKit
 
//MARK: 設(shè)備
let isRetina = (UIScreen.instancesRespond(to: #selector(getter: UIScreen.currentMode)) ? __CGSizeEqualToSize(CGSize(width: 640, height: 960), (UIScreen.main.currentMode?.size)!) : false)
let iPhone5 = (UIScreen.instancesRespond(to: #selector(getter: UIScreen.currentMode)) ? __CGSizeEqualToSize(CGSize(width: 640, height: 1136), (UIScreen.main.currentMode?.size)!) : false)
let iPhone6 = (UIScreen.instancesRespond(to: #selector(getter: UIScreen.currentMode)) ? __CGSizeEqualToSize(CGSize(width: 750, height: 1334), (UIScreen.main.currentMode?.size)!) : false)
let iPhone6Plus = (UIScreen.instancesRespond(to: #selector(getter: UIScreen.currentMode)) ? __CGSizeEqualToSize(CGSize(width: 1242, height: 2208), (UIScreen.main.currentMode?.size)!) : false)
let isPad = (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiom.pad)
let isPhone = (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiom.phone)
let isiPhoneX = (UIScreen.instancesRespond(to: #selector(getter: UIScreen.currentMode)) ? __CGSizeEqualToSize(CGSize(width: 1125, height: 2436), (UIScreen.main.currentMode?.size)!) : false)
 
//MARK: 界面
let TABBAR_HEIGHT = (isiPhoneX ? 83 : 49)
let NAVIGATION_HEIGHT = (isiPhoneX ? 88 : 64)
var SCREEN_WIDTH: CGFloat {
 get {
 return SCREEN_WIDTH_FUNC()
 }
}
var SCREEN_HEIGHT: CGFloat {
 get {
 return SCREEN_HEIGHT_FUNC()
 }
}
 
func SCREEN_WIDTH_FUNC() -> CGFloat {
 return UIScreen.main.bounds.size.width
}
 
func SCREEN_HEIGHT_FUNC() -> CGFloat {
 return UIScreen.main.bounds.size.height
}
 
//MARK: 顏色
let COLOR_WHITESMOKE = ColorHex("#F5F5F5")
 
/**
 *十六進(jìn)制顏色值轉(zhuǎn)換成UIColor
 *@param "#000000"
 */
func ColorHex(_ color: String) -> UIColor? {
 if color.count <= 0 || color.count != 7 || color == "(null)" || color == "<null>" {
 return nil
 }
 var red: UInt32 = 0x0
 var green: UInt32 = 0x0
 var blue: UInt32 = 0x0
 let redString = String(color[color.index(color.startIndex, offsetBy: 1)...color.index(color.startIndex, offsetBy: 2)])
 let greenString = String(color[color.index(color.startIndex, offsetBy: 3)...color.index(color.startIndex, offsetBy: 4)])
 let blueString = String(color[color.index(color.startIndex, offsetBy: 5)...color.index(color.startIndex, offsetBy: 6)])
 Scanner(string: redString).scanHexInt32(&red)
 Scanner(string: greenString).scanHexInt32(&green)
 Scanner(string: blueString).scanHexInt32(&blue)
 let hexColor = UIColor.init(red: CGFloat(red)/255.0, green: CGFloat(green)/255.0, blue: CGFloat(blue)/255.0, alpha: 1)
 return hexColor
}
 
/**
 *給圖層添加陰影
 */
func addShadowToView(_ view: UIView, color: UIColor, offset: CGSize, radius: CGFloat, opacity: Float) {
 view.layer.shadowColor = color.cgColor
 view.layer.shadowOffset = offset
 view.layer.shadowOpacity = opacity
 view.layer.shadowRadius = radius
}
 
/**
 *計(jì)算圖層的寬度
 */
func width(_ object: UIView) -> CGFloat {
 return object.frame.width
}
 
/**
 *在父視圖中的x坐標(biāo)
 */
func minX(_ object: UIView) -> CGFloat {
 return object.frame.origin.x
}
 
/**
 *在父視圖中的x坐標(biāo)+自身寬度
 */
func maxX(_ object: UIView) -> CGFloat {
 return object.frame.origin.x+width(object)
}
 
/**
 *在父視圖中的y坐標(biāo)
 */
func minY(_ object: UIView) -> CGFloat {
 return object.frame.origin.y
}
 
/**
 *在父視圖中的y坐標(biāo)+自身高度
 */
func maxY(_ object: UIView) -> CGFloat {
 return object.frame.origin.y+height(object)
}
 
/**
 *計(jì)算圖層的高度
 */
func height(_ object: UIView) -> CGFloat {
 return object.frame.height
}

以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

  • mac git xcrun error active developer path 錯(cuò)誤

    mac git xcrun error active developer path 錯(cuò)誤

    本文主要是講訴了如何解決在mac下使用git;xcode4.6的環(huán)境時(shí),出現(xiàn)了錯(cuò)誤(mac git xcrun error active developer path)的解決辦法,希望對(duì)大家有所幫助
    2014-09-09
  • 深入講解Swift的內(nèi)存管理

    深入講解Swift的內(nèi)存管理

    不管在什么語(yǔ)言里,內(nèi)存管理的內(nèi)容都很重要,Swift使用自動(dòng)引用計(jì)數(shù)來(lái)管理應(yīng)用程序的內(nèi)存使用。這表示內(nèi)存管理已經(jīng)是Swift的一部分,在大多數(shù)情況下,你并不需要考慮內(nèi)存的管理。本文主要介紹了Swift中內(nèi)存管理的相關(guān)資料,需要的朋友可以參考。
    2017-03-03
  • swift中AnyObject和Any的介紹與區(qū)別詳解

    swift中AnyObject和Any的介紹與區(qū)別詳解

    雖然使用swift開(kāi)發(fā)了一段時(shí)間,但是感覺(jué)對(duì)一些基礎(chǔ)的東西了解不是比較透徹,在查詢(xún)了許多資料以后還是打算自己動(dòng)手記錄一下,下面這篇文章主要給大家介紹了關(guān)于swift中AnyObject和Any的介紹與區(qū)別的相關(guān)資料,需要的朋友可以參考下。
    2017-12-12
  • Swift Set集合及常用方法詳解總結(jié)

    Swift Set集合及常用方法詳解總結(jié)

    Set集合為集類(lèi)型,集是最簡(jiǎn)單的一種集合,存放于集中的對(duì)象不按特定方式排序,只是簡(jiǎn)單地把對(duì)象加入集合中,類(lèi)似于向口袋里放東西,對(duì)集中存在的對(duì)象的訪(fǎng)問(wèn)和操作是通過(guò)對(duì)象的引用進(jìn)行的,因此在集中不能存放重復(fù)對(duì)象
    2021-11-11
  • Swift實(shí)現(xiàn)倒計(jì)時(shí)5秒功能

    Swift實(shí)現(xiàn)倒計(jì)時(shí)5秒功能

    這篇文章主要為大家詳細(xì)介紹了Swift實(shí)現(xiàn)倒計(jì)時(shí)5秒功能,在“登錄”和“注冊(cè)”頁(yè)面也有相似功能,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2020-03-03
  • 在Swift中使用Objective-C編寫(xiě)類(lèi)、繼承Objective-C類(lèi)

    在Swift中使用Objective-C編寫(xiě)類(lèi)、繼承Objective-C類(lèi)

    這篇文章主要介紹了在Swift中使用Objective-C編寫(xiě)類(lèi)、繼承Objective-C類(lèi)等操作方法介紹,需要的朋友可以參考下
    2014-07-07
  • swift計(jì)步器CMPedometer的使用方法

    swift計(jì)步器CMPedometer的使用方法

    這篇文章主要為大家詳細(xì)介紹了swift計(jì)步器CMPedometer的使用方法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-09-09
  • 程序遷移到swift 3.0的一些實(shí)用技巧

    程序遷移到swift 3.0的一些實(shí)用技巧

    Swift項(xiàng)目為適配iOS10,無(wú)奈只能更新Xcode 8 ,可是發(fā)現(xiàn)一入3.0深似海,從此幸福是路人。于是邊摸索邊修改,終于完成了代碼遷移。節(jié)后在完成手頭工作后,整理思路把Swift3.0遷移的一些實(shí)用技巧分享大家,需要的朋友可以參考下。
    2017-03-03
  • 深入解析Swift代理模式

    深入解析Swift代理模式

    委托(代理)是一種設(shè)計(jì)模式,它允許類(lèi)或結(jié)構(gòu)體將一些需要它們負(fù)責(zé)的功能交由(委托)給其他的類(lèi)型。下面這篇文章主要介紹了Swift代理模式的相關(guān)資料,文章開(kāi)始先介紹了Objective-C相關(guān)的內(nèi)容,需要的朋友可以參考借鑒,下面來(lái)一起看看吧。
    2017-03-03
  • Objective-C中的block與Swift中的尾隨閉包使用教程

    Objective-C中的block與Swift中的尾隨閉包使用教程

    Block是OC中的閉包,他和swift中的閉包有什么區(qū)別呢?下面這篇文章就來(lái)給大家介紹關(guān)于Objective-C中的block與Swift中的尾隨閉包使用的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),需要的朋友可以參考下。
    2017-12-12

最新評(píng)論