runtime為類別增加屬性
runtime的一個重要功能就是增加類的屬性,而一般通過類別我們是無法增加類的屬性的,runtime很好的實現了這個功能。下面我們就以當為導航欄增加透明屬性來一步步分析增加屬性的實現。我們通過剖析UINavigationBar+Awesome.m第三方來逐步分析,目前這個第三方在iOS11上獲取子檢視上有bug,本人也沒有找到好的解決方法,如果有同學有好的思路歡迎指點。demo在文末獻上:
提供的方法如下:
//設定背景色
- (void)lt_setBackgroundColor:(UIColor *)backgroundColor;
//設定透明度
- (void)lt_setElementsAlpha:(CGFloat)alpha;
//設定移動的透明高度
- (void)lt_setTranslationY:(CGFloat)translationY;
//移除新增runtime新增的view,所有設定置nil
- (void)lt_reset;
1、首先建立UINavigationBar的類別,匯入runtime相關的庫,如下:
#import "UINavigationBar+Awesome.h"
#import <objc/runtime.h>
2、利用runtime設定屬性
//定義常量,必須是C語言字串
static char overlayKey;
//通過自己編寫setter和getter方法,新增真正可以使用的屬性。
- (UIView *)overlay
{
//我們返回的是一個UIView的物件
return objc_getAssociatedObject(self, &overlayKey);
}
- (void)setOverlay:(UIView *)overlay
{
// 引數1:源物件
// 引數2:關聯時用來標記屬性的key(因為可能要新增很多屬性)
// 引數3:關聯的物件
// 引數4:關聯策略
// 關聯方法
objc_setAssociatedObject(self, &overlayKey, overlay, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
/*
objc_AssociationPolicy引數使用的策略:
OBJC_ASSOCIATION_ASSIGN; //assign策略
OBJC_ASSOCIATION_COPY_NONATOMIC; //copy策略
OBJC_ASSOCIATION_RETAIN_NONATOMIC; // retain策略
OBJC_ASSOCIATION_RETAIN;
OBJC_ASSOCIATION_COPY;
*/
}
3、開始使用屬性,改變背景顏色
- (void)lt_setBackgroundColor:(UIColor *)backgroundColor
{
if (!self.overlay) {
// https://www.jianshu.com/p/31f1637e2349對此也有介紹
//呼叫- (void)setBackgroundImage:(nullable UIImage *)backgroundImage forBarMetrics:(UIBarMetrics)barMetrics方法設定空圖片,置顏色看不到,僅能看到一個透明背景的UINavigationBar
[self setBackgroundImage:[UIImage new] forBarMetrics:UIBarMetricsDefault];
self.overlay = [[UIView alloc] initWithFrame:CGRectMake(0, -20, CGRectGetWidth(self.bounds), CGRectGetHeight(self.bounds) + 20)];
self.overlay.userInteractionEnabled = NO;
//設定View寬高自適應
self.overlay.autoresizingMask = UIViewAutoresizingFlexibleWidth|UIViewAutoresizingFlexibleHeight;
/*在特定位置插入子檢視
view:被插入的子檢視。
index:被插入的位置下標,位置下標從0開始;下標不能大於子檢視的總數。
View只能有一個父檢視,如果,該子檢視已經存在父檢視,那麼執行該方法後,舊的父檢視將被新父檢視所覆蓋。
*/
[self insertSubview:self.overlay atIndex:0];
}
self.overlay.backgroundColor = backgroundColor;
}
4、導航欄移動
導航欄隨著表的移動而移動,同時改變title以及兩邊的view檢視的透明度,這裡需要注意下,發現_liftViews在iOS11裡面無法使用了(iPhone X釋出之前使用這些方法都沒問題),會導致崩潰,如下分析:
//設定移動的高度
- (void)lt_setTranslationY:(CGFloat)translationY
{
//以初始位置為基準,x軸方向上平移x單位,在y軸方向上平移y單位。此處為在Y軸上向上移動單位數。
self.transform = CGAffineTransformMakeTranslation(0, translationY);
}
//設定
- (void)lt_setElementsAlpha:(CGFloat)alpha
{
/*
本來我們可以通過用runtime獲取Bar屬性,可以獲取所有的檢視屬性,通過以下的遍歷方法可以獲取到對應的檢視,然後它就可以被我們隨意擺佈了,嘿嘿嘿~~
でも(但是):我們獲取的_liftViews,_rightViews發現在iOS11裡面不能用了,使用的話會崩潰,提示如下:
Terminating app due to uncaught exception 'NSUnknownKeyException',
reason: '[<UINavigationBar 0x7fbdc55141b0> valueForUndefinedKey:]: this class is not key value coding-compliant for the key _liftViews.'
沒有_liftViews這個key了,也是無奈,我的處理方式是粗暴的用self.alpha = alpha;統一設定了檢視透明度了。
self.alpha = alpha;
*/
// [[self valueForKey:@"_liftViews"] enumerateObjectsUsingBlock:^(UIView *view, NSUInteger i, BOOL *stop) {
// view.alpha = alpha;
// }];
//
// [[self valueForKey:@"_rightViews"] enumerateObjectsUsingBlock:^(UIView *view, NSUInteger i, BOOL *stop) {
// view.alpha = alpha;
// }];
//
// UIView *titleView = [self valueForKey:@"_titleView"];
// titleView.alpha = alpha;
//// when viewController first load, the titleView maybe nil
// [[self subviews] enumerateObjectsUsingBlock:^(UIView *obj, NSUInteger idx, BOOL *stop) {
// if ([obj isKindOfClass:NSClassFromString(@"UINavigationItemView")]) {
// obj.alpha = alpha;
// *stop = YES;
// }
// }];
}
5、為了靈活設定,在離開頁面的時候呼叫一下方法去除runtime新增的view的影響:
//最終在離開頁面的時候呼叫,然後移除通過runtime新增的所有檢視。
- (void)lt_reset
{
[self setBackgroundImage:nil forBarMetrics:UIBarMetricsDefault];
[self.overlay removeFromSuperview];
self.overlay = nil;
}
最後感謝作者,demo下載地址:https://github.com/ltebean/LTNavigationBar
相關文章
- Runtime之分類新增屬性
- iOS 用runtime為分類新增成員變數或屬性iOS變數
- 為QT程式增加版本等屬性資訊QT
- iOS利用runtime給分類擴充套件屬性iOS套件
- iOS runtime 給 Category 加屬性iOSGo
- 利用Runtime清空單例屬性單例
- iOS利用runtime給分類擴充套件屬性Strong bool copyiOS套件
- Python類屬性和例項屬性分別是什麼?Python
- js 物件方法、類方法、原型方法的區別;私有屬性、公有屬性、公有靜態屬性的區別JS物件原型
- Swift快速為類擴充套件屬性Swift套件
- C# 隨機給一個全部資訊都未知的類型別,如何獲取該類的類名、屬性個數、屬性名、屬性的資料型別、屬性值?C#隨機資料型別
- iOS 開發:『Runtime』詳解(四)獲取類詳細屬性、方法iOS
- 為普通Object新增類似AttachedProperty的屬性Object
- Runtime 系列 3-- 給 category 新增屬性Go
- iOS開發之遍歷Model類的屬性並完善使用Runtime給Model類賦值iOS賦值
- Python 類的屬性與例項屬性Python
- TypeScript 類靜態屬性TypeScript
- 獲得類的屬性
- Python 動態新增例項屬性,例項方法,類屬性,類方法Python
- 揭秘Java反射:如何輕鬆獲取類的屬性及父類屬性Java反射
- Runtime類
- [JAVA] 只知物件屬性,不知類屬性?就算類答應,static都不答應Java物件
- iOS開發 Runtime是如何實現weak屬性的?iOS
- 獲取類屬性值,當前類,父類
- JavaSE基礎:Properties屬性類Java
- Python 類屬性的理解Python
- Day30--類的屬性
- Python列印類的屬性Python
- mongodb用mongoose查庫的物件,不能增加屬性MongoDB物件
- 老生常談category增加屬性的幾種操作Go
- 為textarea新增maxlength屬性
- JAVA常用類--Runtime類Java
- iOS runtime實戰應用:成員變數和屬性iOS變數
- 關於Python類屬性與例項屬性的討論Python
- php中呼叫類的屬性和函式的方法->_=>_::_$this->區別PHP函式
- 深入理解JavaScript類與物件:揭秘類欄位和靜態屬性的妙用,js靜態屬性和例項屬性JavaScript物件JS
- PHP 物件導向 (二)類屬性PHP物件
- C# 類相同屬性賦值C#賦值