swift3 缩放悬浮窗的实现

需求:实现一个可缩放界面的悬浮窗,当界面缩小时,可以跟随手势滑动,并且可以继续操作其他界面

思路:将悬浮窗看成一个视图,视图上有一个缩放按钮,再将需要缩放的视图控制器的view加入悬浮窗视图,缩放按钮在界面放大时,可以自定义按钮的大小及位置,缩放按钮在界面缩小时,按钮大小与悬浮窗大小一致

实现效果如下


具体实现:

1、自定义悬浮窗视图

(1)重写UIView的init(frame:CGRect)方法,并添加缩放按钮及缩放界面,添加视图滑动的手势,计算视图初始展示的中心点及位置,将视图加入window,并展示在最上层

enum SuspendedBallLocation:Int {case SuspendedBallLocation_LeftTop = 0case SuspendedBallLocation_Topcase SuspendedBallLocation_RightTopcase SuspendedBallLocation_Rightcase SuspendedBallLocation_RightBottomcase SuspendedBallLocation_Bottomcase SuspendedBallLocation_LeftBottomcase SuspendedBallLocation_Left}private var ballBtn:UIButton?private var timeLable:UILabel?private var currentCenter:CGPoint?private var panEndCenter:CGPoint = CGPoint.init(x: 0, y: 0)private var currentLocation:SuspendedBallLocation?var callingVC : ViewController!

