• 这几天苹果在开 WWDC2017 大会,期间放出了 Xcode9.0-beta 以及 Swift4... 如何适配Xcode9.0-beta 内置的 Swift 版本不止一个,它同时支持 Swift4.0Swift3.2 。而我们正在用的 Xcode8 ,最高只支持 Swift3.1 。基于
        

    这几天苹果在开 WWDC2017 大会,期间放出了 Xcode9.0-beta 以及 Swift4 。为了响应苹果爸爸的号召,我果断下载了 Xcode9.0-beta ,并在项目中拉出了新的分支,准备搞事。

    640?wx_fmt=jpeg&wxfrom=5&wx_lazy=1

    如何适配

    Xcode9.0-beta 内置的 Swift 版本不止一个,它同时支持 Swift4.0Swift3.2 。而我们正在用的 Xcode8 ,最高只支持 Swift3.1 。基于这个事实,我先拉一个 Xcode9.0-beta-Swift3.2 的分支,待适配好 Swift3.2 后,再起分支 Xcode9.0-beta-Swift4.0 去支持 Swift4.0

    适配 Swift3.2

    首先,对于 Swift3.2 ,我的理解是:既然版本命名为 3.2 ,那么应该只是基于 3.1 版本上的微调(我去查 Swift ,查到更多的是关于 Swift4.0 方面的信息)。适配 Swift3.2 的过程中,我的项目代码不需要任何改动,唯一出问题的是一个第三方库: Eureka ,报错的原因是 Collection 协议的 subscript 返回值从 Array 变成了 ArraySlice ,关于这个问题,已有人在 Eureka 的issues中提出( #1082 )。随后有人 commit 修复了这个问题,并开出新分支来适配 Swift3.2

    0?wx_fmt=jpeg

    最后,我在 Podfile 中修改 pod 'Eureka'pod 'Eureka', :git => 'https://github.com/xmartlabs/Eureka.git', :branch => 'swift3.2' ,完成了适配 Swift3.2

    由此可见,适配 Swift3.2 几乎是没有什么压力的,我也就看到 Collection 协议的 subscript 返回值变动这个情况。

    适配 Swift4.0

    并不是所有库都能做到及时支持 Swift4.0 ,更何况是在现在连 Xcode9 也还是 beta 的状态,所以我们仅能做到将自己的业务代码(主工程代码)部分升级到 Swift4.0 ,然后同时保留各种 pod 库在 Swift3.2 版本。没办法,谁叫 Swift4.0 也还无法做到 ABI 兼容呢(但愿能在 Swift5 之前实现吧)。至于我说的同时使用两个版本的 Swift ,这是没问题的, Xcode9 支持在项目中同时使用 Swift3.2Swift4.0

    具体要怎么做呢?(修改 Swift 版本)

    第一步,如下图指定主工程的 Swift 版本为 4.0
    0?wx_fmt=png 第二步,如下所示,在 Podfile 文件的最下方加入如下代码,指定 pod 库的 Swift 版本为 3.2 (这样会使得所有的第三方 pod 库的 Swift 版本都为 3.2 )

    post_install do |installer|
      installer.pods_project.targets.each do |target|
        target.build_configurations.each do |config|
          config.build_settings['SWIFT_VERSION'] = '3.2'
        end
      endend

    做完以上处理,剩下的就是主工程中的代码修改了。

    Swift3.2Swift4.0 的过程,比从 Swift3.1Swift3.2 的过程要麻烦一点,但是比当年从 Swift2.3Swift3 的过程要好太多了。

    下面我列举一下 Swift3.2Swift4.0 的改变(只是我项目中遇到的):

    • Swift4.0 中对于扩展的属性(包括实例属性、 static 属性、 class 属性),都只能使用 get 方法,不可使用 set 方法

    • Swift4.0 中不再允许复写扩展中的方法(包括实例方法、 static 方法、 class 方法)

    • swift3 使用 #selector 指定的方法,只有当方法权限为 private 时需要加 @objc 修饰符,现在全都要加 @objc 修饰符

    • 字体方面的一些重命名( NSFontAttributeName 重命名为 NSAttributedStringKey.fontNSForegroundColorAttributeName 重命名为 NSAttributedStringKey.foregroundColorNSStrikethroughStyleAttributeName 重命名为 NSAttributedStringKey.strikethroughStylesize(withAttributes:) 方法重命名为 size(withAttributes:) )

    OCSwift4.0 混编才是坑

    由于历史原因,我负责的项目,还有好大一部分 OC 的代码,新写的 Swift 需要被 OC 调用。所以,问题来了…

    OC 调用 Swift4.0 问题一:编译不通过

    我在 Swift4 的代码中写了不少 classextension ,有些也给 OC 调用。在 OC 的代码中,我们通过 #import "ModuleName-Swift.h" 导入了 Swift 文件,以给 OC 调用。如果是 Swift3.2 ,一切都能正常工作,但是在 Swift4.0 上,编译通不过了。

    一:在 OC 中调用一个 Swift4.0 类的方法(包括实例方法、 static 方法、 class 方法),你需要:

    • 在该 Swift4.0 类前加上修饰符 @objc

    • Swift4.0 类必须继承 NSObject (否则,无法在前面加上修饰符 @objc 。当然,这里指的是普通类, @objc 也是可以修饰 UI 开头的一系列 UIKit 框架下的 UI 类,只是修饰了这些类,不会产生什么影响)

    • 在需要调用的方法前加上修饰符 @objc
      示例如下:

    @objc class SampleObject: NSObject {    @objc func sampleFunc  {        print("sampleFunc")
        }    
        @objc static func sampleStaticFunc  {        print("sampleStaticFunc")
        }    
        @objc class func sampleClassFunc  {        print("sampleClassFunc")
        }

    如此一来,便可在 OC 文件中调用,示例如下:

    #import "OCSample.h"#import "ModuleName-Swift.h"@implementation OCSample- (void)callSwiftFunc {    // 调用实例方法
        SampleObject *object = [[SampleObject alloc] init];
        [object sampleFunc];    // 调用static方法
        [SampleObject sampleStaticFunc];    // 调用class方法
        [SampleObject sampleClassFunc];
    }@end

    二:在 OC 中调用一个 Swift4.0 扩展的属性(包括实例属性、 static 属性、 class 属性)、方法(包括实例方法、 static 方法、 class 法),你有如下两种选择方式:

    • 在该 Swift4.0 扩展前加上修饰符 @objc (这样的话,该扩展下的所有的属性、方法,都可被 OC 调用)。

    示例如下:

    @objc extension UIViewController {    var name: String {
            reutrn "name"
        }    
        static var staticName: String {
            reutrn "staticName"
        }    
        class var className: String {
            reutrn "className"
        }    
        func nameFunc() {        print("nameFunc")
        }    
        static func staticNameFunc() {        print("staticNameFunc")
        }    
        class func classNameFunc() {        print("classNameFunc")
        }  
    }

     

    • 在需要的属性、方法前直接加上 @objc 修饰,也可达到目的。

    示例如下:

     extension UIViewController {    @objc var name: String {
            reutrn "name"
        }    
        @objc static var staticName: String {
            reutrn "staticName"
        }    
        @objc class var className: String {
            reutrn "className"
        }    
        @objc func nameFunc() {        print("nameFunc")
        }    
        @objc static func staticNameFunc() {        print("staticNameFunc")
        }    
        @objc class func classNameFunc() {        print("classNameFunc")
        }  
    }

    OC 调用 Swift4.0 问题二:运行时找不到属性

    这个问题藏得比较深,恰巧项目中有着相关的实现,让我看出发现这个潜在因素。

    项目中有这么一种实现:有一个 Swift4.0 的类,是继承 UIViewController 的。然后我在 OC 里面对这个继承而来的 UIViewController 进行操作,我用了 [viewController valueForKey:@"iconURL"] 这一 KVC 方法去获取这个自定义 UIViewController 中的 iconURL 这一属性的属性值。这种方式,编译时是无法检查出问题的。但是在运行时,问题就来了,找不到这个属性。因为这个属性没有暴露给 OC 来进行调用。

    解决方式:仅需要在自定义的 UIViewController 类中给需要暴露给 OC 调用的属性前加上 @objc 修饰符便可。如此一来,在 OC 代码中就能访问到这个属性。(注意:这里可不像上面提到的 extension 一样,在这个已定义的 UIViewController 类前面加上 @objc 修饰符没有任何意义)。

    示例如下:

    class SampleViewController: UIViewController {    @objc var iconURL: String?
    }

     

    除了在 OC 里通过 valueForKey: 方法调用到一些未经过 @objc 修饰的 Swift4.0UI 类的属性会导致 crash 。其他比如你在 Swift4.0 代码中,通过 setValuesForKeys 这种通过 KVC 来操作未经过 @objc 修饰的属性,也会导致 crash

    关于混编方面的更多信息

    更多关于混编方面的内容,可以访问查看Apple官方提供的这篇文章: Using Swift with Cocoa and Objective-C (Swift 4) ,篇幅不少,不单单介绍了 Swift4.0OC 的混用,也介绍了与 Capi 的交互、还有更多关于 @objc 修饰符的用法。

    关于 Xcode9-beta 的更多

    Xcode9-beta 局域网调试

    要求

    • 必须是 Xcode9-beta

    • iPhone 必须是 iPhone7 以上设备

    操作

    1. Xcode9-beta 菜单的 Window 选项中选择 Devices and Simulators

    2. 通过连接线让你的 Mac 识别到你的 iPhone

    3. Devices and Simulators 面板的左侧 Connected 菜单中选择连接的设备,然后在顶部的 DevicesSimulators 选项中选择 Devices (这里其实默认就是选择了 Devices ),最后勾选 Connect via network 选项。

    0?wx_fmt=gif

    iOS开发者交流群:446310206 喜欢就❤️❤️❤️star一下吧!


    展开全文
  • 前面写了一部分关于Swift的语法学习,今天要学习的是Swift关于iOS中网络请求的AFNetwoking3.0的封装。Swift关于iOS中网络请求的AFNetwoking3.0的封装的流程有如下的几个步骤: 使用cocoaPods 下载AFNetwoking的库 ...

    下面是我的新建的Swift学习交流群,欢迎大家一起来共同学习Swift。
    这里写图片描述

    前面写了一部分关于Swift的语法学习,今天要学习的是Swift关于iOS中网络请求的AFNetwoking3.0的封装。

    Swift关于iOS中网络请求的AFNetwoking3.0的封装的流程有如下的几个步骤:

    • 使用cocoaPods 下载AFNetwoking的库
    • 建立桥接文件
    • 封装AFNetwokingUtil工具类
    • 使用协议进行传值
    • 案例的实现

    1.使用cocoaPods 下载AFNetwoking的库

    platform :ios,'8.0'
    use_frameworks!
    
    target 'HelloSwfit' do
    pod 'AFNetworking','~> 3.0'
    pod 'SwiftyJSON','~> 2.3'
    pod 'Toast-Swift', '~> 1.3.0'
    end
    

    接着在终端命令执行:pod update –verbose –no-repo-update
    这样下载成功了。

    2.建立桥接文件

    1.1在用Swift使用OC中得类文件的时候,需要进行桥接,首先建一个.h的头文件。
    注意:桥接文件的命名规则:项目名-Bridging-Header.Swift

    #import "AFNetworking/AFNetworking.h"

    1.2 在Build-settings -> Swift Complier - Code Generaton —>Objective C Briding Herder中添加自己的桥接文件。
    如下图:这里写图片描述
    这样的话,桥接文件已经OK。

    3.封装AFNetwokingUtil工具类

    //
    //  AFNetWorkingUtil.swift
    //  HelloSwfit
    //
    //  Created by lidong on 16/5/17.
    //  Copyright © 2016年 lidong. All rights reserved.
    //
    
    import UIKit
    
    
    /// 对AFNetworking的封装
    
    class AFNetWorkingUtil {
    
    
        /// 基础URL
        let BASE_URL = "http://v.juhe.cn"
        /// AFHTTPSessionManager
        let _sessionManager = AFHTTPSessionManager()
    
             /// 定义一个响应结果的传递代理
        var  delegate: ResponseResultDelegate?
    
        // 单例  全局的的网络工具
        class var sharedInstance: AFNetWorkingUtil
        {
    
            struct Static {
                static var onceToken : dispatch_once_t = 0
                static var instance : AFNetWorkingUtil? = nil
    
            }
    
            dispatch_once(&Static.onceToken) {
                Static.instance = AFNetWorkingUtil()
            }
            return Static.instance!
        }
    
    
        /**
         获取baseUrl
    
         - parameter baseUrl: 基础的url
    
         - returns: URL
         */
         func getBaseUrl(baseUrl:String) ->String{
    
            return BASE_URL
         }
        /**
         post请求
    
         - parameter action: 请求的action
         - parameter params: 请求参数
         */
         func post(action:String,params:Dictionary<String,String>){
    
            _sessionManager.POST(getBaseUrl(BASE_URL)+action, parameters: params, success: { (operation:NSURLSessionDataTask?, responseObj:AnyObject?) in
                    print(responseObj)
                self.delegate?.responseSuccess(responseObj)
            }) { (operation:NSURLSessionDataTask? ,error:NSError) in
                    print(error)
                self.delegate?.responseError(error)
            }
        }
        /**
        get请求
    
         - parameter action: 请求的action
         - parameter params: 请求参数
         */
         func get(action:String,params:Dictionary<String,String>){
            _sessionManager.GET(getBaseUrl(BASE_URL)+action, parameters: params, success: { (operation:NSURLSessionDataTask?, responseObj:AnyObject?) in
                print(responseObj)
                self.delegate?.responseSuccess(responseObj)
            }) { (operation:NSURLSessionDataTask? ,error:NSError) in
                print(error)
                self.delegate?.responseError(error)
            }
    
        }
    
    }
    

    4.使用协议进行传值

    //
    //  ResponseResult.swift
    //  HelloSwfit
    //
    //  Created by lidong on 16/6/5.
    //  Copyright © 2016年 lidong. All rights reserved.
    //
    
    /**
     *  网络请求响应结果的回调
     */
    protocol ResponseResultDelegate {
    
    
        /**
         响应成功的回调
    
         - parameter response: 成功的信息
         */
         func responseSuccess(responseObj:AnyObject?)
        /**
         响应失败的回调
    
         - parameter responseError: 失败的信息
         */
         func responseError(responseObj:AnyObject?)
    
    }

    5.案例的实现

    //
    //  NetWokingGetDemo.swift
    //  HelloSwfit
    //
    //  Created by lidong on 16/6/5.
    //  Copyright © 2016年 lidong. All rights reserved.
    //
    
    import Foundation
    import  SwiftyJSON
    
    class NetWokingGetDemo: UITableViewController,
        ResponseResultDelegate {
    
    
        let aFUtils = AFNetWorkingUtil.sharedInstance
    
    
        var items:Array = [String]()
    
    
        override func viewDidLoad() {
            super.viewDidLoad()
            aFUtils.delegate = self
            let action:String = "/dream/category"
            let  dic = ["key":"c73b082b0c150b3bcba2cea1b96a8922"]
            aFUtils.get(action, params: dic)
            self.tableView.delegate = self
            self.tableView.dataSource = self
            self.title = "周公解梦"
        }
    
        func responseError(responseObj: AnyObject?) {
            Util.log("responseSuccess", message: "服务器异常!")
        }
    
        func responseSuccess(responseObj: AnyObject?) {
    
            let json = JSON(responseObj!)
    
            Util.log("responseSuccess", message: json["error_code"].intValue)
            Util.log("responseSuccess", message: json["reason"].string!)
            Util.log("responseSuccess", message: json["result"].array!.count)
    
            let d =  json["result"].array!.count
            if d > 0  {
               let list: Array<JSON> =  json["result"].array!
    
                for item in list {
                    items.append(item["name"].string!)
                }
                self.tableView.reloadData()
            }
    
        }
    
    
    
        override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
            return items.count
        }
    
        override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell
        {
            let cell = UITableViewCell()
            cell.textLabel?.text = items[indexPath.row]
            return cell;
    
        }
    
    
        override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
            Util.showToast(self, message: items[indexPath.row])
    
        } 
    }
    

    代码地址:
    运行的效果:

    这里写图片描述

    展开全文
  • Swift 设置文字阴影

    2015-09-02 18:45:19
    Swift 设置文字阴影其实很简单 我们一UILabel为例来看 let label1=UILabel(frame: CGRectMake(30, 50, 310,36)) label1.text="I'm learning Swift" label1.font=UIFont.systemFontOfSize(30)//调整文字大小

    Swift 设置文字阴影其实很简单

    我们一UILabel为例来看

            let label1=UILabel(frame: CGRectMake(30, 50, 310,36))
            label1.text="I'm learning Swift"
            label1.font=UIFont.systemFontOfSize(30)//调整文字大小
            label1.shadowColor=UIColor.lightGrayColor()//设置阴影颜色
            label1.shadowOffset=CGSizeMake(3, 3)//设置阴影大小
            self.view .addSubview(label1)

    效果如下


    苹果开发群 :414319235  欢迎加入  欢迎讨论问题

    展开全文
  • Swift4.0语法新特性

    2017-12-30 12:08:17
    1.添加Codable协议,方便自定义数据类型序列化2.添加定义多行字符串语法3.改进key-value coding的keypath4.修改并强化字典功能5.字符串变为集合类型1.Swifty encoding and decoding:在Objective-C中值类型的相互...
        

    1.添加Codable协议,方便自定义数据类型序列化
    2.添加定义多行字符串语法
    3.改进key-value coding的keypath
    4.修改并强化字典功能
    5.字符串变为集合类型

    1.Swifty encoding and decoding:

    在Objective-C中值类型的相互影响是十分糟糕的。比如NSCoding协议,类继承它之后,我们需要在类中重写自定义的 encoding 和 decoding方法。这样显得十分痛苦而且很容易出错。
    在swift4.0 中,引入了新的Codable协议,可以让你在不添加其他特殊代码的情况下序列化和反序列化自定义的数据类型,从而不用担心值类型的丢失。更漂亮的是,你可以选择数据被序列化为什么样的格式:plist(XML)或者JSON。
    是的,Swift 4 可以让你在不添加任何特殊代码的情况下将自定义数据类型序列化为JSON。
    以代码为例:
    首先,我们自定义一个数据类型:

    struct Language:Codable {
        var name: String
        var version: Int
    }
    let swift = Language(name:"Swift",version:4)
    let php = Language(name:"PHP",version:7)
    let perl = Language(name:"Perl",version:6)

    让Language这个结构体遵从Codable协议,我们便可以将它转化为json格式的数据展示:

    let encoder = JSONEncoder()
    let encoded = try? encoder.encode(swift){
        //...
    }

    Swift将会自动编码你的数据类型中的所有属性。
    我们可以使用encode和decode方法来编码和解码对象:

    let encoder = JSONEncoder()
    let encoded = try? encoder.encode(swift)
    if encoded != nil {
        if let json = String(data: encoded!,encoding:.utf8){
            print(json)
        }
    }

    let decoder = JSONDecoder()
    if let decoded = try? decoder.decode(Language.self, from: encoded!)
    {
        print(decoded.name)
    }

    同样可以有PropertyList的encode和decode:

    //PropertyList
    let propertyListEncoder = PropertyListEncoder()
    let propertyListed = try? propertyListEncoder.encode(php)

    let propertyDecoder = PropertyListDecoder()
    if let value = try? propertyDecoder.decode(Language.self,from: propertyListed!)
    {
       print(value.name)
    }

    2.多行文字的字符串:

    之前我们可以通过使用"\n"来使字符串换行。比如:

    let beforeString = "When you write a string that spans multiple \nlines make sure you start its content on a  \nline all of its own, and end it with three \nquotes also on a line of their own. Multi-line strings also let you write \"quote marks\" \nfreely inside your strings, which is great!"
    //print(beforeString)

    这种方式阅读起来很不方便,看起来很不美观,不能直观的显示它所要呈现给用户展示的样子。
    在swift4.0中,提供了专门的语法来显示多行字符串,从而告别转义。

    let longString = """
    When you write a string that spans multiple
    lines make sure you start its content on a
    line all of its own, and end it with three
    quotes also on a line of their own.
    Multi-line strings also let you write "quote marks"
    freely inside your strings, which is great!
    """
    print(longString)

    语法说明:
         1.以三个双引号作为开始的标识。
         2.以三个双引号作为结束的标识。
         3.不管开始标识还是结束标识,都必须单独占据一行
         4.你定义的字符串就是开始标识和结束标识中间的样子

    了解更多可以参考链接:the Swift Evolution proposal for this new feature.

    3.改进key-value coding的keypath

    Swift中如何使用keypath呢?
    首先,我们定义两个结构体:

    struct Crew {
        var name: String
        var rank:String
    }
    struct Starship {
        var name: String
        var maxWarp: Double
        var captain: Crew
        func goToMaximumWarp(){
            print("\(name) is now travelling at warp \(maxWarp)")
        }
    }

    let janeway = Crew(name:"Kathryn Janeway",rank:"Captain")
    let voyager = Starship(name: "Voyager", maxWarp: 9.975, captain: janeway)
    let enterWarp = voyager.goToMaximumWarp
    enterWarp()

    在Swift中,我们可以给函数添加一个引用。比如,我们可以给goToMaximumWarp()方法添加一个叫做enterWarp的引用,之后我们便可以使用enterWarp来调用它。然而,我们却不能对属性做同样的操作。是的,我们不能给Starship的name属性添加一个引用。
    这个问题,可以通过使用keypath来解决:正如enterWarp()一样,它们是未被调用的属性引用。 如果您现在调用引用,则得到当前值,但如果稍后调用引用,则获得最新值。
    keyPath的语法格式为反斜杠:

    let nameKeyPath = \Starship.name
    let maxWarpKeyPath = \Starship.maxWarp
    let captainName = \Starship.captain.name

    之后你便可以在Starship的实例中使用它了:

    print(voyager[keyPath: nameKeyPath])  //Voyager
    voyager[keyPath: nameKeyPath] = "456"
    print(voyager.name)   //456
    voyager.goToMaximumWarp()  //456 is now travelling at warp 9.975
    enterWarp()  //Voyager is now travelling at warp 9.975

    let starshipName = voyager[keyPath: nameKeyPath]
    let starshipMaxWarp = voyager[keyPath: maxWarpKeyPath]
    let starshipCaptain = voyager[keyPath: captainName]

    4.改进了字典功能:

    Swift4.0 让Dictionary的功能更强大。
    在Swift3.0 中,Dictionary的filter函数会返回一个包含key/value元组的数组。
    比如:

    let cities = ["Shanghai": 24_256_800, "Karachi": 23_500_000, "Beijing": 21_516_000, "Seoul": 9_995_000];
    let massiveCities = cities.filter { $0.value > 10_000_000 }

    在Swift3.0中,你不能通过massiveCities["Shanghai"]来获取对应的值。因为massiveCities不是一个字典类型。只能通过massiveCities[0].value来获取。
    但在Swift4.0中,massiveCities是字典类型,使用massiveCities["Shanghai"]获取值完全没有问题。

    print(massiveCities["Shanghai"] ?? "nil Value");

    5.String 又变成了集合类型:

    这意味着,你可以做字符串倒置,循环获取每个字符,map(),flatMap()等操作。
    比如:

    et quote = "It is a truth universally acknowledged that new Swift versions bring new features."
    let reversed = quote.reversed()

    for letter in quote {
        print(letter)
    }

    另外,Swift4.0 中,引入类似于python中字符串的一些操作。在省略起始位置或者结束位置的情况下,可以自动推断集合的起始位置或者结束位置。

    et characters = ["Dr Horrible", "Captain Hammer", "Penny", "Bad Horse", "Moist"]
    let bigParts = characters[..<3]
    let smallParts = characters[3...]
    print(bigParts)    //["Dr Horrible", "Captain Hammer", "Penny"]
    print(smallParts)   //["Bad Horse", "Moist"]

    0?wx_fmt=gif

    iOS开发者交流群: 446310206

    展开全文
  • IOS常用的转场方式: 1:UINavigationController的pushViewController打开,popViewController关闭; 2:UIViewController的presentViewController打开,dismissViewController关闭; 当然你也可以直接使用...

    IOS常用的转场方式:
    1:UINavigationController的pushViewController打开,popViewController关闭;
    2:UIViewController的presentViewController打开,dismissViewController关闭;
    当然你也可以直接使用rootViewController赋值的方式…(本文暂不介绍此方法)


    1:首先看一下pushViewController

    //定义一个ViewController
    let testViewController = self.storyboard?.instantiateViewControllerWithIdentifier("TestViewController")
    //通过push打开vc
    @IBAction func onPushTappend() {
        navigationController?.pushViewController(testViewController, animated: true)
    }
    //通过push方式打开的vc,只能通过pop关闭
    navigationController?.popViewControllerAnimated(true)

    2:使用presentViewController方式打开

    @IBAction func onPresentTappend() {
        self.presentViewController(testViewController, animated: true, completion: nil)
    }
    //必须使用对应的方法,才能关闭
    self.dismissViewControllerAnimated(true, completion: nil)

    以上2中方式,打开的ViewController都是使用系统默认的动画,接下来定义动画

    3:Push方式的自定义动画
    push方法是UINavigationController提供的,所以…

    //通过设置UINavigationController的delegate代理,返回一个动画对象.
    navigationController?.delegate = self

    实现代理:

    //MARK: 实现push/pop的动画
    extension ViewController: UINavigationControllerDelegate {
        func navigationController(navigationController: UINavigationController, 
                animationControllerForOperation operation: UINavigationControllerOperation, 
                fromViewController fromVC: UIViewController, toViewController toVC: UIViewController) 
                -> UIViewControllerAnimatedTransitioning? {
    
            if operation == .Push {
                return CustomPushAnimation() //push时,使用此动画
            }
    
            if operation == .Pop {
                return CustomPopAnimation() //pop时,使用此动画
            }
    
            return nil
        }
    }

    实现动画:

    //MARK: Push 动画
    class CustomPushAnimation: NSObject, UIViewControllerAnimatedTransitioning {
        func animateTransition(transitionContext: UIViewControllerContextTransitioning) {
            print("\(#function)")
    
            transitionContext.containerView()?.backgroundColor = UIColor.whiteColor() // 修改过渡时的背景颜色
    
            let toViewController = transitionContext.viewControllerForKey(UITransitionContextToViewControllerKey)!
            let fromViewController = transitionContext.viewControllerForKey(UITransitionContextFromViewControllerKey)!
    
            transitionContext.containerView()?.insertSubview(toViewController.view, aboveSubview: fromViewController.view)
    
            toViewController.view.transform = CGAffineTransformMakeTranslation(width, height)
            //通过以下方式,可以组合2个动画效果
    //      toViewController.view.transform = CGAffineTransformConcat(CGAffineTransformMakeTranslation(-100, -100), CGAffineTransformMakeScale(2, 2))
            UIView.animateWithDuration(self.transitionDuration(transitionContext), animations: {
                toViewController.view.transform = CGAffineTransformIdentity
                fromViewController.view.transform = CGAffineTransformMakeTranslation(-width, -height)
            }) { (completion) in
                fromViewController.view.transform = CGAffineTransformIdentity
                transitionContext.completeTransition(!transitionContext.transitionWasCancelled())
            }
        }
        func transitionDuration(transitionContext: UIViewControllerContextTransitioning?) -> NSTimeInterval {
            return 0.3
        }
    }
    
    //MARK: Pop动画
    class CustomPopAnimation: NSObject, UIViewControllerAnimatedTransitioning {
    
        func animateTransition(transitionContext: UIViewControllerContextTransitioning) {
            transitionContext.containerView()?.backgroundColor = UIColor.whiteColor() // 修改过渡时的背景颜色
    
            let toViewController = transitionContext.viewControllerForKey(UITransitionContextToViewControllerKey)!
            let fromViewController = transitionContext.viewControllerForKey(UITransitionContextFromViewControllerKey)!
    
            transitionContext.containerView()?.insertSubview(toViewController.view, belowSubview: fromViewController.view)
    
            toViewController.view.transform = CGAffineTransformMakeTranslation(-width, -height)
            UIView.animateWithDuration(self.transitionDuration(transitionContext), animations: {
                toViewController.view.transform = CGAffineTransformIdentity
                fromViewController.view.transform = CGAffineTransformMakeTranslation(width, height)
            }) { (completion) in
                fromViewController.view.transform = CGAffineTransformIdentity
                transitionContext.completeTransition(!transitionContext.transitionWasCancelled())
            }
        }
        func transitionDuration(transitionContext: UIViewControllerContextTransitioning?) -> NSTimeInterval {
            return 0.3
        }
    }
    

    4:Present方式的自定义动画
    这种方式只需要实现ViewController的transitioningDelegate代理即可

    //设置目标VC的代理
    testViewController.transitioningDelegate = self

    通过代理,返回动画对象(和Push的动画,是一样的):

    //MARK: 实现Present动画
    extension ViewController: UIViewControllerTransitioningDelegate {
    
        func animationControllerForPresentedController(presented: UIViewController, presentingController presenting: UIViewController, sourceController source: UIViewController) -> UIViewControllerAnimatedTransitioning? {
            return CustomPresentAnimation() //打开时的动画
        }
    
        func animationControllerForDismissedController(dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning? {
            return CustomDismissAnimation() //关闭时的动画
        }
    
    }

    动画对象,和直接使用上面的:效果是一样的:你也可以使用一下代码,作为动画使用的参考:

    //MARK: Present动画
    class CustomPresentAnimation: NSObject, UIViewControllerAnimatedTransitioning {
    
        func animateTransition(transitionContext: UIViewControllerContextTransitioning) {
            transitionContext.containerView()?.backgroundColor = UIColor.whiteColor() // 修改过渡时的背景颜色
    
            let toViewController = transitionContext.viewControllerForKey(UITransitionContextToViewControllerKey)!
            let fromViewController = transitionContext.viewControllerForKey(UITransitionContextFromViewControllerKey)!
    
            transitionContext.containerView()?.insertSubview(toViewController.view, belowSubview: fromViewController.view)
    
            // 1:
            toViewController.view.transform = CGAffineTransformMakeTranslation(0, height)
            UIView.animateWithDuration(self.transitionDuration(transitionContext), animations: {
                toViewController.view.transform = CGAffineTransformIdentity
                fromViewController.view.transform = CGAffineTransformMakeTranslation(0, -height)
            }) { (completion) in
                fromViewController.view.transform = CGAffineTransformIdentity
                transitionContext.completeTransition(completion)
            }
    
            // 2:
    //      toViewController.view.frame.offsetInPlace(dx: 0, dy: height)
    //      UIView.animateWithDuration(transitionDuration(transitionContext), animations: {
    //          toViewController.view.frame.offsetInPlace(dx: 0, dy: -height)
    //          fromViewController.view.frame.offsetInPlace(dx: 0, dy: -height)
    //      }) { completion in
    //          fromViewController.view.frame.offsetInPlace(dx: 0, dy: height)
    //          transitionContext.completeTransition(completion)
    //      }
    
            // 3:
    //      toViewController.view.center.y = 3 * height / 2
    //      UIView.animateWithDuration(transitionDuration(transitionContext), animations: {
    //          toViewController.view.center.y = height / 2
    //          fromViewController.view.center.y = -height / 2
    //      }) { completion in
    //          transitionContext.completeTransition(completion)
    //      }
        }
        func transitionDuration(transitionContext: UIViewControllerContextTransitioning?) -> NSTimeInterval {
            return 0.3
        }
    }
    
    //MARK: Dismiss动画
    class CustomDismissAnimation: NSObject, UIViewControllerAnimatedTransitioning {
    
        func animateTransition(transitionContext: UIViewControllerContextTransitioning) {
            transitionContext.containerView()?.backgroundColor = UIColor.whiteColor() // 修改过渡时的背景颜色
    
            let toViewController = transitionContext.viewControllerForKey(UITransitionContextToViewControllerKey)!
            let fromViewController = transitionContext.viewControllerForKey(UITransitionContextFromViewControllerKey)!
    
            transitionContext.containerView()?.insertSubview(toViewController.view, belowSubview: fromViewController.view)
    
            // 1:
            toViewController.view.transform = CGAffineTransformMakeTranslation(0, -height)
            UIView.animateWithDuration(self.transitionDuration(transitionContext), animations: {
                toViewController.view.transform = CGAffineTransformIdentity
                fromViewController.view.transform = CGAffineTransformMakeTranslation(0, height)
            }) { (completion) in
                fromViewController.view.transform = CGAffineTransformIdentity
                transitionContext.completeTransition(completion)
            }
    
            // 2:
    //      toViewController.view.frame.offsetInPlace(dx: 0, dy: -height)
    //      UIView.animateWithDuration(transitionDuration(transitionContext), animations: {
    //          toViewController.view.frame.offsetInPlace(dx: 0, dy: height)
    //          fromViewController.view.frame.offsetInPlace(dx: 0, dy: height)
    //      }) { completion in
    //          fromViewController.view.frame.offsetInPlace(dx: 0, dy: -height)
    //          transitionContext.completeTransition(completion)
    //      }
    
            // 3:
    //      toViewController.view.center.y = -height / 2
    //      UIView.animateWithDuration(transitionDuration(transitionContext), animations: {
    //          toViewController.view.center.y = height / 2
    //          fromViewController.view.center.y = 3 * height / 2
    //      }) { completion in
    //          transitionContext.completeTransition(completion)
    //      }
        }
        func transitionDuration(transitionContext: UIViewControllerContextTransitioning?) -> NSTimeInterval {
            return 0.3
        }
    }
    

    这里写图片描述
    源码: https://github.com/angcyo/ViewControllerDemo

    参考: http://www.xiaoyaoli.com/?p=1271


    至此: 文章就结束了,如有疑问: QQ群 Android:274306954 Swift:399799363 欢迎您的加入.

    展开全文
  • APP开发,必不可少的就是存储数据. CoreData是IOS原生的数据存储框架,今天我就来膜拜一下苹果杰作.1:在创建IOS项目的时候,界面上勾选Use Core Data 这样IDE就会帮你创建CoreData的初始化代码//MARK: 最主要的就是这...
  • 关于 Swift Swift 是一种新的编程语言,用于编写 iOS 和 OS X 应用程序。Swift 结合了 C 和 Objective-C 的优点并且不受C的兼容性的限制。Swift 使用安全的编程模式并添加了很多新特性,这将使编程更简单,扩展性更...
  • Swift-从简单到复杂Swift基础知识大全,Swift学习从简单到复杂,不断地完善与更新, 欢迎Star❤️,欢迎Fork,☀️iOS开发者交流:446310206基础篇知识架构:常两变量基本数据类型类型转换Bool类型元祖可选值字符和字符...
  • 序言 仁圣之本,在乎制度而已, ...Swift是苹果公司于2014年推出用于撰写OS和iOS应用程序的语言。它由苹果开发者工具部门总监“克里斯.拉特纳”在2010年开始着手设计,历时一年完成基本的架构。到后来苹...
  • 11月的最后一周已经来到,希望你读完这篇博客之后把本周的碎片化时间留给Swift,在一周内完全理解并掌握Swift入门。 很多开发者对于Swift还是比较陌生,甚至完全没有接触过!内心慌成一匹,所以专门为大家写下这篇...
  • Swift字典集合

    2014-09-07 20:47:54
    字典表示一种非常复杂的集合,允许按照某个键来访问元素。字典是由两部分集合构成的,一个是键(key)集合,一个是值(value)集合。键集合是不能有重复元素的,而值集合是可以重复的,键和值是成对出现的。...
  • 如下代码是实现调用5S以上设备指纹识别的代码,按照官网给出的代码,会出现识别成功后很久才执行成功后调用的代码,逛了很久的,才知道要将其放入主线程实现才可以。具体代码如下。 1、引入类 import ...
  • 2019独角兽企业重金招聘Python工程师标准>>> ...
  • Swift UIButton UIButtonType

    2015-09-06 15:17:56
    UIButton 有一个枚举 UIButtonType 专门用来指定button的类型 这里我们尝试一下接种类型看看效果、 //按钮的几种类型 //系统默认button let btn1=UIButton.buttonWithType(UIButtonType.System) as!...
  • 点击上方“iOS开发”,选择“置顶公众号” 关键时刻,第一时间送达! ...到目前为止,我们的界面上只有以背景和一个按钮,接下来还是添加一些其它界面控件吧。...如你所见,我在部分标签处
  • 下午看见里有人问 swift 插件导入 oc 项目报错的问题, 我之前解决过, 但是忘了解决过程是怎么样的了, 这里记录下方便以后备查 没兴趣追踪原因的直接查看"总结下"章节 文章目录复现错误尝试解决总结下后记 复现错误...
  • 新年新语言,WCDB Swift

    2018-01-03 13:09:04
    而这其中,呼声最高的莫过于 对 Swift 的支持。 WCDB ObjC 版本的实现中,由于引入了 C++ 代码,并不能直接 bridge 到 Swift。因此,我们从 9 月份开始就着手使用原生的 Swift,重写 WCDB。并于 10.
  • 应用开发可采用 Swift 项目本身已经包含的 Python 的绑定实现;如果使用其它编程语言,可以参考 Rackspace 兼容 Swift 的 Cloud Files API,支持 Java,.Net,Ruby,PHP 等语言绑定。 结束语 OpenStack Swift 作为...
  • 欢迎大家前往云+社区,获取更多腾讯海量技术实践干货哦~ 作者:sanhuazhang,此文发布在微信终端开发团队的专栏 ...而这其中,呼声最高的莫过于 对 Swift 的支持。 WCDB ObjC 版本的实现中,由于引入了 C++
  • 原文链接 ...Swift 官方博客也专门发了一篇文章 Evolving Swift On Apple Platforms After ABI Stability 来进行阐述,来看看他们是怎么说的。 随着 Swift 5 的发布,Swift 的 ABI 也终于稳定下来...
1 2 3 4 5 ... 17
收藏数 335
精华内容 134