├── WXProgressWindow ├── Demo │ ├── demo.gif │ ├── progressWindow.png │ ├── ViewController.swift │ ├── Assets.xcassets │ │ └── AppIcon.appiconset │ │ │ └── Contents.json │ ├── Info.plist │ ├── TestNoNavViewController.swift │ ├── TestViewController.swift │ ├── AppDelegate.swift │ ├── LaunchScreen.storyboard │ └── Base.lproj │ │ └── Main.storyboard └── WXProgressWindow │ ├── Extensions.swift │ ├── WXProgressCircleTransition.swift │ ├── WXProgressWindowManager.swift │ └── WXProgressViewController.swift ├── WXProgressWindow.xcodeproj ├── project.xcworkspace │ └── contents.xcworkspacedata ├── xcuserdata │ └── luo.xcuserdatad │ │ ├── xcschemes │ │ ├── xcschememanagement.plist │ │ └── WXProgressWindow.xcscheme │ │ └── xcdebugger │ │ └── Breakpoints_v2.xcbkptlist └── project.pbxproj └── README.md /WXProgressWindow/Demo/demo.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/luowenxing/WXProgressWindow/HEAD/WXProgressWindow/Demo/demo.gif -------------------------------------------------------------------------------- /WXProgressWindow/Demo/progressWindow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/luowenxing/WXProgressWindow/HEAD/WXProgressWindow/Demo/progressWindow.png -------------------------------------------------------------------------------- /WXProgressWindow.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /WXProgressWindow.xcodeproj/xcuserdata/luo.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | WXProgressWindow.xcscheme 8 | 9 | orderHint 10 | 0 11 | 12 | 13 | SuppressBuildableAutocreation 14 | 15 | B175CDD81D3795CA009B5D52 16 | 17 | primary 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /WXProgressWindow/Demo/ViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.swift 3 | // WXProgressWindow 4 | // 5 | // Created by Luo on 7/14/16. 6 | // Copyright © 2016 Luo. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class ViewController: UIViewController { 12 | 13 | override func viewDidLoad() { 14 | self.view.backgroundColor = UIColor.lightGrayColor() 15 | super.viewDidLoad() 16 | // Do any additional setup after loading the view, typically from a nib. 17 | } 18 | 19 | override func didReceiveMemoryWarning() { 20 | super.didReceiveMemoryWarning() 21 | // Dispose of any resources that can be recreated. 22 | } 23 | 24 | @IBAction func btnPresentTouch(sender: AnyObject) { 25 | let sb = UIStoryboard(name: "Main", bundle: nil) 26 | let vc = sb.instantiateViewControllerWithIdentifier("TestViewController") 27 | let nc = UINavigationController(rootViewController: vc) 28 | self.presentViewController(nc, animated: true, completion: nil) 29 | 30 | } 31 | @IBAction func btnPresentNoNavTouch(sender: AnyObject) { 32 | 33 | let sb = UIStoryboard(name: "Main", bundle: nil) 34 | let vc = sb.instantiateViewControllerWithIdentifier("TestNoNavViewController") 35 | self.presentViewController(vc, animated: true, completion: nil) 36 | } 37 | 38 | } 39 | 40 | -------------------------------------------------------------------------------- /WXProgressWindow/Demo/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "29x29", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "29x29", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "40x40", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "40x40", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "60x60", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "60x60", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "idiom" : "ipad", 35 | "size" : "29x29", 36 | "scale" : "1x" 37 | }, 38 | { 39 | "idiom" : "ipad", 40 | "size" : "29x29", 41 | "scale" : "2x" 42 | }, 43 | { 44 | "idiom" : "ipad", 45 | "size" : "40x40", 46 | "scale" : "1x" 47 | }, 48 | { 49 | "idiom" : "ipad", 50 | "size" : "40x40", 51 | "scale" : "2x" 52 | }, 53 | { 54 | "idiom" : "ipad", 55 | "size" : "76x76", 56 | "scale" : "1x" 57 | }, 58 | { 59 | "idiom" : "ipad", 60 | "size" : "76x76", 61 | "scale" : "2x" 62 | } 63 | ], 64 | "info" : { 65 | "version" : 1, 66 | "author" : "xcode" 67 | } 68 | } -------------------------------------------------------------------------------- /WXProgressWindow/WXProgressWindow/Extensions.swift: -------------------------------------------------------------------------------- 1 | // 2 | // extensions.swift 3 | // WXProgressWindow 4 | // 5 | // Created by Luo on 7/14/16. 6 | // Copyright © 2016 Luo. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | extension UIScreen { 12 | var compatibleBounds:CGRect{//iOS7 mainScreen bounds 不随设备旋转 13 | var rect = self.bounds 14 | if NSFoundationVersionNumber < NSFoundationVersionNumber_iOS_8_0 { 15 | let orientation = UIApplication.sharedApplication().statusBarOrientation 16 | if orientation.isLandscape{ 17 | rect.size.width = self.bounds.height 18 | rect.size.height = self.bounds.width 19 | } 20 | } 21 | return rect 22 | } 23 | } 24 | 25 | extension UIColor { 26 | class func hexColor(hex:String) -> UIColor { 27 | var cString:String = hex.stringByTrimmingCharactersInSet(NSCharacterSet.whitespaceAndNewlineCharacterSet() as NSCharacterSet).uppercaseString 28 | 29 | if (cString.hasPrefix("#")) { 30 | cString = cString.substringFromIndex(cString.startIndex.advancedBy(1)) 31 | } 32 | 33 | if ((cString.characters.count) != 6) { 34 | return UIColor.grayColor() 35 | } 36 | 37 | var rgbValue:UInt32 = 0 38 | NSScanner(string: cString).scanHexInt(&rgbValue) 39 | 40 | return UIColor( 41 | red: CGFloat((rgbValue & 0xFF0000) >> 16) / 255.0, 42 | green: CGFloat((rgbValue & 0x00FF00) >> 8) / 255.0, 43 | blue: CGFloat(rgbValue & 0x0000FF) / 255.0, 44 | alpha: CGFloat(1.0) 45 | ) 46 | } 47 | } 48 | 49 | -------------------------------------------------------------------------------- /WXProgressWindow/Demo/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | LSRequiresIPhoneOS 24 | 25 | UILaunchStoryboardName 26 | LaunchScreen 27 | UIMainStoryboardFile 28 | Main 29 | UIRequiredDeviceCapabilities 30 | 31 | armv7 32 | 33 | UISupportedInterfaceOrientations 34 | 35 | UIInterfaceOrientationPortrait 36 | UIInterfaceOrientationLandscapeLeft 37 | UIInterfaceOrientationLandscapeRight 38 | 39 | UISupportedInterfaceOrientations~ipad 40 | 41 | UIInterfaceOrientationPortrait 42 | UIInterfaceOrientationPortraitUpsideDown 43 | UIInterfaceOrientationLandscapeLeft 44 | UIInterfaceOrientationLandscapeRight 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # WXProgressWindow 2 | A progress window hide presented view controller of background work with progress(e.g. download),and return to view controller by tap.The progress window also can be dragged to place in somewhere else. 3 | 4 | # Demo 5 | ![progressWindow.png](https://github.com/luowenxing/WXProgressWindow/blob/master/WXProgressWindow/Demo/progressWindow.png) 6 | 7 | ![Demo.gif](https://github.com/luowenxing/WXProgressWindow/blob/master/WXProgressWindow/Demo/demo.gif) 8 | 9 | # Installation 10 | There is no other dependecy in it.Just add WXProgressWindow folder to your project. 11 | 12 | # Usage 13 | * Implement delegate method. 14 | ``` 15 | @objc protocol WXProgressWindowManagerDelegate:NSObjectProtocol { 16 | func currentProgress() -> Float 17 | optional func currentProgressText() -> String? 18 | } 19 | ``` 20 | * Init `WXProgressWindowManager` in view controller to present. 21 | ``` 22 | private lazy var progressManager:WXProgressWindowManager = { 23 | //Pass self.navigationController! to rootViewController if your view controller is wrapped in a navigationController. 24 | let manager = WXProgressWindowManager(rootViewController: self, delegate: self) 25 | //manager.arcColor = UIColor.redColor() 26 | //manager.cycleColor = UIColor.grayColor() 27 | //manager.fontSize = 13 28 | //manager.progressRect = CGRect(x: UIScreen.mainScreen().compatibleBounds.width - 50 - 100, y: 20, width: 50, height: 50) 29 | return manager 30 | }() 31 | ``` 32 | * Call instance function `showProgressWindow()` to hide your view controller and show the progress window. 33 | * Call instance function `dismissProgressWindow()` to dismiss your view controller and destory progress window. 34 | 35 | # Detail 36 | http://www.jianshu.com/p/34701b334ed7 37 | 38 | -------------------------------------------------------------------------------- /WXProgressWindow/Demo/TestNoNavViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // TestNoNavViewController.swift 3 | // WXProgressWindow 4 | // 5 | // Created by Luo on 7/14/16. 6 | // Copyright © 2016 Luo. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class TestNoNavViewController:UIViewController,WXProgressWindowManagerDelegate { 12 | 13 | private var timer:NSTimer! 14 | @IBOutlet weak var labelProgress: UILabel! 15 | @IBOutlet weak var progress: UIProgressView! 16 | 17 | override func viewDidLoad() { 18 | self.progress.progress = 0 19 | } 20 | 21 | func updateProgress() { 22 | if self.progress.progress < 1 { 23 | self.progress.progress += 0.01 24 | self.labelProgress.text = "\(Int(self.progress.progress * 100))%" 25 | } else { 26 | self.timer.invalidate() 27 | } 28 | } 29 | 30 | @IBAction func btnStartTouch(sender: AnyObject) { 31 | self.timer = NSTimer(timeInterval: 0.1, target: self, selector: #selector(TestViewController.updateProgress), userInfo: nil, repeats: true) 32 | NSRunLoop.currentRunLoop().addTimer(self.timer, forMode: NSDefaultRunLoopMode) 33 | } 34 | 35 | 36 | 37 | //MARK:ProgressWindowManager 38 | private lazy var progressManager:WXProgressWindowManager! = WXProgressWindowManager(rootViewController: self, delegate:self) 39 | 40 | func currentProgress() -> Float { 41 | return progress.progress 42 | } 43 | 44 | @IBAction func btnHideTouch(sender: AnyObject) { 45 | self.progressManager.showProgressView() 46 | } 47 | 48 | @IBAction func btnCancelTouch(sender: AnyObject) { 49 | self.progressManager.dismissProgressView() 50 | } 51 | 52 | } -------------------------------------------------------------------------------- /WXProgressWindow/Demo/TestViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // TestViewController.swift 3 | // WXProgressWindow 4 | // 5 | // Created by Luo on 7/14/16. 6 | // Copyright © 2016 Luo. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class TestViewController:UIViewController,WXProgressWindowManagerDelegate { 12 | 13 | private var timer:NSTimer! 14 | @IBOutlet weak var labelProgress: UILabel! 15 | @IBOutlet weak var progress: UIProgressView! 16 | 17 | override func viewDidLoad() { 18 | self.progress.progress = 0 19 | } 20 | 21 | func updateProgress() { 22 | if self.progress.progress < 1 { 23 | self.progress.progress += 0.01 24 | self.labelProgress.text = "\(Int(self.progress.progress * 100))%" 25 | } else { 26 | self.timer.invalidate() 27 | } 28 | } 29 | 30 | @IBAction func btnStartTouch(sender: AnyObject) { 31 | self.timer = NSTimer(timeInterval: 0.1, target: self, selector: #selector(TestViewController.updateProgress), userInfo: nil, repeats: true) 32 | NSRunLoop.currentRunLoop().addTimer(self.timer, forMode: NSDefaultRunLoopMode) 33 | } 34 | 35 | 36 | 37 | //MARK:ProgressWindowManager 38 | 39 | private lazy var progressManager:WXProgressWindowManager = WXProgressWindowManager(rootViewController: self.navigationController!, delegate: self) 40 | 41 | @IBAction func btnHideTouch(sender: AnyObject) { 42 | self.progressManager.showProgressView() 43 | } 44 | 45 | @IBAction func btnCancelTouch(sender: AnyObject) { 46 | self.progressManager.dismissProgressView() 47 | } 48 | 49 | func currentProgress() -> Float { 50 | return progress.progress 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /WXProgressWindow/Demo/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.swift 3 | // WXProgressWindow 4 | // 5 | // Created by Luo on 7/14/16. 6 | // Copyright © 2016 Luo. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | @UIApplicationMain 12 | class AppDelegate: UIResponder, UIApplicationDelegate { 13 | 14 | var window: UIWindow? 15 | 16 | 17 | func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool { 18 | // Override point for customization after application launch. 19 | return true 20 | } 21 | 22 | func applicationWillResignActive(application: UIApplication) { 23 | // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. 24 | // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game. 25 | } 26 | 27 | func applicationDidEnterBackground(application: UIApplication) { 28 | // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. 29 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 30 | } 31 | 32 | func applicationWillEnterForeground(application: UIApplication) { 33 | // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background. 34 | } 35 | 36 | func applicationDidBecomeActive(application: UIApplication) { 37 | // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. 38 | } 39 | 40 | func applicationWillTerminate(application: UIApplication) { 41 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 42 | } 43 | 44 | 45 | } 46 | 47 | -------------------------------------------------------------------------------- /WXProgressWindow.xcodeproj/xcuserdata/luo.xcuserdatad/xcschemes/WXProgressWindow.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 39 | 40 | 41 | 42 | 43 | 44 | 54 | 56 | 62 | 63 | 64 | 65 | 66 | 67 | 73 | 75 | 81 | 82 | 83 | 84 | 86 | 87 | 90 | 91 | 92 | -------------------------------------------------------------------------------- /WXProgressWindow/Demo/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 27 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /WXProgressWindow/WXProgressWindow/WXProgressCircleTransition.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ProgressWindowTransition.swift 3 | // WXProgressWindow 4 | // 5 | // Created by Luo on 7/14/16. 6 | // Copyright © 2016 Luo. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | 12 | enum WXProgressCircleTransitionType { 13 | case Present 14 | case Dismiss 15 | } 16 | 17 | class WXProgressCircleTransition:NSObject,UIViewControllerAnimatedTransitioning { 18 | 19 | var type:WXProgressCircleTransitionType 20 | 21 | init(type:WXProgressCircleTransitionType) { 22 | self.type = type 23 | } 24 | 25 | func animateTransition(transitionContext: UIViewControllerContextTransitioning) { 26 | if self.type == .Present { 27 | self.animateTransitionPresent(transitionContext) 28 | } else { 29 | self.animateTransitionDismiss(transitionContext) 30 | } 31 | } 32 | 33 | func transitionDuration(transitionContext: UIViewControllerContextTransitioning?) -> NSTimeInterval { 34 | return 0.35 35 | } 36 | 37 | func animationEnded(transitionCompleted: Bool) { 38 | 39 | } 40 | 41 | private func animateTransitionPresent(transitionContext: UIViewControllerContextTransitioning) { 42 | guard let fromVC = transitionContext.viewControllerForKey(UITransitionContextFromViewControllerKey),toVC = transitionContext.viewControllerForKey(UITransitionContextToViewControllerKey) as? WXProgressViewController else { 43 | return 44 | } 45 | if let containerView = transitionContext.containerView() { 46 | containerView.addSubview(fromVC.view) 47 | let x = max(toVC.progressRect.origin.x,containerView.frame.size.width - toVC.progressRect.origin.x) 48 | let y = max(toVC.progressRect.origin.y,containerView.frame.size.height - toVC.progressRect.origin.y) 49 | let radius = sqrt(x*x + y*y) 50 | let startCycle = UIBezierPath(arcCenter: containerView.center, radius: radius, startAngle: 0, endAngle: CGFloat(M_PI * 2), clockwise:true) 51 | let endCycle = UIBezierPath(ovalInRect: toVC.progressRect) 52 | 53 | let maskLayer = CAShapeLayer() 54 | maskLayer.path = startCycle.CGPath 55 | fromVC.view.layer.mask = maskLayer 56 | 57 | let maskAnimation = CABasicAnimation(keyPath: "path") 58 | maskAnimation.delegate = self 59 | maskAnimation.fromValue = startCycle.CGPath 60 | maskAnimation.toValue = endCycle.CGPath 61 | maskAnimation.duration = self.transitionDuration(transitionContext) 62 | maskAnimation.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseInEaseOut) 63 | maskAnimation.setValue(transitionContext, forKey: "transitionContext") 64 | maskAnimation.setValue(fromVC.view, forKey: "maskedView") 65 | maskAnimation.fillMode = kCAFillModeForwards 66 | maskAnimation.removedOnCompletion = false 67 | maskLayer.addAnimation(maskAnimation, forKey: "path") 68 | 69 | } 70 | } 71 | 72 | private func animateTransitionDismiss(transitionContext: UIViewControllerContextTransitioning) { 73 | guard let fromVC = transitionContext.viewControllerForKey(UITransitionContextFromViewControllerKey) as? WXProgressViewController,toVC = transitionContext.viewControllerForKey(UITransitionContextToViewControllerKey) else { 74 | return 75 | } 76 | if let containerView = transitionContext.containerView() { 77 | fromVC.view.removeFromSuperview() 78 | containerView.addSubview(toVC.view) 79 | let x = max(fromVC.progressRect.origin.x,containerView.frame.size.width - fromVC.progressRect.origin.x) 80 | let y = max(fromVC.progressRect.origin.y,containerView.frame.size.height - fromVC.progressRect.origin.y) 81 | let radius = sqrt(x*x + y*y) 82 | let endCycle = UIBezierPath(arcCenter: containerView.center, radius: radius, startAngle: 0, endAngle: CGFloat(M_PI * 2), clockwise:true) 83 | let startCycle = UIBezierPath(ovalInRect: fromVC.progressRect) 84 | 85 | let maskLayer = CAShapeLayer() 86 | maskLayer.path = startCycle.CGPath 87 | toVC.view.layer.mask = maskLayer 88 | 89 | let maskAnimation = CABasicAnimation(keyPath: "path") 90 | maskAnimation.delegate = self 91 | maskAnimation.fromValue = startCycle.CGPath 92 | maskAnimation.toValue = endCycle.CGPath 93 | maskAnimation.duration = self.transitionDuration(transitionContext) 94 | maskAnimation.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseInEaseOut) 95 | maskAnimation.setValue(transitionContext, forKey: "transitionContext") 96 | maskAnimation.setValue(toVC.view, forKey: "maskedView") 97 | maskAnimation.fillMode = kCAFillModeForwards 98 | maskAnimation.removedOnCompletion = false 99 | maskLayer.addAnimation(maskAnimation, forKey: "path") 100 | 101 | } 102 | 103 | } 104 | 105 | override func animationDidStop(anim: CAAnimation, finished flag: Bool) { 106 | if let context = anim.valueForKey("transitionContext") as? UIViewControllerContextTransitioning,maskedView = anim.valueForKey("maskedView") as? UIView { 107 | context.completeTransition(true) 108 | maskedView.layer.mask = nil 109 | } 110 | } 111 | } 112 | 113 | -------------------------------------------------------------------------------- /WXProgressWindow/WXProgressWindow/WXProgressWindowManager.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ProgressWindow.swift 3 | // WXProgressWindow 4 | // 5 | // Created by Luo on 7/14/16. 6 | // Copyright © 2016 Luo. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | enum WXProgressWindowStatus { 12 | case InitialView 13 | case RootView 14 | case ProgressView 15 | 16 | } 17 | 18 | class WXProgressWindow:UIWindow { 19 | weak var manager:WXProgressWindowManager! 20 | override func hitTest(point: CGPoint, withEvent event: UIEvent?) -> UIView? { 21 | let hitView = super.hitTest(point, withEvent: event) 22 | //显示悬浮窗时,只响应悬浮窗区域的手势事件 23 | if let m = self.manager where m.status == .ProgressView { 24 | if let _ = hitView as? WXProgressView { 25 | return hitView 26 | } else { 27 | return nil 28 | } 29 | } 30 | return hitView 31 | } 32 | } 33 | 34 | @objc protocol WXProgressWindowManagerDelegate:NSObjectProtocol { 35 | func currentProgress() -> Float 36 | optional func currentProgressText() -> String? 37 | } 38 | 39 | class WXProgressWindowManager:NSObject,UIViewControllerTransitioningDelegate,WXProgressViewControllerDelegate { 40 | 41 | deinit { 42 | NSLog("deinit ProgressWindowManager") 43 | } 44 | 45 | var progressRect:CGRect { 46 | get { 47 | return self.progressVC.progressRect 48 | } 49 | set { 50 | self.progressVC.progressRect = newValue 51 | } 52 | } 53 | var cycleColor:UIColor { 54 | get { 55 | return self.progressVC.cycleColor 56 | } 57 | set { 58 | self.progressVC.cycleColor = newValue 59 | } 60 | } 61 | var arcColor:UIColor { 62 | get { 63 | return self.progressVC.arcColor 64 | } 65 | set { 66 | self.progressVC.arcColor = newValue 67 | } 68 | } 69 | var fontSize:CGFloat { 70 | get { 71 | return self.progressVC.fontSize 72 | } 73 | set { 74 | self.progressVC.fontSize = newValue 75 | } 76 | } 77 | 78 | var status:WXProgressWindowStatus = .InitialView 79 | private var prevWindow:UIWindow! 80 | private weak var rootViewController:UIViewController! 81 | private weak var delegate:WXProgressWindowManagerDelegate? 82 | private lazy var progressVC:WXProgressViewController! = WXProgressViewController(delegate: self) 83 | private lazy var snapView:UIView = self.rootViewController.view.snapshotViewAfterScreenUpdates(false) 84 | private lazy var window:WXProgressWindow! = { 85 | let window = WXProgressWindow(frame: UIScreen.mainScreen().bounds) 86 | window.backgroundColor = UIColor.clearColor() 87 | window.layer.masksToBounds = true 88 | window.manager = self 89 | return window 90 | }() 91 | 92 | init(rootViewController:UIViewController,delegate:WXProgressWindowManagerDelegate) { 93 | super.init() 94 | self.rootViewController = rootViewController 95 | self.delegate = delegate 96 | } 97 | 98 | //MARK:界面切换 99 | func showProgressView() { 100 | if self.status == .InitialView { 101 | if self.window.hidden { 102 | // 在window设置rootVC为snapViewVC,防止闪屏 103 | // 使用vc包裹snapView为了使旋转正确。只有vc会处理旋转,view不会。此处也可自行处理旋转后直接window.addSubview 104 | let vc = UIViewController() 105 | vc.view.addSubview(self.snapView) 106 | vc.view.layoutIfNeeded() 107 | self.window.hidden = false 108 | self.window.rootViewController = vc 109 | self.performSelector(#selector(WXProgressWindowManager.showProgressView), withObject: nil, afterDelay: 0) 110 | return 111 | } 112 | self.status = .RootView 113 | self.rootViewController.dismissViewControllerAnimated(false) { 114 | self.window.rootViewController = self.rootViewController 115 | // 防止闪屏 116 | self.performSelector(#selector(WXProgressWindowManager.showProgressView), withObject: nil, afterDelay: 0) 117 | } 118 | } 119 | else if self.status == .RootView{ 120 | self.status = .ProgressView 121 | self.progressVC.transitioningDelegate = self 122 | self.rootViewController.transitioningDelegate = self 123 | //设置transitionDelegate后present就有自定义动画效果 124 | self.rootViewController.presentViewController(self.progressVC, animated: true) { 125 | // iOS8以上的bug,present之后又present一个view,这个view不会被加到window上,需要手动添加 126 | self.window.addSubview(self.progressVC.view) 127 | self.progressVC.startCADisplayLink() 128 | } 129 | } 130 | } 131 | 132 | func showRootView() { 133 | progressVC.stopCADisplayLink() 134 | self.status = .RootView 135 | progressVC.dismissViewControllerAnimated(true, completion: nil) 136 | } 137 | 138 | func dismissProgressView(complete:(()->Void)? = nil) { 139 | if self.status == .InitialView { 140 | self.rootViewController.dismissViewControllerAnimated(true, completion: nil) 141 | } 142 | else if self.status == .RootView { 143 | UIView.animateWithDuration(0.35, delay: 0, options: .CurveEaseInOut , animations: { 144 | // 处理iOS7的的window消失动画,因为iOS7的bounds不随系统旋转而改变 145 | if NSFoundationVersionNumber < NSFoundationVersionNumber_iOS_8_0 { 146 | if self.rootViewController.interfaceOrientation.isPortrait { 147 | self.window.frame.origin.y = UIScreen.mainScreen().bounds.height 148 | } else { 149 | self.window.frame.origin.x = -UIScreen.mainScreen().bounds.width 150 | } 151 | } else { 152 | self.window.frame.origin.y = UIScreen.mainScreen().bounds.height 153 | } 154 | }) { 155 | _ in 156 | self.window.hidden = true 157 | self.window.rootViewController = nil 158 | } 159 | } else { 160 | self.window.hidden = true 161 | self.progressVC.stopCADisplayLink() 162 | self.progressVC.dismissViewControllerAnimated(false) { 163 | self.window.rootViewController = nil 164 | self.window = nil 165 | } 166 | } 167 | } 168 | 169 | //MARK:ProgressViewControllerDelegate 170 | func getProgress() -> Float { 171 | if let delegate = self.delegate { 172 | return delegate.currentProgress() 173 | } 174 | return 0 175 | } 176 | 177 | func getProgressText() -> String? { 178 | if let delegate = self.delegate { 179 | return delegate.currentProgressText?() 180 | } 181 | return nil 182 | } 183 | 184 | //MARK:UIViewControllerTransitioningDelegate 185 | func animationControllerForDismissedController(dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning? { 186 | return WXProgressCircleTransition(type: .Dismiss) 187 | } 188 | 189 | func animationControllerForPresentedController(presented: UIViewController, presentingController presenting: UIViewController, sourceController source: UIViewController) -> UIViewControllerAnimatedTransitioning? { 190 | return WXProgressCircleTransition(type: .Present) 191 | } 192 | 193 | } 194 | -------------------------------------------------------------------------------- /WXProgressWindow/WXProgressWindow/WXProgressViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ProgressWindowController.swift 3 | // CMBMobile 4 | // 5 | // Created by Luo on 7/11/16. 6 | // Copyright © 2016 Yst-WHB. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import UIKit 11 | 12 | class WXProgressView:UIView { 13 | 14 | } 15 | 16 | protocol WXProgressViewControllerDelegate:NSObjectProtocol { 17 | func getProgress() -> Float 18 | func getProgressText() -> String? 19 | func showRootView() 20 | } 21 | 22 | class WXProgressViewController:UIViewController { 23 | 24 | weak var delegate: WXProgressViewControllerDelegate? 25 | init(delegate:WXProgressViewControllerDelegate) { 26 | self.delegate = delegate 27 | super.init(nibName: nil, bundle: nil) 28 | } 29 | 30 | required init?(coder aDecoder: NSCoder) { 31 | super.init(coder: aDecoder) 32 | } 33 | 34 | var progressRect:CGRect = CGRect(x: UIScreen.mainScreen().compatibleBounds.width - 50 - 100, y: 20, width: 50, height: 50) 35 | var cycleColor:UIColor = UIColor.hexColor("#AFD8FB") 36 | var arcColor:UIColor = UIColor.hexColor("#1F7FEC") 37 | lazy var fontSize:CGFloat = self.progressRect.size.width / 8.0 * 3.0 38 | 39 | private lazy var progressView:WXProgressView = WXProgressView() 40 | private lazy var progressLabel = UILabel() 41 | private lazy var circleLayer:CAShapeLayer! = self.getCycleLayer(self.cycleColor, startAngle: 0, endAngle: CGFloat(M_PI * 2)) 42 | private lazy var arcLayer:CAShapeLayer! = self.getCycleLayer(self.arcColor, startAngle: -CGFloat(M_PI_2), endAngle: -CGFloat(M_PI_2)) 43 | private var displayLink:CADisplayLink! 44 | 45 | override func viewDidLayoutSubviews() { 46 | super.viewDidLayoutSubviews() 47 | self.circleLayer.frame = self.progressView.bounds 48 | } 49 | 50 | 51 | override func willRotateToInterfaceOrientation(toInterfaceOrientation: UIInterfaceOrientation, duration: NSTimeInterval) { 52 | if self.interfaceOrientation.isPortrait != toInterfaceOrientation.isPortrait { 53 | let size = self.view.frame.size 54 | self.resetProgressViewFrameOnRotate(size.height, toHeight: size.width) 55 | } 56 | } 57 | 58 | // 处理iOS7旋转bug 59 | override func didRotateFromInterfaceOrientation(fromInterfaceOrientation: UIInterfaceOrientation) { 60 | let size = self.view.frame.size 61 | self.resetProgressViewFrameOnRotate(size.width, toHeight: size.height) 62 | } 63 | 64 | 65 | override func viewDidLoad() { 66 | super.viewDidLoad() 67 | self.view.backgroundColor = UIColor.clearColor() 68 | 69 | self.progressView.frame = self.progressRect 70 | self.progressView.backgroundColor = UIColor.whiteColor() 71 | self.progressView.layer.cornerRadius = self.progressRect.width / 2.0 72 | self.view.addSubview(progressView) 73 | 74 | let tapRecognizer = UITapGestureRecognizer(target: self, action: #selector(WXProgressViewController.onTap)) 75 | let panRecognizer = UIPanGestureRecognizer(target: self, action: #selector(WXProgressViewController.onPan)) 76 | self.progressView.addGestureRecognizer(tapRecognizer) 77 | self.progressView.addGestureRecognizer(panRecognizer) 78 | 79 | self.progressLabel.translatesAutoresizingMaskIntoConstraints = false 80 | self.progressLabel.text = "0" 81 | self.progressLabel.textColor = arcColor 82 | self.progressLabel.font = UIFont.boldSystemFontOfSize(fontSize) 83 | self.progressView.addSubview(self.progressLabel) 84 | let constraintX = NSLayoutConstraint(item: progressLabel, attribute: .CenterX, relatedBy: .Equal, toItem: self.progressView, attribute: .CenterX, multiplier: 1, constant: 0) 85 | let constraintY = NSLayoutConstraint(item: progressLabel, attribute: .CenterY, relatedBy: .Equal, toItem: self.progressView, attribute: .CenterY, multiplier: 1, constant: 0) 86 | self.progressView.addConstraints([constraintX,constraintY]) 87 | 88 | self.progressView.layer.addSublayer(self.circleLayer) 89 | self.progressView.layer.addSublayer(self.arcLayer) 90 | 91 | } 92 | 93 | func startCADisplayLink() { 94 | self.displayLink = CADisplayLink(target: self, selector: #selector(WXProgressViewController.updateProgressView)) 95 | self.displayLink.addToRunLoop(NSRunLoop.currentRunLoop(), forMode: NSRunLoopCommonModes) 96 | } 97 | 98 | func stopCADisplayLink() { 99 | self.displayLink?.invalidate() 100 | self.displayLink = nil 101 | } 102 | 103 | func updateProgressView() { 104 | if let delegate = self.delegate { 105 | let progress = CGFloat(delegate.getProgress()) 106 | self.arcLayer.path = self.getLayerPath(-CGFloat(M_PI_2), endAngle: CGFloat(M_PI) * 2 * progress - CGFloat(M_PI_2) ) 107 | self.arcLayer.setNeedsDisplay() 108 | if let text = delegate.getProgressText() { 109 | self.progressLabel.text = text 110 | } else { 111 | self.progressLabel.text = String(Int(progress * 100)) 112 | } 113 | } 114 | } 115 | 116 | func onTap() { 117 | self.delegate?.showRootView() 118 | } 119 | 120 | func onPan(sender:UIPanGestureRecognizer) { 121 | let point = sender.locationInView(self.view) 122 | // 保证悬浮框在边框范围内 123 | let prevCenter = self.progressView.center 124 | var frame = UIScreen.mainScreen().compatibleBounds 125 | frame.origin.y = 20 126 | frame.size.height -= 20 127 | self.progressView.center = point 128 | if !frame.contains(self.progressView.frame) { 129 | let unionFrame = frame.union(self.progressView.frame) 130 | if unionFrame.width > frame.width { 131 | self.progressView.center.x = prevCenter.x 132 | } 133 | if unionFrame.height > frame.height { 134 | self.progressView.center.y = prevCenter.y 135 | } 136 | } 137 | self.progressRect = self.progressView.frame 138 | } 139 | 140 | private func getLayerPath(startAngle:CGFloat,endAngle:CGFloat) -> CGPath { 141 | let width = self.progressRect.size.width 142 | let lineWidth:CGFloat = width / 8.0 143 | let radius = (width - lineWidth ) / 2.0 144 | let center = CGPoint(x: width / 2.0, y: width / 2.0) 145 | return UIBezierPath(arcCenter:center , radius: radius, startAngle: startAngle, endAngle:endAngle , clockwise:true).CGPath 146 | } 147 | 148 | private func getCycleLayer(color:UIColor,startAngle:CGFloat,endAngle:CGFloat) -> CAShapeLayer { 149 | let width = self.progressRect.size.width 150 | let lineWidth:CGFloat = width / 8.0 151 | let layer = CAShapeLayer() 152 | layer.strokeColor = color.CGColor 153 | layer.lineCap = "round" 154 | layer.lineWidth = lineWidth 155 | layer.path = self.getLayerPath(startAngle, endAngle: endAngle) 156 | layer.fillColor = UIColor.clearColor().CGColor 157 | return layer 158 | } 159 | 160 | // 处理旋转 161 | private func resetProgressViewFrameOnRotate(toWidth:CGFloat,toHeight:CGFloat) { 162 | let origin = self.progressView.frame.origin 163 | let size = self.progressView.frame.size 164 | if origin.x + size.width > toWidth { 165 | self.progressView.frame.origin.x = toWidth - size.width 166 | } 167 | if origin.y + size.height > toHeight { 168 | self.progressView.frame.origin.y = toHeight - size.height 169 | } 170 | self.progressRect = self.progressView.frame 171 | } 172 | } 173 | 174 | 175 | 176 | 177 | 178 | -------------------------------------------------------------------------------- /WXProgressWindow.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | B175CDF81D37961D009B5D52 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = B175CDEF1D37961D009B5D52 /* AppDelegate.swift */; }; 11 | B175CDF91D37961D009B5D52 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = B175CDF01D37961D009B5D52 /* Assets.xcassets */; }; 12 | B175CDFB1D37961D009B5D52 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = B175CDF31D37961D009B5D52 /* Main.storyboard */; }; 13 | B175CDFC1D37961D009B5D52 /* Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = B175CDF51D37961D009B5D52 /* Info.plist */; }; 14 | B175CDFD1D37961D009B5D52 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B175CDF61D37961D009B5D52 /* ViewController.swift */; }; 15 | B175CDFF1D379651009B5D52 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = B175CDFE1D379651009B5D52 /* LaunchScreen.storyboard */; }; 16 | B175CE011D3796F3009B5D52 /* WXProgressViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B175CE001D3796F3009B5D52 /* WXProgressViewController.swift */; }; 17 | B175CE031D379735009B5D52 /* Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = B175CE021D379735009B5D52 /* Extensions.swift */; }; 18 | B175CE051D37A654009B5D52 /* WXProgressWindowManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = B175CE041D37A654009B5D52 /* WXProgressWindowManager.swift */; }; 19 | B175CE071D37A6DC009B5D52 /* WXProgressCircleTransition.swift in Sources */ = {isa = PBXBuildFile; fileRef = B175CE061D37A6DC009B5D52 /* WXProgressCircleTransition.swift */; }; 20 | B175CE091D37A904009B5D52 /* TestViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B175CE081D37A904009B5D52 /* TestViewController.swift */; }; 21 | B175CE0B1D37BB27009B5D52 /* TestNoNavViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B175CE0A1D37BB27009B5D52 /* TestNoNavViewController.swift */; }; 22 | /* End PBXBuildFile section */ 23 | 24 | /* Begin PBXFileReference section */ 25 | B175CDD91D3795CA009B5D52 /* WXProgressWindow.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = WXProgressWindow.app; sourceTree = BUILT_PRODUCTS_DIR; }; 26 | B175CDEF1D37961D009B5D52 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 27 | B175CDF01D37961D009B5D52 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 28 | B175CDF41D37961D009B5D52 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 29 | B175CDF51D37961D009B5D52 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 30 | B175CDF61D37961D009B5D52 /* ViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; }; 31 | B175CDFE1D379651009B5D52 /* LaunchScreen.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = LaunchScreen.storyboard; sourceTree = ""; }; 32 | B175CE001D3796F3009B5D52 /* WXProgressViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WXProgressViewController.swift; sourceTree = ""; }; 33 | B175CE021D379735009B5D52 /* Extensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Extensions.swift; sourceTree = ""; }; 34 | B175CE041D37A654009B5D52 /* WXProgressWindowManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WXProgressWindowManager.swift; sourceTree = ""; }; 35 | B175CE061D37A6DC009B5D52 /* WXProgressCircleTransition.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WXProgressCircleTransition.swift; sourceTree = ""; }; 36 | B175CE081D37A904009B5D52 /* TestViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TestViewController.swift; sourceTree = ""; }; 37 | B175CE0A1D37BB27009B5D52 /* TestNoNavViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TestNoNavViewController.swift; sourceTree = ""; }; 38 | /* End PBXFileReference section */ 39 | 40 | /* Begin PBXFrameworksBuildPhase section */ 41 | B175CDD61D3795CA009B5D52 /* Frameworks */ = { 42 | isa = PBXFrameworksBuildPhase; 43 | buildActionMask = 2147483647; 44 | files = ( 45 | ); 46 | runOnlyForDeploymentPostprocessing = 0; 47 | }; 48 | /* End PBXFrameworksBuildPhase section */ 49 | 50 | /* Begin PBXGroup section */ 51 | B175CDD01D3795CA009B5D52 = { 52 | isa = PBXGroup; 53 | children = ( 54 | B175CDDB1D3795CB009B5D52 /* WXProgressWindow */, 55 | B175CDDA1D3795CA009B5D52 /* Products */, 56 | ); 57 | sourceTree = ""; 58 | }; 59 | B175CDDA1D3795CA009B5D52 /* Products */ = { 60 | isa = PBXGroup; 61 | children = ( 62 | B175CDD91D3795CA009B5D52 /* WXProgressWindow.app */, 63 | ); 64 | name = Products; 65 | sourceTree = ""; 66 | }; 67 | B175CDDB1D3795CB009B5D52 /* WXProgressWindow */ = { 68 | isa = PBXGroup; 69 | children = ( 70 | B175CDEE1D37961D009B5D52 /* Demo */, 71 | B175CDF71D37961D009B5D52 /* WXProgressWindow */, 72 | ); 73 | path = WXProgressWindow; 74 | sourceTree = ""; 75 | }; 76 | B175CDEE1D37961D009B5D52 /* Demo */ = { 77 | isa = PBXGroup; 78 | children = ( 79 | B175CDEF1D37961D009B5D52 /* AppDelegate.swift */, 80 | B175CDF01D37961D009B5D52 /* Assets.xcassets */, 81 | B175CDF31D37961D009B5D52 /* Main.storyboard */, 82 | B175CDF51D37961D009B5D52 /* Info.plist */, 83 | B175CDF61D37961D009B5D52 /* ViewController.swift */, 84 | B175CDFE1D379651009B5D52 /* LaunchScreen.storyboard */, 85 | B175CE081D37A904009B5D52 /* TestViewController.swift */, 86 | B175CE0A1D37BB27009B5D52 /* TestNoNavViewController.swift */, 87 | ); 88 | path = Demo; 89 | sourceTree = ""; 90 | }; 91 | B175CDF71D37961D009B5D52 /* WXProgressWindow */ = { 92 | isa = PBXGroup; 93 | children = ( 94 | B175CE041D37A654009B5D52 /* WXProgressWindowManager.swift */, 95 | B175CE001D3796F3009B5D52 /* WXProgressViewController.swift */, 96 | B175CE061D37A6DC009B5D52 /* WXProgressCircleTransition.swift */, 97 | B175CE021D379735009B5D52 /* Extensions.swift */, 98 | ); 99 | path = WXProgressWindow; 100 | sourceTree = ""; 101 | }; 102 | /* End PBXGroup section */ 103 | 104 | /* Begin PBXNativeTarget section */ 105 | B175CDD81D3795CA009B5D52 /* WXProgressWindow */ = { 106 | isa = PBXNativeTarget; 107 | buildConfigurationList = B175CDEB1D3795CB009B5D52 /* Build configuration list for PBXNativeTarget "WXProgressWindow" */; 108 | buildPhases = ( 109 | B175CDD51D3795CA009B5D52 /* Sources */, 110 | B175CDD61D3795CA009B5D52 /* Frameworks */, 111 | B175CDD71D3795CA009B5D52 /* Resources */, 112 | ); 113 | buildRules = ( 114 | ); 115 | dependencies = ( 116 | ); 117 | name = WXProgressWindow; 118 | productName = WXProgressWindow; 119 | productReference = B175CDD91D3795CA009B5D52 /* WXProgressWindow.app */; 120 | productType = "com.apple.product-type.application"; 121 | }; 122 | /* End PBXNativeTarget section */ 123 | 124 | /* Begin PBXProject section */ 125 | B175CDD11D3795CA009B5D52 /* Project object */ = { 126 | isa = PBXProject; 127 | attributes = { 128 | LastSwiftUpdateCheck = 0730; 129 | LastUpgradeCheck = 0730; 130 | ORGANIZATIONNAME = Luo; 131 | TargetAttributes = { 132 | B175CDD81D3795CA009B5D52 = { 133 | CreatedOnToolsVersion = 7.3; 134 | }; 135 | }; 136 | }; 137 | buildConfigurationList = B175CDD41D3795CA009B5D52 /* Build configuration list for PBXProject "WXProgressWindow" */; 138 | compatibilityVersion = "Xcode 3.2"; 139 | developmentRegion = English; 140 | hasScannedForEncodings = 0; 141 | knownRegions = ( 142 | en, 143 | Base, 144 | ); 145 | mainGroup = B175CDD01D3795CA009B5D52; 146 | productRefGroup = B175CDDA1D3795CA009B5D52 /* Products */; 147 | projectDirPath = ""; 148 | projectRoot = ""; 149 | targets = ( 150 | B175CDD81D3795CA009B5D52 /* WXProgressWindow */, 151 | ); 152 | }; 153 | /* End PBXProject section */ 154 | 155 | /* Begin PBXResourcesBuildPhase section */ 156 | B175CDD71D3795CA009B5D52 /* Resources */ = { 157 | isa = PBXResourcesBuildPhase; 158 | buildActionMask = 2147483647; 159 | files = ( 160 | B175CDFC1D37961D009B5D52 /* Info.plist in Resources */, 161 | B175CDFB1D37961D009B5D52 /* Main.storyboard in Resources */, 162 | B175CDF91D37961D009B5D52 /* Assets.xcassets in Resources */, 163 | B175CDFF1D379651009B5D52 /* LaunchScreen.storyboard in Resources */, 164 | ); 165 | runOnlyForDeploymentPostprocessing = 0; 166 | }; 167 | /* End PBXResourcesBuildPhase section */ 168 | 169 | /* Begin PBXSourcesBuildPhase section */ 170 | B175CDD51D3795CA009B5D52 /* Sources */ = { 171 | isa = PBXSourcesBuildPhase; 172 | buildActionMask = 2147483647; 173 | files = ( 174 | B175CE091D37A904009B5D52 /* TestViewController.swift in Sources */, 175 | B175CE0B1D37BB27009B5D52 /* TestNoNavViewController.swift in Sources */, 176 | B175CDFD1D37961D009B5D52 /* ViewController.swift in Sources */, 177 | B175CE071D37A6DC009B5D52 /* WXProgressCircleTransition.swift in Sources */, 178 | B175CE011D3796F3009B5D52 /* WXProgressViewController.swift in Sources */, 179 | B175CDF81D37961D009B5D52 /* AppDelegate.swift in Sources */, 180 | B175CE051D37A654009B5D52 /* WXProgressWindowManager.swift in Sources */, 181 | B175CE031D379735009B5D52 /* Extensions.swift in Sources */, 182 | ); 183 | runOnlyForDeploymentPostprocessing = 0; 184 | }; 185 | /* End PBXSourcesBuildPhase section */ 186 | 187 | /* Begin PBXVariantGroup section */ 188 | B175CDF31D37961D009B5D52 /* Main.storyboard */ = { 189 | isa = PBXVariantGroup; 190 | children = ( 191 | B175CDF41D37961D009B5D52 /* Base */, 192 | ); 193 | name = Main.storyboard; 194 | sourceTree = ""; 195 | }; 196 | /* End PBXVariantGroup section */ 197 | 198 | /* Begin XCBuildConfiguration section */ 199 | B175CDE91D3795CB009B5D52 /* Debug */ = { 200 | isa = XCBuildConfiguration; 201 | buildSettings = { 202 | ALWAYS_SEARCH_USER_PATHS = NO; 203 | CLANG_ANALYZER_NONNULL = YES; 204 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 205 | CLANG_CXX_LIBRARY = "libc++"; 206 | CLANG_ENABLE_MODULES = YES; 207 | CLANG_ENABLE_OBJC_ARC = YES; 208 | CLANG_WARN_BOOL_CONVERSION = YES; 209 | CLANG_WARN_CONSTANT_CONVERSION = YES; 210 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 211 | CLANG_WARN_EMPTY_BODY = YES; 212 | CLANG_WARN_ENUM_CONVERSION = YES; 213 | CLANG_WARN_INT_CONVERSION = YES; 214 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 215 | CLANG_WARN_UNREACHABLE_CODE = YES; 216 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 217 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 218 | COPY_PHASE_STRIP = NO; 219 | DEBUG_INFORMATION_FORMAT = dwarf; 220 | ENABLE_STRICT_OBJC_MSGSEND = YES; 221 | ENABLE_TESTABILITY = YES; 222 | GCC_C_LANGUAGE_STANDARD = gnu99; 223 | GCC_DYNAMIC_NO_PIC = NO; 224 | GCC_NO_COMMON_BLOCKS = YES; 225 | GCC_OPTIMIZATION_LEVEL = 0; 226 | GCC_PREPROCESSOR_DEFINITIONS = ( 227 | "DEBUG=1", 228 | "$(inherited)", 229 | ); 230 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 231 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 232 | GCC_WARN_UNDECLARED_SELECTOR = YES; 233 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 234 | GCC_WARN_UNUSED_FUNCTION = YES; 235 | GCC_WARN_UNUSED_VARIABLE = YES; 236 | IPHONEOS_DEPLOYMENT_TARGET = 9.3; 237 | MTL_ENABLE_DEBUG_INFO = YES; 238 | ONLY_ACTIVE_ARCH = YES; 239 | SDKROOT = iphoneos; 240 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 241 | TARGETED_DEVICE_FAMILY = "1,2"; 242 | }; 243 | name = Debug; 244 | }; 245 | B175CDEA1D3795CB009B5D52 /* Release */ = { 246 | isa = XCBuildConfiguration; 247 | buildSettings = { 248 | ALWAYS_SEARCH_USER_PATHS = NO; 249 | CLANG_ANALYZER_NONNULL = YES; 250 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 251 | CLANG_CXX_LIBRARY = "libc++"; 252 | CLANG_ENABLE_MODULES = YES; 253 | CLANG_ENABLE_OBJC_ARC = YES; 254 | CLANG_WARN_BOOL_CONVERSION = YES; 255 | CLANG_WARN_CONSTANT_CONVERSION = YES; 256 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 257 | CLANG_WARN_EMPTY_BODY = YES; 258 | CLANG_WARN_ENUM_CONVERSION = YES; 259 | CLANG_WARN_INT_CONVERSION = YES; 260 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 261 | CLANG_WARN_UNREACHABLE_CODE = YES; 262 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 263 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 264 | COPY_PHASE_STRIP = NO; 265 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 266 | ENABLE_NS_ASSERTIONS = NO; 267 | ENABLE_STRICT_OBJC_MSGSEND = YES; 268 | GCC_C_LANGUAGE_STANDARD = gnu99; 269 | GCC_NO_COMMON_BLOCKS = YES; 270 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 271 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 272 | GCC_WARN_UNDECLARED_SELECTOR = YES; 273 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 274 | GCC_WARN_UNUSED_FUNCTION = YES; 275 | GCC_WARN_UNUSED_VARIABLE = YES; 276 | IPHONEOS_DEPLOYMENT_TARGET = 9.3; 277 | MTL_ENABLE_DEBUG_INFO = NO; 278 | SDKROOT = iphoneos; 279 | TARGETED_DEVICE_FAMILY = "1,2"; 280 | VALIDATE_PRODUCT = YES; 281 | }; 282 | name = Release; 283 | }; 284 | B175CDEC1D3795CB009B5D52 /* Debug */ = { 285 | isa = XCBuildConfiguration; 286 | buildSettings = { 287 | INFOPLIST_FILE = "$(SRCROOT)/WXProgressWindow/Demo/Info.plist"; 288 | IPHONEOS_DEPLOYMENT_TARGET = 7.0; 289 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 290 | PRODUCT_BUNDLE_IDENTIFIER = com.cmbchina.Test; 291 | PRODUCT_NAME = "$(TARGET_NAME)"; 292 | }; 293 | name = Debug; 294 | }; 295 | B175CDED1D3795CB009B5D52 /* Release */ = { 296 | isa = XCBuildConfiguration; 297 | buildSettings = { 298 | INFOPLIST_FILE = "$(SRCROOT)/WXProgressWindow/Demo/Info.plist"; 299 | IPHONEOS_DEPLOYMENT_TARGET = 7.0; 300 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 301 | PRODUCT_BUNDLE_IDENTIFIER = com.cmbchina.Test; 302 | PRODUCT_NAME = "$(TARGET_NAME)"; 303 | }; 304 | name = Release; 305 | }; 306 | /* End XCBuildConfiguration section */ 307 | 308 | /* Begin XCConfigurationList section */ 309 | B175CDD41D3795CA009B5D52 /* Build configuration list for PBXProject "WXProgressWindow" */ = { 310 | isa = XCConfigurationList; 311 | buildConfigurations = ( 312 | B175CDE91D3795CB009B5D52 /* Debug */, 313 | B175CDEA1D3795CB009B5D52 /* Release */, 314 | ); 315 | defaultConfigurationIsVisible = 0; 316 | defaultConfigurationName = Release; 317 | }; 318 | B175CDEB1D3795CB009B5D52 /* Build configuration list for PBXNativeTarget "WXProgressWindow" */ = { 319 | isa = XCConfigurationList; 320 | buildConfigurations = ( 321 | B175CDEC1D3795CB009B5D52 /* Debug */, 322 | B175CDED1D3795CB009B5D52 /* Release */, 323 | ); 324 | defaultConfigurationIsVisible = 0; 325 | defaultConfigurationName = Release; 326 | }; 327 | /* End XCConfigurationList section */ 328 | }; 329 | rootObject = B175CDD11D3795CA009B5D52 /* Project object */; 330 | } 331 | -------------------------------------------------------------------------------- /WXProgressWindow/Demo/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 28 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 70 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 129 | 135 | 142 | 143 | 144 | 145 | 152 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | -------------------------------------------------------------------------------- /WXProgressWindow.xcodeproj/xcuserdata/luo.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 8 | 20 | 21 | 22 | 24 | 36 | 37 | 38 | 40 | 52 | 53 | 54 | 56 | 68 | 69 | 70 | 72 | 84 | 85 | 99 | 100 | 114 | 115 | 116 | 117 | 118 | 120 | 132 | 133 | 134 | 136 | 148 | 149 | 150 | 152 | 164 | 165 | 179 | 180 | 194 | 195 | 196 | 197 | 198 | 200 | 212 | 213 | 214 | 216 | 228 | 229 | 230 | 232 | 244 | 245 | 246 | 248 | 260 | 261 | 262 | 264 | 276 | 277 | 278 | 280 | 292 | 293 | 294 | 296 | 308 | 309 | 323 | 324 | 338 | 339 | 340 | 341 | 342 | 344 | 356 | 357 | 358 | 360 | 372 | 373 | 374 | 376 | 388 | 389 | 390 | 392 | 404 | 405 | 406 | 408 | 420 | 421 | 422 | 424 | 436 | 437 | 438 | 440 | 452 | 453 | 454 | 456 | 468 | 469 | 470 | 472 | 484 | 485 | 486 | 488 | 500 | 501 | 502 | 504 | 516 | 517 | 518 | 520 | 532 | 533 | 534 | 536 | 548 | 549 | 550 | 552 | 564 | 565 | 566 | 568 | 580 | 581 | 582 | 584 | 596 | 597 | 598 | 600 | 612 | 613 | 614 | 616 | 628 | 629 | 630 | 632 | 644 | 645 | 646 | 648 | 660 | 661 | 675 | 676 | 690 | 691 | 692 | 693 | 694 | 696 | 708 | 709 | 723 | 724 | 738 | 739 | 740 | 741 | 742 | 744 | 756 | 757 | 758 | 760 | 772 | 773 | 774 | 776 | 788 | 789 | 790 | 792 | 804 | 805 | 819 | 820 | 834 | 835 | 836 | 837 | 838 | 840 | 852 | 853 | 854 | 856 | 868 | 869 | 870 | 872 | 884 | 885 | 886 | 888 | 900 | 901 | 902 | 904 | 916 | 917 | 918 | 920 | 932 | 933 | 934 | 936 | 948 | 949 | 950 | 952 | 964 | 965 | 966 | 968 | 980 | 981 | 982 | 984 | 996 | 997 | 998 | 1000 | 1012 | 1013 | 1014 | 1016 | 1028 | 1029 | 1030 | 1032 | 1044 | 1045 | 1059 | 1060 | 1074 | 1075 | 1089 | 1090 | 1091 | 1092 | 1093 | 1095 | 1107 | 1108 | 1122 | 1123 | 1137 | 1138 | 1139 | 1140 | 1141 | 1143 | 1155 | 1156 | 1157 | 1159 | 1171 | 1172 | 1173 | 1175 | 1187 | 1188 | 1189 | 1191 | 1203 | 1204 | 1205 | 1207 | 1219 | 1220 | 1221 | 1223 | 1235 | 1236 | 1237 | 1239 | 1251 | 1252 | 1253 | 1255 | 1267 | 1268 | 1269 | 1270 | 1271 | --------------------------------------------------------------------------------