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

本来想写个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加上这段代码,所有问题都解决了,这是我做之前都没想到的,效果好的让我想哭......

代码

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

import UIKit

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控件同时继承同一个子类直接定制。

最后

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

补充

OC版代码

#import <UIKit/UIKit.h>

NS_ASSUME_NONNULL_BEGIN

@interface UIView (Extension)
//扩展属性 block
@property (nonatomic, copy) void (^doApearanceBlock)(UIView *view);
@property (nonatomic, strong) NSString *languageText UI_APPEARANCE_SELECTOR;
//-(void)setLanguage:(NSString *)language UI_APPEARANCE_SELECTOR;
@end

NS_ASSUME_NONNULL_END

#import "UIView+Extension.h"
#import <objc/runtime.h>


static const void *doApearanceBlockKey = &doApearanceBlockKey;
static const void *languageTextKey = &languageTextKey;
@implementation UIView (Extension)
@dynamic doApearanceBlock;

- (void (^)(UIView * _Nonnull))doApearanceBlock{
    return objc_getAssociatedObject(self,doApearanceBlockKey);
}
- (void)setDoApearanceBlock:(void (^)(UIView * _Nonnull))doApearanceBlock{
    objc_setAssociatedObject(self, doApearanceBlockKey, doApearanceBlock, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
- (NSString *)languageText{
    return objc_getAssociatedObject(self,languageTextKey);
}
- (void)setLanguageText:(NSString *)languageText{
    objc_setAssociatedObject(self, languageTextKey, languageText, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}

@end
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,179评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,229评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,032评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,533评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,531评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,539评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,916评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,574评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,813评论 1 296
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,568评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,654评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,354评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,937评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,918评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,152评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,852评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,378评论 2 342

推荐阅读更多精彩内容

  • 发现 关注 消息 iOS 第三方库、插件、知名博客总结 作者大灰狼的小绵羊哥哥关注 2017.06.26 09:4...
    肇东周阅读 12,016评论 4 62
  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 171,386评论 25 707
  • 人们相遇, 然后彼此告别。 熟悉的城市陌生的人, 来来往往,匆匆忙忙。 世间所谓缘分, 一切只是巧合。 每颗心上,...
    孤独诗人阅读 344评论 0 1
  • 作为一个人,往往都回有其自恋因素。所以很多人通过自己对别人说过的话。为了能证明自己是对的常常会把自己往那方面推动,...
    一号根据地阅读 213评论 0 0
  • 假设有两个表,订单表和产品表,订单跟产品的关系是一对多的关系,那么在JPA中怎样表示一对多的关系呢?实体关系一对多...
    姜小码阅读 17,082评论 0 3