swift简单粗暴方式实现任意模式切换

作者: 梦里风吹过 | 来源:发表于2016-07-30 18:09 被阅读631次

本来想写个UIApearance的教程改应用模式切换的,结果搞出来一个非常赞的方法来实现任意模式的切换。

不了解UIApearance的可以点这里看看了解下。

说下思路:

本来我是想通过extension和子类化,自定义UIApearance可以调用的方法来实现模式的切换,具体方式就不写了,说真的,有点麻烦,也不容易封装,本来是想推荐给大家在找不到合适的方式而且不想使用通知的时候尝试下,后来突然想到如果我直接用block把对象本身传回来,不是可以任意修改样式了吗,然后就有了这个。

期间做了许多尝试:

1.本来想在自定义UIApearance方法时把block作为参数,结果UIApearance的自定义方法有严格的限制,然后失败了。

// Swift
func propertyForAxis1(axis1: IntegerType, axis2: IntegerType, axisN: IntegerType) -> PropertyType
func setProperty(property: PropertyType, forAxis1 axis1: IntegerType, axis2: IntegerType)
 
// OBJECTIVE-C
- (PropertyType)propertyForAxis1:(IntegerType)axis1 axis2:(IntegerType)axis2 … axisN:(IntegerType)axisN;
- (void)setProperty:(PropertyType)property forAxis1:(IntegerType)axis1 axis2:(IntegerType)axis2 … axisN:(IntegerType)axisN;

2.然后我想到了使用子类化,增加block的属性进行操作,然后结合UIApearance的自定义方法,通过传递模式类型来选择执行哪个block。这个方法很有效,但是也很麻烦,因为你用到的所有需要改变模式的UI空间都需要子类化一遍。

3.之后我直接删掉了block的属性,专门定制化在某个模式见切换的UI控件,比如一个View的子类专门黑白切换,另一个浅灰深灰切换,然后在自定义的方法里直接根据传入的模式修改颜色,在使用时只要把对应的控件继承对应的子类就好了。这样的好处是不用每个对象都写两套修改方案,节省代码。坏处是如果不同类型的控件很多,就需要定义很多的子类,而且对与那些已经完成的项目添加模式切换也会比较坑爹。

4.再后来突然想到第2次尝试的方法可以优化下,直接把block通过extension+runtime的方式直接给系统控件添加block作为存储属性。结果失败了,因为set方法编译无法通过。下面贴一下通过extension+runtime添加存储属性的方法,大家可以自己尝试下。

private struct AssociatedKeys {
        static var aStringKey = "aStringKey"
    }
var aString: String? {
        get {
            return objc_getAssociatedObject(self, &AssociatedKeys. aStringKey) as? String
        }
        set {
            if let newValue = newValue {
                objc_setAssociatedObject( self, &AssociatedKeys. aStringKey, newValue as NSString?, .OBJC_ASSOCIATION_COPY_NONATOMIC )
            }
        }
    }

5.然后我就以学习的目的想想办法看能不能解决,做了许多尝试,中间demo崩了多少次都不想说了,之后终于set方法通过了,然后去用,发现get方法每次取到得都是nil,然后又想办法,到最后终于解决掉这个在extension里创建block类型的存储属性的方法。过程没办法说了,其实就是把自定义block类型与AnyObject相互转换。

unsafeBitCast(anyObjectValue, MyBlock.self)
unsafeBitCast(myBlockValue, AnyObject.self)

6.解决之后再去尝试模式切换,结果给了我一个很大的惊喜。通过(extension+runtime自定义block存储属性)+ 自定义UIApearance方法,我发现只要给UIView加上这段代码,所有问题都解决了,这是我做之前都没想到的,效果好的让我想哭......

以上全废话,看完的都是好朋友

代码并不多,下面看代码:

typealias Block = @convention(block) (UIView) -> Void
extension UIView{
    
    private struct AssociatedKeys {
        static var blockName1 = "blockName1"
        static var blockName2 = "blockName2"
    }
    //自定义的UIApearance方法,调用方法为 UIView.appearance().setType(1) UIApearance的具体特性可以自己去尝试和查资料
    //通过type切换模式
    dynamic func setType(type: Int){
        switch type {
        case 1:
            if block1 != nil {
                block1!(self)
            }
        default:
            if block2 != nil {
                block2!(self)
            }
        }
    }
    var block1: Block?{
        get {
            let value = objc_getAssociatedObject(self, &AssociatedKeys.blockName1)
            return unsafeBitCast(value, Block.self)
        }
        set {
            if let newValue = newValue {
                let value:AnyObject = unsafeBitCast(newValue, AnyObject.self)
                objc_setAssociatedObject( self, &AssociatedKeys.blockName1, value, .OBJC_ASSOCIATION_COPY )
            }
        }
    }
    var block2: Block?{
        get {
            let value = objc_getAssociatedObject(self, &AssociatedKeys.blockName2)
            return unsafeBitCast(value, Block.self)
        }
        set {
            if let newValue = newValue {
                let value:AnyObject = unsafeBitCast(newValue, AnyObject.self)
                objc_setAssociatedObject( self, &AssociatedKeys.blockName2, value, .OBJC_ASSOCIATION_COPY )
            }
        }
    }
    
}

