美文网首页SwiftiOS分享世界iOS-Swift
MG--Swift3.x干货( 转屏 跳转 RunTime

MG--Swift3.x干货( 转屏 跳转 RunTime

作者: Mg明明就是你 | 来源:发表于2016-12-22 21:44 被阅读2187次
    • 代码下载

    直播喵播MGMiaoBo下载

    • 自动旋转--横竖屏控制(Swift3.0)


    • appDelegate代码

    ######## appDelegate  ######## appDelegate   ######## appDelegate ######## ######## ########
    // MARK: - 是否横屏
    extension AppDelegate {
       @objc(application:supportedInterfaceOrientationsForWindow:) func application(_ application: UIApplication, supportedInterfaceOrientationsFor window: UIWindow?) -> UIInterfaceOrientationMask {
             if isLandscape {
                 return .all
             }else{
                 return .portrait
             }
         }
    }
    
    • 控制器代码

     ######## 控制器  ######## 控制器   ######## 控制器 ######## ######## ########
        override func viewWillAppear(_ animated: Bool) {
            KAppDelegate.isLandscape = true
            // 强制横屏
            let value = UIInterfaceOrientation.landscapeLeft.rawValue
            UIDevice.current.setValue(value, forKey: "orientation")
            super.viewWillAppear(animated)
        }
        override func viewWillDisappear(_ animated: Bool) {
            super.viewWillDisappear(animated)
            //将试图还原为竖屏
            KAppDelegate.isLandscape = false
            let value = UIInterfaceOrientation.portrait.rawValue
            UIDevice.current.setValue(value, forKey: "orientation")
        }
        // 视图是否自动旋转
        override var shouldAutorotate : Bool {
            return true
        }
        override var supportedInterfaceOrientations : UIInterfaceOrientationMask {
            return [UIInterfaceOrientationMask.portrait, UIInterfaceOrientationMask.landscapeLeft]
        }
        /// size : 屏幕翻转后的新的尺寸;
        /// coordinator : 屏幕翻转过程中的一些信息,比如翻转时间等;
        override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
            coordinator.animate(alongsideTransition: { [unowned self] (context) in
                let orient = UIApplication.shared.statusBarOrientation
                switch orient {
                case .portrait:
                    MGLog(message: "Portrait")
                    self.tableView.frame = CGRect(x: 0, y: navHeight, width: self.view.mg_width, height: self.view.mg_height - navHeight)
                case .landscapeLeft, .landscapeRight:
                    MGLog(message: "LandscapeLeft")
                    self.tableView.frame = CGRect(x: 0, y: navHeight/2, width: self.view.mg_width, height: MGScreenH - navHeight/2)
                default:
                    MGLog(message: "Anything But Portrait")
                    break
                }
            }) { (context) in
                MGLog(message:"rotation completed")
            }
            super.viewWillTransition(to: size, with: coordinator)
        }
    


    • 补充1: iOS10 APP内跳转至系统设置(如WIFI,Bluetooth....)

      • app-Prefs:root=+跳转名称

      • eg: 1、WIFi:app-Prefs:root=WIFI
      • e.g: 2、蜂窝网络:app-Prefs:root=MOBILE_DATA_SETTINGS_ID
      • eg:** 3、蓝牙:app-Prefs:root=Bluetooth **
      • eg:** 4、About:app-Prefs:root=General&path=About **
      • eg:跳转到自己的应用下面的设置 app-Prefs:root=Appid
    无线局域网 App-Prefs:root=WIFI
    蓝牙 App-Prefs:root=Bluetooth
    蜂窝移动网络 App-Prefs:root=MOBILE_DATA_SETTINGS_ID
    个人热点 App-Prefs:root=INTERNET_TETHERING
    运营商 App-Prefs:root=Carrier
    通知 App-Prefs:root=NOTIFICATIONS_ID
    通用 App-Prefs:root=General
    通用-关于本机 App-Prefs:root=General&path=About
    通用-键盘 App-Prefs:root=General&path=Keyboard
    通用-辅助功能 App-Prefs:root=General&path=ACCESSIBILITY
    通用-语言与地区 App-Prefs:root=General&path=INTERNATIONAL
    通用-还原 App-Prefs:root=Reset
    墙纸 App-Prefs:root=Wallpaper
    Siri App-Prefs:root=SIRI
    隐私 App-Prefs:root=Privacy
    Safari App-Prefs:root=SAFARI
    音乐 App-Prefs:root=MUSIC
    音乐-均衡器 App-Prefs:root=MUSIC&path=com.apple.Music:EQ
    照片与相机 App-Prefs:root=Photos
    FaceTime App-Prefs:root=FACETIME
    
    guard let url = URL(string: "app-Prefs:root=Bluetooth") else { 
            return 
    }
    if UIApplication.shared.canOpenURL(url) {
            UIApplication.shared.openURL(url)
    }
    

    DemoTest测试,需真机运行代码



    • 补充2:导航栏和TabBar的appearance

      • 听说这个坑了好多人,分享一下

     var tabBarItemAppear = UITabBarItem.appearance()
      if #available(iOS 9.0, *) {
                tabBarItemAppear = UITabBarItem.appearance(whenContainedInInstancesOf: [MainTabBarVC.classForCoder() as! UIAppearanceContainer.Type])
    }
    
    • 补充3:RunTime 扩展封装方法 只需调用

      • 获取所有的方法和属性

    // MARK: - RunTime
    extension NSObject {
        /**
         *   获取所有的方法和属性
         *   参数: 当前类
         */
        func mg_GetMethodAndPropertiesFromClass(cls: AnyClass) {
            debugPrint("方法========================================================")
            var methodNum: UInt32 = 0
            let methods = class_copyMethodList(cls, &methodNum)
            for index in 0..<numericCast(methodNum) {
                let met: Method = methods![index]!
                debugPrint("m_name: \(method_getName(met)!)")
    //            debugPrint("m_returnType: \(String(utf8String: method_copyReturnType(met))!)")
    //            debugPrint("m_type: \(String(utf8String: method_getTypeEncoding(met))!)")
            }
            debugPrint("属性=========================================================")
            var propNum: UInt32 = 0
            let properties = class_copyPropertyList(cls, &propNum)
            for index in 0..<Int(propNum) {
                let prop: objc_property_t = properties![index]!
                debugPrint("p_name: \(String(utf8String: property_getName(prop))!)")
    //            debugPrint("p_Attr: \(String(utf8String: property_getAttributes(prop))!)")
            }        
            debugPrint("成员变量======================================================")
            var ivarNum: UInt32 = 0
            let ivars = class_copyIvarList(cls, &ivarNum)
            for index in 0..<numericCast(ivarNum) {
                let ivar: objc_property_t = ivars![index]!
                let name = ivar_getName(ivar)
                debugPrint("ivar_name: \(String(cString: name!))")
            }
        }
    
    • 黑魔法(交换方法)

    /** 
         *  交换方法
         *  参数: 当前类 ,原方法   要交换的方法
         */
        class func mg_SwitchMethod(cls: AnyClass, originalSelector: Selector, swizzledSelector: Selector) {        
            let originalMethod = class_getInstanceMethod(cls, originalSelector)
            let swizzledMethod = class_getInstanceMethod(cls, swizzledSelector)      
            let didAddMethod = class_addMethod(cls, originalSelector, method_getImplementation(swizzledMethod), method_getTypeEncoding(swizzledMethod))        
            if didAddMethod {
                class_replaceMethod(cls, swizzledSelector, method_getImplementation(originalMethod), method_getTypeEncoding(originalMethod))
            } else {
                method_exchangeImplementations(originalMethod, swizzledMethod);
            }
          }
    }
    


    • 补充4:获取系统所有的UIFont文字名称

    func getSystemAllFontName() {
          for familyName in UIFont.familyNames {
              print("Family name: \(familyName)")
              for fontName in UIFont.fontNames(forFamilyName: familyName) {
                  print("Font name: \(fontName)")
              }
          }
    }
    
    • Family Name.png
    • FontName.png


    • 补充5:swift3.0以上 tableviewcell分割线显示不全解决方案

      • 方案1:UITableViewCell.separatorInset和UIView.layoutMargins

      • 在viewDidLoad()添加一下代码
    if tableView.responds(to:#selector(setter: UITableViewCell.separatorInset)) {
          tableView.separatorInset = UIEdgeInsets.zero
    }        
    if tableView.responds(to:#selector(setter: UIView.layoutMargins)) {
          tableView.layoutMargins = UIEdgeInsets.zero
    }
    
    • tableview实现多以下代理
        func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
            if cell.responds(to: #selector(setter: UITableViewCell.separatorInset)) {
                cell.separatorInset = UIEdgeInsets.zero
            }
            if cell.responds(to:#selector(setter: UIView.layoutMargins)) {
                cell.layoutMargins = UIEdgeInsets.zero
            }
        }
    
    • 方案2:draw(_ rect: CGRect),通过在底部绘制颜色

    // MARK: - 系统方法
        override func awakeFromNib() {
            super.awakeFromNib()
            // 记得要设置contentView.backgroundColor为clear,否则颜色会被它挡住了
            self.contentView.backgroundColor = UIColor.clear
        }
    override func draw(_ rect: CGRect) {
            let context = UIGraphicsGetCurrentContext()!
            context.setFillColor(UIColor.white.cgColor)
            context.fill(rect)
            context.setFillColor(UIColor(white: 0.9, alpha: 1.0).cgColor)
            context.fill(CGRect(x: 0, y: rect.size.height - 3, width:rect.size.width, height: 3))
        }
    
    • 方案3:朋友教的,重写frame,高度-x,露出背景色

    override var frame: CGRect {
            didSet {
                var tmpFrame : CGRect = super.frame
                tmpFrame.size.height -= 3
                super.frame           = tmpFrame
            }
        }
    
    • 总结:方法一和方法二需要去掉系统的分割线tb.separatorStyle = UITableViewCellSeparatorStyle.none效果更佳

    OC方法改变Tableview分割线的边距

     //  tableView设置:
     //1.调整(iOS7以上)表格分隔线边距
        if ([self.tableView respondsToSelector:@selector(setSeparatorInset:)]) {
            self.tableView.separatorInset = UIEdgeInsetsZero;
        }
        //    2.调整(iOS8以上)view边距(或者在cell中设置preservesSuperviewLayoutMargins,二者等效)
        if ([self.tableView respondsToSelector:@selector(setLayoutMargins:)]) {
            self.tableView.layoutMargins = UIEdgeInsetsZero;
        }
    // cell 设置:
        cell.preservesSuperviewLayoutMargins = NO;
        [cell setLayoutMargins:UIEdgeInsetsZero];
    

    • 补充6:Swift3.0纯代码添加约束 可供参考

      • 禁用autoresizing(重要)

      • 给需要设置约束的视图禁用autoresizing,禁用父视图autoresizing对子控件无效
      • 方法1:代码添加autolayout约束

            // 说明
            /*
                 constraintWithItem:需要设置约束的view
                 attribute:需要设置约束的位置
                 relatedBy:约束的条件
                 toItem:约束依赖目标
                 attribute:依赖目标约束位置
                 multiplier:配置系数
                 constant:额外需要添加的长度
             */
            /*
                 计算公式:redView.attribute = self.view.attribute * multiplier + constant;
                 其中:=符号取决于relatedBy:参数
                 typedef NS_ENUM(NSInteger, NSLayoutRelation) {
                 NSLayoutRelationLessThanOrEqual = -1,   小于等于
                 NSLayoutRelationEqual = 0,              等于
                 NSLayoutRelationGreaterThanOrEqual = 1, 大于等于
                 };
             */
            tableView.translatesAutoresizingMaskIntoConstraints = false
            let leftCon = NSLayoutConstraint(item: tableView, attribute: NSLayoutAttribute.left, relatedBy: NSLayoutRelation.equal, toItem: self.view, attribute: NSLayoutAttribute.left, multiplier: 1.0, constant: 0)
            let rightCon = NSLayoutConstraint(item: tableView, attribute: .right, relatedBy: NSLayoutRelation.equal, toItem: self.view, attribute: .right, multiplier: 1.0, constant: 0)
            let topCon = NSLayoutConstraint(item: tableView, attribute: .top, relatedBy: .equal, toItem: self.view, attribute: .top, multiplier: 1.0, constant: 0)
            let bottomCon = NSLayoutConstraint(item: tableView, attribute: .bottom, relatedBy: .equal
                , toItem: self.view, attribute: .bottom, multiplier: 1.0, constant: 0)
            self.view.addConstraints([leftCon,rightCon,topCon,bottomCon])
    
    • 方法2:添加约束 VFL格式

        // 说明
        /*VFL格式说明
         功能        表达式
         水平方向        H:
         垂直方向        V:
         Views        [view]
         SuperView      |
         关系         >=,==,<=
         空间,间隙       -
         优先级        @value 
         -----------------------------------------------------
         /* VisualFormat: VFL语句
           options: 对齐方式等,可以选择居中等
           metrics: VFL语句中使用到的一些变量
           views: VFL语句中使用到的一些控件*/
    
    // 代码
    tableView.translatesAutoresizingMaskIntoConstraints = false
    var cons = NSLayoutConstraint.constraints(withVisualFormat: "H:|-0-[tableView]-0-|", options: NSLayoutFormatOptions(rawValue: 0), metrics: nil, views: ["tableView": tableView])
    cons += NSLayoutConstraint.constraints(withVisualFormat: "V:|-0-[tableView]-0-|", options: NSLayoutFormatOptions(rawValue: 0), metrics: nil, views: ["tableView": tableView])
    view.addConstraints(cons)
    
    • eg1: "V:|-20-[redView(==50)]"

      • 解释:redView(==50)是什么意思?V是代表垂直方向,垂直方向也就是高度,说明redView他的高度是50,同理如果是H开头呢,就是代表宽度 。-20-又是什么意思呢?距离父控件上边为20。
    • eg2:"V:[redView]-20-[blueView(==50)]"

      • 解释:同理blueView他的高度是50,V是代表垂直方向,而且blueView距离redView垂直距离为20
    • eg3:

    let layout_frameView = ["frameView":frameView,"superView":self.view]
    var frameView_constraints = NSLayoutConstraint.constraintsWithVisualFormat("H:[frameView(300.)]-(<=1)-[superView]", options: NSLayoutFormatOptions.AlignAllCenterY, metrics: nil, views: layout_frameView)
    frameView_constraints = NSLayoutConstraint.constraintsWithVisualFormat("V:[frameView(200.0)]-(<=1)-[superView]", options: NSLayoutFormatOptions.AlignAllCenterX, metrics: nil, views: layout_frameView)
    view.addConstraints(frameView_constraints)
    
    • 解释:frameView宽度300和高度为200并且居中显示

    • 补充7:Swift3.0控件存在屏幕底部,当键盘出现,控件出现在键盘上方

    类似这个
        // MARK:- 系统方法
        override func viewDidLoad() {
            super.viewDidLoad()
            // 1.添加并且布局
            view.addSubview(toolBar)
            toolBar.snp_makeConstraints { (make) -> Void in
                make.bottom.left.right.equalTo(view)
                make.height.equalTo(44)
            }
            // 2.监听键盘尺寸的改变的通知
            MGNotificationCenter.addObserver(self, selector: #selector(self.keyboardFrameChange(noti:)), name: NSNotification.Name.UIKeyboardDidChangeFrame, object: nil)
        }
        /// 监听键盘尺寸的改变的方法
        @objc fileprivate func keyboardFrameChange(noti: NSNotification) {
            /*
             userInfo = {
             UIKeyboardAnimationCurveUserInfoKey = 7;
             UIKeyboardAnimationDurationUserInfoKey = "0.4";
             UIKeyboardFrameEndUserInfoKey = "NSRect: {{0, 365}, {375, 302}}";
             }
             */
            let duration = (noti.userInfo![UIKeyboardAnimationDurationUserInfoKey]! as AnyObject).doubleValue        
            let offsetY = (noti.userInfo![UIKeyboardFrameEndUserInfoKey]! as AnyObject).cgRectValue.origin.y - MGScreenH
            // toolBar: 是要挨着键盘的控件
            toolBar.snp.updateConstraints { (make) -> Void in
                make.bottom.equalTo(view.snp.bottom).offset(offsetY)
            }
            let CurveValue = noti.userInfo![UIKeyboardAnimationCurveUserInfoKey]! as! Int
            UIView.animate(withDuration: duration!, delay: 0, options: UIViewAnimationOptions(rawValue: 0), animations: { () -> Void in
                UIView.setAnimationCurve(UIViewAnimationCurve.init(rawValue: CurveValue)!)
                self.view.layoutIfNeeded()
            }, completion: nil)
        }
    


    • 补充8:Swift3.0tableView右边标题按钮兰的研究,通过KVC和Runtime可以改变颜色,系统API默认有提供接口sectionIndexColorsectionIndexBackgroundColor。其他功能还没有研究到,要做这个其他功能自定义比较合适。(比如选中文字有颜色...等)

    func test() {
           let indexView = tableView.value(forKeyPath: "_index")
                as? UIView
           indexView?.setValue(UIColor.darkGray, forKey: "_indexColor")
           indexView?.setValue(UIColor.randomColor(), forKey: "_indexTrackingBackgroundColor")
           indexView?.setValue(UIColor.randomColor(), forKey: "_indexBackgroundColor")
           let sel = NSSelectorFromString("endTrackingWithTouch:withEvent:")
           let _ = indexView?.perform(sel)
           self.mg_GetMethodAndPropertiesFromClass(cls: NSClassFromString("UITableViewIndex")!)
           (NSClassFromString("UITableViewIndex") as! UIView.Type).init()
    }
    

    • 补充9:Swift3.0 URL的encode和decode

    extension String {
        // MARK: - encoding 系统API
        /*
           URLFragmentAllowedCharacterSet  "#%<>[\]^`{|}
           URLHostAllowedCharacterSet      "#%/<>?@\^`{|}
           URLPasswordAllowedCharacterSet  "#%/:<>?@[\]^`{|}
           URLPathAllowedCharacterSet      "#%;<>?[\]^`{|}
           URLQueryAllowedCharacterSet     "#%<>[\]^`{|}
           URLUserAllowedCharacterSet      "#%/:<>?@[\]^`
       */
        /**   这个方法没有多大用,系统API已经提供了很多方法给我们如上
         *  URL 编码
         *   return 编码字符串
         */
        func encodeEscapesURL(value: String) -> String {
            let str:String = value
            let originalString = str as CFString
            let charactersToBeEscaped = "!*'();:@&=+$,/?%#[]" as CFString  //":/?&=;+!@#$()',*"    //转意符号
            //let charactersToLeaveUnescaped = "[]." as CFStringRef  //保留的符号
            let result =
                CFURLCreateStringByAddingPercentEscapes(kCFAllocatorDefault,
                                                        originalString,
                                                        nil,    //charactersToLeaveUnescaped,
                    charactersToBeEscaped,
                    CFStringConvertNSStringEncodingToEncoding(String.Encoding.utf8.rawValue)) as NSString 
            return result as String
        }
        /**
         *  URL 解码
         *   return 解码字符串
         */
        func stringByURLDecode() -> String {
            if self.removingPercentEncoding != nil {
                return self.removingPercentEncoding!
            } else {
                let en: CFStringEncoding = CFStringConvertNSStringEncodingToEncoding(String.Encoding.utf8.rawValue)
                var decoded: String = self.replacingOccurrences(of: "+", with: " ")
                decoded = (CFURLCreateStringByReplacingPercentEscapesUsingEncoding(nil, (decoded as CFString),nil, en) as String)
                return decoded
            }
        }
    }
    "http://baidu.com".encodeEscapesURL(value: "http://你好baidu.com")
    let urlCode = "http://你好baidu.com".addingPercentEncoding(withAllowedCharacters: CharacterSet.urlPasswordAllowed)
    urlCode?.stringByURLDecode()
    
    打印结果.png

    补充10:In-Call Status Bar的监听及视图位置改变调整

    • 监听通知方法

    //监听状态栏的改变
    MGNotificationCenter.addObserver(self, selector: #selector(self.statusBarChange(noti:)), name: NSNotification.Name.UIApplicationWillChangeStatusBarFrame, object: nil)
    
    • 通知方法,执行一些相应的的操作(感觉主要对frame布局的UI影响较大)

    @objc fileprivate func statusBarChange(noti: Notification) {
        // 获取变化参数
        let rectValue: NSValue? = (noti.userInfo?[UIApplicationStatusBarFrameUserInfoKey] as? NSValue)
        let statusRect: CGRect? = rectValue?.cgRectValue
        let statusFrame: CGRect = view.convert(statusRect!, from: MGKeyWindow)
        let statusHeight: CGFloat = statusFrame.size.height - 20
        // 需要修改的控件,举个🌰:比如下面这个
        if statusHeight == 0 {
            settingBtn.frame = CGRect(x: 15, y: MGScreenH-64-44, width: 60, height: 44)
        } else {
            settingBtn.frame = CGRect(x: 15, y: MGScreenH-64-44-20, width: 60, height: 44)
        }
    }
    
    处理前.png
    处理后.png
    • 补充11:Swift3.0 自定义UIButton替换导航返回按钮,仍然保持系统边缘返回手势

    class BaseNavigationController: UINavigationController  {
            override func viewDidLoad() {
                super.viewDidLoad()
                // 1.保留局部返回手势
                self.interactivePopGestureRecognizer?.delegate = nil
                self.popDelegate = self.interactivePopGestureRecognizer?.delegate
                self.delegate = self
            }
    }
    // MARK: - UINavigationControllerDelegate
    extension BaseNavigationController: UINavigationControllerDelegate {
        func navigationController(_ navigationController: UINavigationController, didShow viewController: UIViewController, animated: Bool) {
            // 实现滑动返回功能
            // 清空滑动返回手势的代理就能实现
            if viewController == self.viewControllers[0] || viewController is ProdProgressItemListVC { // 可以控制那个控制器不需要局部返回手势
                self.interactivePopGestureRecognizer!.delegate = self.popDelegate
            } else {
                self.interactivePopGestureRecognizer!.delegate = nil
            }
        }
    }
    

    • 补充12:解决Swift3.0 自定义全局返回手势和TableView左滑手势的冲突

    class BaseNavigationController: UINavigationController  {
            override func viewDidLoad() {
                super.viewDidLoad()
                // 1.全局拖拽手势
                setUpGlobalPan()
            }
    }
    // MARK: - 全局拖拽手势
    extension BaseNavigationController: UIGestureRecognizerDelegate {
        /// 全局拖拽手势
        fileprivate func setUpGlobalPan() {
            // 1.创建Pan手势
            let target = interactivePopGestureRecognizer?.delegate
            let globalPan = UIPanGestureRecognizer(target: target, action: Selector(("handleNavigationTransition:")))
            globalPan.delegate = self
            self.view.addGestureRecognizer(globalPan)
            
            // 2.禁止系统的手势
            navigationController?.interactivePopGestureRecognizer?.isEnabled = false
        }
        
        /// 什么时候支持全屏手势
        func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool {
            if self.childViewControllers.count != 1 {
                if (gestureRecognizer is UIPanGestureRecognizer) {
                    if (self.topViewController != nil) && (self.view.gestureRecognizers!.contains(gestureRecognizer)) {
                        let tPoint: CGPoint = ((gestureRecognizer as? UIPanGestureRecognizer)?.translation(in: gestureRecognizer.view))!
                        if tPoint.x >= 0 {
                            let y: CGFloat = fabs(tPoint.y)
                            let x: CGFloat = fabs(tPoint.x)
                            let af: CGFloat = 30.0 / 180.0 * .pi  // tanf(Float(af))
                            let tf: CGFloat = tan(af)
                            return (y / x) <= tf
                        } else {
                            return false
                        }
                    }
                }
                return true
            } else {
               return false
            }
        }
    }
    

    • 补充13:判断是模拟器还是真机

    • Swift3.x 运行在模拟器还是真机的判断

    struct Platform {
        static let isSimulator: Bool = {
            var isSim = false
            #if arch(i386) || arch(x86_64)
                isSim = true
            #endif
            return isSim
        }()
    }
    
    • iOS Objective-C判断是模拟器还是真机

    #if TARGET_IPHONE_SIMULATOR//模拟器
    #elseif TARGET_OS_IPHONE//真机
    #endif
    

    • 补充14:运行在后台继续执行任务,比如定时器计时

    //后台任务
    var backgroundTask:UIBackgroundTaskIdentifier! = nil
     func applicationDidEnterBackground(_ application: UIApplication) {
            //如果已存在后台任务,先将其设为完成
            if self.backgroundTask != nil {
                application.endBackgroundTask(self.backgroundTask)
                self.backgroundTask = UIBackgroundTaskInvalid
            }
            //如果要后台运行
            //注册后台任务
            self.backgroundTask = application.beginBackgroundTask(expirationHandler: {
                () -> Void in
                //如果没有调用endBackgroundTask,时间耗尽时应用程序将被终止
                application.endBackgroundTask(self.backgroundTask)
                self.backgroundTask = UIBackgroundTaskInvalid
            })
        }
    

    • 补充15:钟摆效果

        var imageView: UIImageView!
        override func viewDidLoad() {
            super.viewDidLoad()
            self.view.backgroundColor = UIColor.brown
            setUpInit()
        }
        func setUpInit() {
            self.view.layoutIfNeeded()
            imageView = UIImageView(image: #imageLiteral(resourceName: "user_img_qd.png"))
            view.addSubview(imageView)
            imageView.frame.origin = CGPoint(x: 240, y: -5)
            imageView.layer.anchorPoint = CGPoint(x: 0.5, y: 0)
            startAnimation()
        }
        func startAnimation() {
            imageView.layer.removeAllAnimations()
            // 旋转动画
            let anim = CABasicAnimation(keyPath: "transform.rotation.z")
            anim.fromValue = 7.5/4 * M_PI
            anim.toValue = 8.5/4 * M_PI
            // 悬浮
            let pathAnimation = CAKeyframeAnimation(keyPath: "position")
            pathAnimation.calculationMode = kCAAnimationPaced
            pathAnimation.fillMode = kCAFillModeBoth
    //        pathAnimation.repeatCount = MAXFLOAT
    //        pathAnimation.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionLinear)
            let path = UIBezierPath(ovalIn: imageView.frame.insetBy(dx: 10, dy: imageView.frame.size.height - 2))
            pathAnimation.path = path.cgPath
            pathAnimation.duration = Double(arc4random_uniform(UInt32(8))) + 2.0
            // 放大动画
            let scaleX = CAKeyframeAnimation(keyPath: "transform.scale")
            scaleX.values   = [1.0, 1.1, 1.0];
            scaleX.keyTimes = [0.0, 0.5, 1.0];
            // 组动画
            let group = CAAnimationGroup()
            group.animations = [anim,pathAnimation,scaleX]
            group.duration = 2.0
            group.repeatCount = HUGE
            group.autoreverses = true
            imageView.layer.add(group, forKey: "group")
        }
    
    效果.gif
    • 补充16:iOS判断过期或者想要延时x天后才执行某方法(Swift3.x和Objective-c)

      • 登录是否过期(连续5天未登录App,就重新登录)Objective-c(iOS判断过期)

    /** 判断用户登录的tocken是否过期   */
    +(BOOL)checkTockenIsExpire {
                // 获取tocken日期
                NSUserDefaults *userDefault =  [NSUserDefaults standardUserDefaults];
                NSString *date = [userDefault valueForKeyPath:TockenIsExpireDateKey];
                NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
                formatter.dateFormat = @"yyyyMMdd";
                NSString *snow = [formatter stringFromDate:[NSDate date]];
                if (date == nil) { // tocken设置为连续超过5天不打开App就重新登录
                    date = [formatter stringFromDate:[NSDate dateWithTimeIntervalSinceNow: 24 * 60 * 60 * 5]];
                    [userDefault setValue: date forKeyPath: TockenIsExpireDateKey];
                }
                if ([snow compare:date] == NSOrderedDescending) { // 当前日期大于之前保存的日期 // 降序
                    // 设置下一次过期的时间(5天有效)
                    date = [formatter stringFromDate:[NSDate dateWithTimeIntervalSinceNow: 24 * 60 * 60 * 5]];
                    [userDefault setValue: date forKeyPath: TockenIsExpireDateKey];
                    return YES; // 过期
                }
                // 刷新过期的时间(5天有效)
                date = [formatter stringFromDate:[NSDate dateWithTimeIntervalSinceNow: 24 * 60 * 60 * 5]];
                [userDefault setValue: date forKeyPath: TockenIsExpireDateKey];
                return NO; // 没有过期
    }
    
    • 某方法审核的时候不要去执行,审核通过后才去执行该方法,Swift(想要延时x天后才执行某方法)

            // 判断今天是否执行某方法
            let defaultst = UserDefaults.standard
            var date = defaultst.object(forKey: kCurrentVersionDateKey) as? String    
            let formatter = DateFormatter()
            formatter.dateFormat = "yyyy-MM-dd"
            let snow = formatter.string(from: Date())
            if date == nil { // 第一次使用三天后才会有执行这个方法(跳过审核)
                date = formatter.string(from: Date(timeIntervalSinceNow: 24 * 60 * 60 * 3))
            }
            if snow.compare(date!) == .orderedAscending {
                return
            }  
            //  设置这个是为了以后每天都会执行方法
            defaultst.set(snow, forKey: kCurrentVersionDateKey)
            // 要执行的方法
            test()
    




    • github

    项目 简介
    MGDS_Swif 逗视视频直播
    MGMiaoBo 喵播视频直播
    MGDYZB 斗鱼视频直播
    MGDemo n多小功能合集
    MGBaisi 高度仿写百思
    MGSinaWeibo 高度仿写Sina
    MGLoveFreshBeen 一款电商App
    MGWeChat 小部分实现微信功能
    MGTrasitionPractice 自定义转场练习
    DBFMDemo 豆瓣电台
    MGPlayer 一个播放视频的Demo
    MGCollectionView 环形图片排布以及花瓣形排布
    MGPuBuLiuDemo 瀑布流--商品展
    MGSlideViewDemo 一个简单点的侧滑效果,仿QQ侧滑
    MyResume 一个展示自己个人简历的Demo
    GoodBookDemo 好书


    喵播图片介绍 逗视介绍1.gif
    逗视介绍2.gif


    • 轻轻点击,关注我简书

    轻轻点击,关注我简书

    轻轻点击,关注我微博

    浏览我的GitHub


    • 扫一扫,关注我

    扫一扫,关注我.jpg

    相关文章

      网友评论

      • 23998c768628:第一句就是错的,楼主确定是swift3么,isLandscape已经不存在了,另外有2个类似的需要填参数,不知道怎么用
        Mg明明就是你:isLandscape,大神这个是我自定义的属性,用来修改横屏还是竖屏的。
        你的这个UIDeviceOrientationIsLandscape(deviceOrientation),deviceOrientation是参数,有系统的一个方法(屏幕发生变化)传进来的,UIDeviceOrientationIsLandscape(deviceOrientation)这个判断是放在那个方法里,用来判断屏幕旋转后此时是横屏还是竖屏的
        Mg明明就是你:@神风天翔 :disappointed_relieved:
        23998c768628:UIDeviceOrientationIsLandscape(<#UIDeviceOrientation#>)
      • saman0:楼主有类似qq说说图片那个功能效果吗?
      • saman0:楼主厉害啊。
      • 布袋的世界:好多干货啊!
        Mg明明就是你:@布袋的世界 :sweat_smile:云里雾里傻傻分不清了
        布袋的世界:@Mg明明就是你 偶才刚看一会 神叨叨了一天
        Mg明明就是你:@布袋的世界 :joy:都是打酱油的东西,今天看了一整天PDF书
      • NicWhite:IOS10 跳转系统设置楼主是怎么找到的?而且这个方式可以通过审核吧应该?
        Mg明明就是你:@NicWhite 🙈网上一大堆没用的方法
        NicWhite:@Mg明明就是你 找了很久第一次找到有用的:+1: :+1: :+1: :smile:
        Mg明明就是你:@NicWhite 我朋友告诉我的,应该可以的吧,项目还没上线:grin:

      本文标题:MG--Swift3.x干货( 转屏 跳转 RunTime

      本文链接:https://www.haomeiwen.com/subject/ctvhvttx.html