override init(frame: CGRect) {super.init(frame: CGRect.init(x: 0, y: 0, width: frame.size.width, height: frame.size.height))//增加呼出界面let storyboard = UIStoryboard(name: "Main", bundle: nil)callingVC = (storyboard.instantiateViewController(withIdentifier: "VC")as?ViewController)!self.addSubview(callingVC.view)ballBtn = UIButton.init(type: .custom)ballBtn?.setBackgroundImage(UIImage.init(named: "shrink"), for: .normal)ballBtn?.imageView?.contentMode = .centerballBtn?.frame = CGRect.init(x: ScreenWidth-51, y: 40, width: 31, height: 23)ballBtn?.addTarget(self, action: #selector(clickBallViewAction), for: .touchUpInside)self.addSubview(self.ballBtn!)self.backgroundColor = UIColor.clearself.currentCenter = CGPoint.init(x: frame.size.width/2, y: frame.size.height/2) //初始位置self.calculateShowCenter(point: self.currentCenter!)self.configLocation(point: self.currentCenter!)//跟随手指拖动let moveGes:UIPanGestureRecognizer = UIPanGestureRecognizer.init(target: self, action: #selector(self.dragBallView))self.addGestureRecognizer(moveGes)//添加到window上self.ww_getKeyWindow().addSubview(self)//显示在视图的最上层self.ww_getKeyWindow().bringSubview(toFront: self)}
//MARK:- private utilityfunc ww_getKeyWindow() -> UIWindow {if UIApplication.shared.keyWindow == nil {return ((UIApplication.shared.delegate?.window)!)!}else{return UIApplication.shared.keyWindow!}}
//计算浮窗展示的中心点func calculateShowCenter(point:CGPoint) {unowned let weakSelf = selfUIView.animate(withDuration: 0.3) {weakSelf.center = CGPoint.init(x: point.x, y: point.y)}}
 //当前方位func configLocation(point:CGPoint) {if (point.x <= centerX*3 && point.y <= centerY*3) {self.currentLocation = .SuspendedBallLocation_LeftTop;}else if (point.x>centerX*3 && point.x= ScreenWidth-centerX*3 && point.y <= 3*centerY){self.currentLocation = .SuspendedBallLocation_RightTop;}else if (point.x == ScreenWidth-centerX && point.y>3*centerY && point.y= ScreenWidth-3*centerX && point.y >= ScreenHeight-3*centerY){self.currentLocation = .SuspendedBallLocation_RightBottom;}else if (point.y == ScreenHeight-centerY && point.x > 3*centerX && point.x= ScreenHeight-3*centerY){self.currentLocation = .SuspendedBallLocation_LeftBottom;}else if (point.x == centerX && point.y > 3*centerY && point.y

(2)缩放按钮点击方法:根据判断悬浮窗视图的width是否等于整个屏幕的width来决定视图执行的操作,若等于,则视图执行缩小操作,反之则放大

//MARK:- 悬浮窗按钮方法@objc func clickBallViewAction() {if self.frame.size.width == ScreenWidth {//缩小//固定缩放的中心点为右上角var frame = self.callingVC.view.frameself.layer.anchorPoint = CGPoint.init(x: 1, y: 0)self.frame = frameself.smallToShow()var callingVCFrame = self.callingVC.view.framecallingVCFrame.origin.y -= 70callingVCFrame.origin.x -= 50callingVCFrame.size.width += 100callingVCFrame.size.height += 140self.ballBtn?.frame = callingVCFrameballBtn?.setBackgroundImage(UIImage.init(named: "拨打中"), for: .normal)ballBtn?.imageView?.contentMode = .scaleToFilllet point = CGPoint.init(x: ScreenWidth-centerX, y:centerY) //初始位置self.calculateShowCenter(point: point)self.configLocation(point: point)}else{//放大//固定缩放的中心点为右上角let frame = CGRect.init(x: 0, y: 0, width: ScreenWidth, height: ScreenHeight)self.layer.anchorPoint = CGPoint.init(x: 1, y: 0)self.frame = frameself.bigToShow()self.frame = CGRect.init(x: 0, y: 0, width: ScreenWidth, height: ScreenHeight)self.ballBtn?.frame = CGRect.init(x: ScreenWidth-51, y: 40, width: 31, height: 23)ballBtn?.setBackgroundImage(UIImage.init(named: "shrink"), for: .normal)ballBtn?.imageView?.contentMode = .center}}
//放大func bigToShow(){let animation = CAKeyframeAnimation.init(keyPath: "transform")animation.duration = 0.5let values = NSMutableArray.init()values.add(NSValue.init(caTransform3D: CATransform3DMakeScale(0.2, 0.17, 1.0)))values.add(NSValue.init(caTransform3D: CATransform3DMakeScale(1.0, 1.0, 1.0)))animation.values = values as? [Any]self.layer.add(animation, forKey: nil)self.layer.transform = CATransform3DMakeScale(1, 1, 1)}//缩小func smallToShow(){let animation = CAKeyframeAnimation.init(keyPath: "transform")animation.duration = 0.5let values = NSMutableArray.init()values.add(NSValue.init(caTransform3D: CATransform3DMakeScale(1.0, 1.0, 1.0)))values.add(NSValue.init(caTransform3D: CATransform3DMakeScale(0.2, 0.17, 1.0)))animation.values = values as? [Any]self.layer.add(animation, forKey: nil)self.layer.transform = CATransform3DMakeScale(0.2, 0.17, 1)}
(3)滑动手势方法:根据手势最后停留的中心点计算悬浮窗停留的中心位置,中心点区域主要氛围9个部分,如图所示:


具体代码如下:

//跟随手指拖动@objc func dragBallView(panGes:UIPanGestureRecognizer) {if self.frame.size.width != ScreenWidth {let translation:CGPoint = panGes.translation(in: self.ww_getKeyWindow())let center:CGPoint = self.centerself.center = CGPoint.init(x: center.x+translation.x, y: center.y+translation.y)panGes .setTranslation(CGPoint.init(x: 0, y: 0), in: self.ww_getKeyWindow())if panGes.state == UIGestureRecognizerState.ended{self.panEndCenter = self.centerself.caculateBallCenter()}}}//计算中心位置func caculateBallCenter() {if (self.panEndCenter.x>centerX && self.panEndCenter.x < ScreenWidth-centerX && self.panEndCenter.y>centerY && self.panEndCenter.yScreenHeight-3*centerY){//                左下角//if self.panEndCenter.x < 4*centerX {self.calculateBallNewCenter(point: CGPoint.init(x: centerX+2*centerY, y: ScreenHeight-4*centerY-10))}else{self.calculateBallNewCenter(point: CGPoint.init(x: self.panEndCenter.x, y: ScreenHeight-4*centerY-10))}}else{if (self.panEndCenter.x<=ScreenWidth/2) {self.calculateBallNewCenter(point: CGPoint.init(x: centerX+2*centerY, y: self.panEndCenter.y))}else{self.calculateBallNewCenter(point: CGPoint.init(x: ScreenWidth-centerX, y: self.panEndCenter.y))}}}else{if (self.panEndCenter.x<=centerX && self.panEndCenter.y<=centerY){self.calculateBallNewCenter(point: CGPoint.init(x: 3*centerX, y: centerY))}else if (self.panEndCenter.x>=ScreenWidth-centerX && self.panEndCenter.y<=centerY){//右上角self.calculateBallNewCenter(point: CGPoint.init(x: ScreenWidth-centerX, y:centerY))}else if (self.panEndCenter.x>=ScreenWidth-centerX && self.panEndCenter.y>=ScreenHeight-centerY){self.calculateBallNewCenter(point: CGPoint.init(x: ScreenWidth-centerX, y: ScreenHeight-centerY))}else if(self.panEndCenter.x<=centerX && self.panEndCenter.y>=ScreenHeight-centerY){self.calculateBallNewCenter(point: CGPoint.init(x: centerX, y: ScreenHeight-centerY))}else if (self.panEndCenter.x>centerX && self.panEndCenter.xcenterX && self.panEndCenter.xScreenHeight-centerY){self.calculateBallNewCenter(point: CGPoint.init(x: self.panEndCenter.x, y:ScreenHeight-centerY))}else if (self.panEndCenter.y>centerY && self.panEndCenter.ycenterY && self.panEndCenter.yScreenWidth-centerX){//右下角if self.panEndCenter.y>ScreenHeight-4*centerY {self.calculateBallNewCenter(point: CGPoint.init(x: ScreenWidth-centerX, y:ScreenHeight-4*centerY-10))}else{self.calculateBallNewCenter(point: CGPoint.init(x: ScreenWidth-centerX, y:self.panEndCenter.y))}}}}
//计算浮窗新的中心点func calculateBallNewCenter(point:CGPoint) {self.currentCenter = pointself.configLocation(point: point)unowned let weakSelf = selfUIView.animate(withDuration: 0.3) {weakSelf.center = CGPoint.init(x: point.x, y: point.y)}}

2、点击界面“点击弹出悬浮窗”按钮,弹出界面

整体框架如图所示


具体代码如下:

import UIKitvar ballView : IMOSuspendedBallView!class FViewController: UIViewController {override func viewDidLoad() {super.viewDidLoad()UserDefaults.standard.setValue("0", forKey: "ballViewSave")// Do any additional setup after loading the view.}@IBAction func click(_ sender: Any) {if UserDefaults.standard.object(forKey: "ballViewSave")as! String == "1" {let aleat = UIAlertController(title: "提示", message:"当前已有悬浮窗", preferredStyle: UIAlertControllerStyle.alert)let tempAction = UIAlertAction(title: "知道了", style: .cancel) { (action) in}aleat.addAction(tempAction)self.present(aleat, animated: true, completion: {})}else{ballView = IMOSuspendedBallView.init(frame: CGRect.init(x: 0, y: 0, width: ScreenWidth, height: ScreenHeight))UserDefaults.standard.setValue("1", forKey: "ballViewSave")}}override func didReceiveMemoryWarning() {super.didReceiveMemoryWarning()// Dispose of any resources that can be recreated.}/*// MARK: - Navigation// In a storyboard-based application, you will often want to do a little preparation before navigationoverride func prepare(for segue: UIStoryboardSegue, sender: Any?) {// Get the new view controller using segue.destinationViewController.// Pass the selected object to the new view controller.}*/}

3、弹出界面代码如下:

import UIKitclass ViewController: UIViewController {override func viewDidLoad() {super.viewDidLoad()self.view.backgroundColor = UIColor.lightGray}@IBAction func buttonClick(_ sender: Any) {ballView.dismissView()}}

综上所述,具体代码实现:swift 实现可缩放悬浮窗


本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!

相关文章

立即
投稿

微信公众账号

微信扫一扫加关注

返回
顶部