吐槽模式
最近看了很多關(guān)于UIPresentationController的文章演侯,個人表示太難看懂了憔四,他們的自己封裝的太多了,不利于快速學(xué)習(xí)措拇,對于這類知識不需要太多的寫封裝洛口,又不是專門教架構(gòu)和封裝问拘,跳來跳去的眼睛都花了蒸矛,真是蛋疼柿汛!
教授模式
當(dāng)父UIViewController調(diào)用present(_:animated:completion:)來呈現(xiàn)子UIViewController過程中使用UIPresentationController來控制轉(zhuǎn)場的,所以我把所有的自定義UIPresentationController的都放在了子UIViewController中券犁。
直接看我寫的子UIViewController术健,
//此視圖控制器是將要 被 呈現(xiàn)的
class TestViewController: UIViewController, UIViewControllerTransitioningDelegate {//這個代理是必須的,用來控制轉(zhuǎn)場動畫粘衬,個人覺得TestViewController的呈現(xiàn)動畫由TestViewController自己去實現(xiàn)是最好的荞估,所以我用TestViewController繼承了UIViewControllerTransitioningDelegate代理
init() {
super.init(nibName: nil, bundle: nil)
//自定義呈現(xiàn),這兩個操作必須放在init方法中
modalPresentationStyle = .custom? //這個很重要
transitioningDelegate = self //UIViewControllerTransitioningDelegate的代理
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
fatalError("init(coder:) has not been implemented")
}
deinit {
print("TestViewController -- 釋放")
}
override func viewDidLoad() {
super.viewDidLoad()
view.layer.cornerRadius = 10? ? //只設(shè)置這一個稚新,自己會有剪切勘伺,子視圖不會被剪切
}
@IBAction func dismissAction(_ sender: Any) {
dismiss(animated: true)
}
//這個是UIViewControllerTransitioningDelegate中的方法
public func presentationController(forPresented presented: UIViewController, presenting: UIViewController?, source: UIViewController) -> UIPresentationController? {
let pc = XMAlertPresentationController(presentedViewController: presented, presenting: presenting)
return pc//返回自定義的UIPresentationController
}
}
然后在看自定義的UIPresentationController
//present or dismiss 兩個過程實現(xiàn)
class XMAlertPresentationController: UIPresentationController {
var view: UIView?? ? ? //此試圖包含一個點擊手勢
var bgView: UIView?? ? //不能交互的視圖
deinit {
print("XMAlertSheetPresentationController -- 釋放")
}
//呈現(xiàn)動畫將要開始
override func presentationTransitionWillBegin() {
//
view = UIView(frame: (containerView?.bounds)!)
view?.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(dismissAction)))
view?.backgroundColor = UIColor(white: 0, alpha: 0)? ? //這個一定要的,不然下面的動畫就沒效果了
containerView?.addSubview(view!)
bgView = UIView(frame: (containerView?.bounds)!)
bgView?.isUserInteractionEnabled = false
containerView?.addSubview(bgView!)
//通過使用「負(fù)責(zé)呈現(xiàn)」的 controller 的 UIViewControllerTransitionCoordinator褂删,我們可以確保我們的動畫與其他動畫一道兒播放娇昙。
//背景色變動畫,使用present or dismiss默認(rèn)的動畫實現(xiàn)
guard let transitionCoordinator = presentingViewController.transitionCoordinator else {
return
}
transitionCoordinator.animate(alongsideTransition: {(context: UIViewControllerTransitionCoordinatorContext!) -> Void in//動畫0.4秒
self.view?.backgroundColor = UIColor(white: 0, alpha: 0.4)
})
}
//呈現(xiàn)動畫已結(jié)束
override func presentationTransitionDidEnd(_ completed: Bool) {
// 如果呈現(xiàn)沒有完成笤妙,那就移除背景 View,沒有完成就是出了錯誤
if !completed {
view?.removeFromSuperview()
bgView?.removeFromSuperview()
}
}
//消失動畫將要開始
override func dismissalTransitionWillBegin() {
//背景色變動畫噪裕,使用present or dismiss默認(rèn)的動畫實現(xiàn)
guard let transitionCoordinator = presentingViewController.transitionCoordinator else {
self.view?.backgroundColor = UIColor(white: 0, alpha: 0.0)
return
}
transitionCoordinator.animate(alongsideTransition: {(context: UIViewControllerTransitionCoordinatorContext!) -> Void in
self.view?.backgroundColor = UIColor(white: 0, alpha: 0.0)
})
}
//消失動畫已結(jié)束
override func dismissalTransitionDidEnd(_ completed: Bool) {
if completed {
view?.removeFromSuperview()
bgView?.removeFromSuperview()
}
}
//計算presentedView的frame
override var frameOfPresentedViewInContainerView: CGRect {
let size = containerView!.bounds.size//containerView是轉(zhuǎn)場容器視圖的蹲盘,這里的size相當(dāng)于mainScreen的size
if presentedViewController.preferredInterfaceOrientationForPresentation.isLandscape {//豎屏
let width = size.height - 20
return CGRect(x: (size.width - width)/2.0, y: size.height - 270, width: width, height: 260)
}
return CGRect(x: 10, y: size.height - 270, width: size.width - 20, height: 260)
}
//當(dāng)前橫豎屏變換時調(diào)用,調(diào)整自己寫的視圖
open override func containerViewWillLayoutSubviews() {
view?.frame = containerView!.frame
bgView?.frame = containerView!.frame
//當(dāng)屏幕旋轉(zhuǎn)后presentedView的frame需要自己調(diào)整膳音,所以下面一行是必須的召衔,presentedView == TestViewController.view這就明白了吧
presentedView?.frame = frameOfPresentedViewInContainerView? //這行是必須的
}
func dismissAction() {//點擊消失
presentedViewController.dismiss(animated: true)
}
}
如何使用測試:
let vc = TestViewController();
self.present(vc, animated: true)
是不是使用起來很簡單?
你可以打印XMAlertPresentationController中的presentedViewController和presentingViewController看看是什么類型
賢者模式
寫完了祭陷,看著是不是很簡單苍凛,把上面的兩個類直接考到文件里就可使用,這個博客沒有語法高亮也是個麻煩事兵志,下面是效果圖醇蝴,源碼