Swift仿微信語音通話最小化時後的效果實例代碼

前言

最近碰到個需求,需要仿微信語音通話縮小化後,保持界面最上層有一個懸浮的小View可以一點擊就把剛剛縮放掉的界面再放回來,其實本質就是創造瞭一個新的Window,在這個window上創建瞭一個rootController並展示他,縮小化時是把controller dismiss掉瞭,再次點擊那個小View之後把這個controller再展示出來便可以瞭。同理微信小程序其實也是在一個新的Window中做瞭一套新的邏輯。隨著現在手機性能的提升,多Window同時存在並不會造成嚴重卡頓,而衍生出來的一種新的開發方式。

實例代碼

上代碼,這個是根據網上找到的類似效果進行瞭部分修改的,作者叫馮琦帆

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!
 }

}

總結

到此這篇關於Swift仿微信語音通話最小化時後效果的文章就介紹到這瞭,更多相關Swift微信語音通話最小化內容請搜索WalkonNet以前的文章或繼續瀏覽下面的相關文章希望大傢以後多多支持WalkonNet!

推薦閱讀: