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é)省代碼。壞處是如果不同類型的控件很多,就需要定義很多的子類,而且對與那些已經完成的項目添加模式切換也會比較坑爹。

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)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

  • 發(fā)現(xiàn) 關注 消息 iOS 第三方庫、插件、知名博客總結 作者大灰狼的小綿羊哥哥關注 2017.06.26 09:4...
    肇東周閱讀 15,103評論 4 61
  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 178,828評論 25 709
  • 人們相遇, 然后彼此告別。 熟悉的城市陌生的人, 來來往往,匆匆忙忙。 世間所謂緣分, 一切只是巧合。 每顆心上,...
    孤獨詩人閱讀 381評論 0 1
  • 作為一個人,往往都回有其自戀因素。所以很多人通過自己對別人說過的話。為了能證明自己是對的常常會把自己往那方面推動,...
    一號根據(jù)地閱讀 290評論 0 0
  • 假設有兩個表,訂單表和產品表,訂單跟產品的關系是一對多的關系,那么在JPA中怎樣表示一對多的關系呢?實體關系一對多...
    姜小碼閱讀 17,316評論 0 3

友情鏈接更多精彩內容