首页 > 编程语言 > Swift仿微信语音通话最小化时后的效果实例代码
2021
03-05

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微信语音通话最小化内容请搜索自学编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持自学编程网!

编程技巧