swift簡單粗暴方式實現(xiàn)任意模式切換

本來想寫個UIApearance的教程改應用模式切換的绞蹦,結果搞出來一個非常贊的方法來實現(xiàn)任意模式的切換。

不了解UIApearance的可以點這里看看了解下榜旦。

說下思路:

本來我是想通過extension和子類化幽七,自定義UIApearance可以調用的方法來實現(xiàn)模式的切換,具體方式就不寫了溅呢,說真的澡屡,有點麻煩,也不容易封裝咐旧,本來是想推薦給大家在找不到合適的方式而且不想使用通知的時候嘗試下驶鹉,后來突然想到如果我直接用block把對象本身傳回來,不是可以任意修改樣式了嗎铣墨,然后就有了這個室埋。

期間做了許多嘗試:

1.本來想在自定義UIApearance方法時把block作為參數(shù),結果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的自定義方法看峻,通過傳遞模式類型來選擇執(zhí)行哪個block萨西。這個方法很有效摹恰,但是也很麻煩昙篙,因為你用到的所有需要改變模式的UI空間都需要子類化一遍惯殊。

3.之后我直接刪掉了block的屬性骤肛,專門定制化在某個模式見切換的UI控件纳本,比如一個View的子類專門黑白切換,另一個淺灰深灰切換腋颠,然后在自定義的方法里直接根據(jù)傳入的模式修改顏色繁成,在使用時只要把對應的控件繼承對應的子類就好了。這樣的好處是不用每個對象都寫兩套修改方案淑玫,節(jié)省代碼巾腕。壞處是如果不同類型的控件很多,就需要定義很多的子類絮蒿,而且對與那些已經(jīng)完成的項目添加模式切換也會比較坑爹尊搬。

4.再后來突然想到第2次嘗試的方法可以優(yōu)化下,直接把block通過extension+runtime的方式直接給系統(tǒng)控件添加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方法通過了袭祟,然后去用,發(fā)現(xiàn)get方法每次取到得都是nil捞附,然后又想辦法巾乳,到最后終于解決掉這個在extension里創(chuàng)建block類型的存儲屬性的方法。過程沒辦法說了鸟召,其實就是把自定義block類型與AnyObject相互轉換胆绊。

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

6.解決之后再去嘗試模式切換,結果給了我一個很大的驚喜欧募。通過(extension+runtime自定義block存儲屬性)+ 自定義UIApearance方法压状,我發(fā)現(xiàn)只要給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 )
            }
        }
    }
    
}

根據(jù)這種模式直接復制粘貼可以添加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
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末宵呛,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子夕凝,更是在濱河造成了極大的恐慌烤蜕,老刑警劉巖,帶你破解...
    沈念sama閱讀 207,248評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件迹冤,死亡現(xiàn)場離奇詭異讽营,居然都是意外死亡,警方通過查閱死者的電腦和手機泡徙,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,681評論 2 381
  • 文/潘曉璐 我一進店門橱鹏,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事莉兰√粑В” “怎么了?”我有些...
    開封第一講書人閱讀 153,443評論 0 344
  • 文/不壞的土叔 我叫張陵糖荒,是天一觀的道長杉辙。 經(jīng)常有香客問我,道長捶朵,這世上最難降的妖魔是什么蜘矢? 我笑而不...
    開封第一講書人閱讀 55,475評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮综看,結果婚禮上品腹,老公的妹妹穿的比我還像新娘。我一直安慰自己红碑,他們只是感情好舞吭,可當我...
    茶點故事閱讀 64,458評論 5 374
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著析珊,像睡著了一般羡鸥。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上忠寻,一...
    開封第一講書人閱讀 49,185評論 1 284
  • 那天惧浴,我揣著相機與錄音,去河邊找鬼锡溯。 笑死赶舆,一個胖子當著我的面吹牛哑姚,可吹牛的內容都是我干的祭饭。 我是一名探鬼主播,決...
    沈念sama閱讀 38,451評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼叙量,長吁一口氣:“原來是場噩夢啊……” “哼倡蝙!你這毒婦竟也來了?” 一聲冷哼從身側響起绞佩,我...
    開封第一講書人閱讀 37,112評論 0 261
  • 序言:老撾萬榮一對情侶失蹤寺鸥,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后品山,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體胆建,經(jīng)...
    沈念sama閱讀 43,609評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 36,083評論 2 325
  • 正文 我和宋清朗相戀三年肘交,在試婚紗的時候發(fā)現(xiàn)自己被綠了笆载。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,163評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖凉驻,靈堂內的尸體忽然破棺而出腻要,到底是詐尸還是另有隱情,我是刑警寧澤涝登,帶...
    沈念sama閱讀 33,803評論 4 323
  • 正文 年R本政府宣布雄家,位于F島的核電站,受9級特大地震影響胀滚,放射性物質發(fā)生泄漏趟济。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,357評論 3 307
  • 文/蒙蒙 一蛛淋、第九天 我趴在偏房一處隱蔽的房頂上張望咙好。 院中可真熱鬧,春花似錦褐荷、人聲如沸勾效。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,357評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽层宫。三九已至,卻和暖如春其监,著一層夾襖步出監(jiān)牢的瞬間萌腿,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,590評論 1 261
  • 我被黑心中介騙來泰國打工抖苦, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留毁菱,地道東北人。 一個月前我還...
    沈念sama閱讀 45,636評論 2 355
  • 正文 我出身青樓锌历,卻偏偏與公主長得像贮庞,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子究西,可洞房花燭夜當晚...
    茶點故事閱讀 42,925評論 2 344

推薦閱讀更多精彩內容

  • 發(fā)現(xiàn) 關注 消息 iOS 第三方庫窗慎、插件、知名博客總結 作者大灰狼的小綿羊哥哥關注 2017.06.26 09:4...
    肇東周閱讀 12,033評論 4 62
  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 171,527評論 25 707
  • 人們相遇卤材, 然后彼此告別遮斥。 熟悉的城市陌生的人, 來來往往扇丛,匆匆忙忙术吗。 世間所謂緣分, 一切只是巧合帆精。 每顆心上较屿,...
    孤獨詩人閱讀 346評論 0 1
  • 作為一個人材蹬,往往都回有其自戀因素。所以很多人通過自己對別人說過的話吝镣。為了能證明自己是對的常常會把自己往那方面推動堤器,...
    一號根據(jù)地閱讀 213評論 0 0
  • 假設有兩個表,訂單表和產(chǎn)品表末贾,訂單跟產(chǎn)品的關系是一對多的關系闸溃,那么在JPA中怎樣表示一對多的關系呢?實體關系一對多...
    姜小碼閱讀 17,090評論 0 3