Swift仿微信語音通話最小化時(shí)后的效果實(shí)例代碼
前言
最近碰到個(gè)需求,需要仿微信語音通話縮小化后,保持界面最上層有一個(gè)懸浮的小View可以一點(diǎn)擊就把剛剛縮放掉的界面再放回來,其實(shí)本質(zhì)就是創(chuàng)造了一個(gè)新的Window,在這個(gè)window上創(chuàng)建了一個(gè)rootController并展示他,縮小化時(shí)是把controller dismiss掉了,再次點(diǎn)擊那個(gè)小View之后把這個(gè)controller再展示出來便可以了。同理微信小程序其實(shí)也是在一個(gè)新的Window中做了一套新的邏輯。隨著現(xiàn)在手機(jī)性能的提升,多Window同時(shí)存在并不會(huì)造成嚴(yán)重卡頓,而衍生出來的一種新的開發(fā)方式。
實(shí)例代碼
上代碼,這個(gè)是根據(jù)網(wǎng)上找到的類似效果進(jìn)行了部分修改的,作者叫馮琦帆
SuspendTool
import Foundation import UIKit enum SuspendType { case none case single case multi } class SuspendTool: NSObject { static let sharedInstance = SuspendTool() private var suspendWindows: [SuspendWindow] = [] // var semicircle: Semicircle? var origin: CGPoint = CGPoint.init(x: 10, y: 300) static func showSuspendWindow(rootViewController: UIViewController, coverImageName: String) { let tool = SuspendTool.sharedInstance let window = SuspendWindow.init(rootViewController: rootViewController, coverImageName: coverImageName, frame: CGRect.init(origin: tool.origin, size: CGSize.init(width: radious, height: radious))) window.show() tool.suspendWindows.append(window) } static func replaceSuspendWindow(rootViewController: UIViewController, coverImageName: String) { let tool = SuspendTool.sharedInstance tool.suspendWindows.removeAll() let window = SuspendWindow.init(rootViewController: rootViewController, coverImageName: coverImageName, frame: CGRect.init(origin: tool.origin, size: CGSize.init(width: radious, height: radious))) window.show() tool.suspendWindows.append(window) } static func remove(suspendWindow: SuspendWindow) { UIView.animate(withDuration: 0.25, animations: { suspendWindow.alpha = 0 }) { (complete) in if let index = SuspendTool.sharedInstance.suspendWindows.index(of: suspendWindow) { SuspendTool.sharedInstance.suspendWindows.remove(at: index) } } } static func setLatestOrigin(origin: CGPoint) { SuspendTool.sharedInstance.origin = origin } }
SuspendWindow
import UIKit let radious: CGFloat = 82 class SuspendWindow: UIWindow { fileprivate let coverImageName: String fileprivate let space: CGFloat = 15 var containsRootViewController: UIViewController? init(rootViewController: UIViewController ,coverImageName: String, frame: CGRect) { self.coverImageName = coverImageName super.init(frame: frame) // self.rootViewController = rootViewController self.containsRootViewController = rootViewController } required init?(coder aDecoder: NSCoder) { fatalError("init(coder:) has not been implemented") } func show() { self.backgroundColor = UIColor.clear self.windowLevel = UIWindow.Level.alert - 1//UIWindowLevelAlert - 1 self.screen = UIScreen.main self.isHidden = false let bgView = UIView() bgView.isUserInteractionEnabled = true bgView.frame = self.bounds bgView.backgroundColor = UIColor.white bgView.layer.cornerRadius = radious / 2.0 bgView.layer.borderColor = UIColor.lightGray.cgColor bgView.layer.borderWidth = 5 bgView.layer.masksToBounds = true self.addSubview(bgView) bgView.addSubview(iconImageView) bgView.addSubview(timeLabel) let panGesture = UIPanGestureRecognizer.init(target: self, action: #selector(didPan(_:))) self.addGestureRecognizer(panGesture) let tapGesture = UITapGestureRecognizer.init(target: self, action: #selector(didTap(_:))) self.addGestureRecognizer(tapGesture) } @objc fileprivate func didTap(_ tapGesture: UITapGestureRecognizer) { SuspendTool.sharedInstance.origin = self.frame.origin self.containsRootViewController?.spread(from: self.self.frame.origin) SuspendTool.remove(suspendWindow: self) } @objc fileprivate func didPan(_ panGesture: UIPanGestureRecognizer) { let point = panGesture.translation(in: panGesture.view) var originX = self.frame.origin.x + point.x if originX < space { originX = space } else if originX > UIScreen.main.bounds.width - radious - space { originX = UIScreen.main.bounds.width - radious - space } var originY = self.frame.origin.y + point.y if originY < space { originY = space } else if originY > UIScreen.main.bounds.height - radious - space { originY = UIScreen.main.bounds.height - radious - space } self.frame = CGRect.init(x: originX, y: originY, width: self.bounds.width, height: self.bounds.height) if panGesture.state == UIGestureRecognizer.State.cancelled || panGesture.state == UIGestureRecognizer.State.ended || panGesture.state == UIGestureRecognizer.State.failed { self.adjustFrameAfterPan() } panGesture.setTranslation(CGPoint.zero, in: self) } fileprivate func adjustFrameAfterPan() { var originX: CGFloat = space if self.center.x < UIScreen.main.bounds.width / 2 { originX = space } else if self.center.x >= UIScreen.main.bounds.width / 2 { originX = UIScreen.main.bounds.width - radious - space } UIView.animate(withDuration: 0.25, animations: { self.frame = CGRect.init(x: originX, y: self.frame.origin.y, width: self.frame.size.width, height: self.frame.size.height) }) { (complete) in SuspendTool.setLatestOrigin(origin: self.frame.origin) } } lazy var timeLabel: UILabel = { let timeLabel = UILabel() timeLabel.frame = CGRect(x: 0, y: 55.5, width: 42, height: 13) timeLabel.center.x = self.bounds.size.width / 2 timeLabel.textAlignment = .center timeLabel.text = "0:00" timeLabel.textColor = UIColor.text timeLabel.font = UIFont.mediumFont(ofSize: 13) return timeLabel }() lazy var iconImageView: UIImageView = { let iconImageView = UIImageView.init(image: UIImage.init(named: coverImageName)) iconImageView.isUserInteractionEnabled = true iconImageView.frame = CGRect(x: 0, y: 12, width: 38, height: 38) iconImageView.center.x = self.bounds.size.width / 2 return iconImageView }() }
UIViewController+FF
import Foundation import UIKit extension UIViewController { func suspend(coverImageName: String, type: SuspendType) { if type == .none { self.navigationController?.popViewController(animated: true) return } self.view.layer.masksToBounds = true UIView.animate(withDuration: 0.25, animations: { self.view.layer.cornerRadius = radious / 2.0 self.view.frame = CGRect.init(origin: SuspendTool.sharedInstance.origin, size: CGSize.init(width: radious, height: radious)) self.view.layoutIfNeeded() }) { (complete) in self.navigationController?.popViewController(animated: false) if type == .single { SuspendTool.replaceSuspendWindow(rootViewController: self, coverImageName: coverImageName) } else { SuspendTool.showSuspendWindow(rootViewController: self, coverImageName: coverImageName) } } } func spread(from point: CGPoint) { if let isContain = self.navigationController?.viewControllers.contains(self), isContain { return } self.view.frame = CGRect.init(origin: point, size: CGSize.init(width: radious, height: radious)) //UIViewController.currentViewController() UIViewController.currentViewController().navigationController?.pushViewController(self, animated: false) UIView.animate(withDuration: 0.25, animations: { self.view.layer.cornerRadius = 0 self.view.frame = UIScreen.main.bounds self.view.layoutIfNeeded() }) } static func currentViewController() -> UIViewController { var rootViewController: UIViewController? = nil for window in UIApplication.shared.windows { if (window.rootViewController != nil) { rootViewController = window.rootViewController break } } var viewController = rootViewController while (true) { if viewController?.presentedViewController != nil { viewController = viewController!.presentedViewController } else if viewController!.isKind(of: UINavigationController.self) { viewController = (viewController as! UINavigationController).visibleViewController } else if viewController!.isKind(of: UITabBarController.self) { viewController = (viewController as! UITabBarController).selectedViewController } else { break } } return viewController! } }
總結(jié)
到此這篇關(guān)于Swift仿微信語音通話最小化時(shí)后效果的文章就介紹到這了,更多相關(guān)Swift微信語音通話最小化內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
深入解析Swift中switch語句對(duì)case的數(shù)據(jù)類型匹配的支持
這篇文章主要介紹了Swift中switch語句對(duì)case的數(shù)據(jù)類型匹配的支持,Swift中switch...case語句支持多種數(shù)據(jù)類型的匹配判斷,十分強(qiáng)大,需要的朋友可以參考下2016-04-04Swift免費(fèi)短信驗(yàn)證碼實(shí)現(xiàn)及動(dòng)態(tài)倒計(jì)時(shí)功能
這篇文章主要介紹了Swift免費(fèi)短信驗(yàn)證碼實(shí)現(xiàn)及動(dòng)態(tài)倒計(jì)時(shí)功能的相關(guān)資料,非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友可以參考下2017-02-02