根据这种模式直接复制粘贴可以添加block3,block4...
然后是使用示例:

        //aView是个UIView 不同的UIVIew子类互不影响
        //模式1时做的内容 
        aView.block1 = { view in
         view.backgroundColor = UIColor.redColor()
        }
       //模式2时做的内容
        aView.block2 = {view in
            view.backgroundColor = UIColor.blueColor()
        }
        //aLabel是一个UILabel
        aLabel.block1 = { view in
            let lab = view as! UILabel
            lab.backgroundColor = UIColor.redColor()
            lab.textColor = UIColor.blueColor()
        }
        aLabel.block2 = {view in
            let lab = view as! UILabel
            lab.backgroundColor = UIColor.blueColor()
            lab.textColor = UIColor.redColor()
        }
UIView.appearance().setType(1)
UIView.appearance().setType(0)

你可以在block里写任何你想改变的效果。
把UIView的extension写进项目里,然后给所有切换模式改变颜色的UI控件设置block1和block2,另外建议那些大量的相同类型的UI控件同时继承同一个子类直接定制。

最后

如果应用要添加模式设置,尤其是已完成的项目,用这种方式修改起来会比较简单,可以尝试下。

相关文章

  • swift简单粗暴方式实现任意模式切换

    本来想写个UIApearance的教程改应用模式切换的,结果搞出来一个非常赞的方法来实现任意模式的切换。 不了解U...

  • 一行代码实现swift的单例模式

    swift实现单例的四种方式 : 单例模式 单例模式是设计模式中最简单的一种,甚至有些模式大师都不称其为模式,称其...

  • border 的运用

    尖角边框的实现方式有很多种 1.最简单粗暴的方法:背景图片。 可维护性不好。但是可以是任意形状。 2.利用icon...

  • Swift的单例模式及如何处理并发访问

    Swift的单例模式 Swift有两种方式实现单例模式 1、全局常量 2、类型常量 处理单例模式的并发访问 1、多...

  • 夜间模式

    标签(空格分隔): Android 1、通过切换theme来实现夜间模式。2、通过资源id映射的方式来实现夜间模式...

  • POP 实现 Template Method

    本文简单介绍在 Swift 中用面向协议编程(POP)的方式实现模板方法。 模板方法是一种古老的设计模式,它使用一...

  • 行为型模式-策略模式

    针对方法切换,对某个方法进行切换,实现不同的实现方式 策略模式: 在策略模式中,一个类的行为或器算法可以在运行时更...

  • iOS开发之设计模式 - 简单工厂模式

    简单工厂模式 简单工厂模式, 解决对象的创建问题,工厂本身包括了多有的方法集合 实现计算器部分功能 swift ...

  • 界面换肤笔记

    界面换肤的两种实现方式 1.主题切换模式 创建两种主题模式 自定义属性 应用样式,通过?attr/去引用样式 切换...

  • 林永贵:做微商的3种模式

    1.卖货模式 这是最原始的微商模式,也是最简单粗暴的方式,通过刷屏朋友圈,或者直接发广告的方式卖货,这种方式在微商...

网友评论

  • afb2c99a05c3:思路很牛,但是代码量多了以后管理起来有点蛋疼
    afb2c99a05c3:@梦星Chen 我同意你的想法,看得出来你很有想法,也很大牛,谢谢你的文章,我们现在用的qmui来做的主题变化,效果不是太好。
    梦里风吹过:还有,我觉得提供一种简便的解决问题的思路往往比直接封装成一个第三方库要好的多,除了一些特别优秀的第三方库,我发现,我做项目时间越长越不愿意使用一些封装过的第三方,基本都是把一些第三方拿过来修改成自己想要的样子或者干脆自己封装.哪怕是一些优秀的第三方有时候我也会觉得它自带的很多的根本没在项目里用到的代码而觉得它很臃肿.我觉得对一个优秀的项目来说适合的才是最好的,哪怕封装的一些模块很难移植(尤其做APP,除了极个别的,很少很少有东西或者模块会被重用移植).
    梦里风吹过:算是一个参考吧,我觉得这种方法比较适合中小型APP,或者已经做的差不多了的项目后续要添加模式切换,但是又不想重构代码的时候可以用这种模式,这种方式是在原代码基础上改动相对来说比较小的一种方式.我觉得这种方式最好的地方在于它的灵活性,它没有固定的只能改颜色或者改字体什么的,你可以在block里做任何你想做的改变(比如改变控件的大小形状),这是我接触到的模式切换方式里唯一可做到这一点的.当时测试搞出来的时候我真的很惊喜,因为这种方式提供了一种几乎没有任何限制的可能性,它可以解决所有的模式切换问题,哪怕你可能要把所有的UI形态都要重写一遍.另外,如果是新项目,这种方式结合子类化的控件会更好点.

本文标题:swift简单粗暴方式实现任意模式切换

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