xaoxuu / axkit Goto Github PK
View Code? Open in Web Editor NEW系统类的功能扩展和一些常用的控件封装。文档地址:https://xaoxuu.com/wiki/axkit
License: MIT License
系统类的功能扩展和一些常用的控件封装。文档地址:https://xaoxuu.com/wiki/axkit
License: MIT License
想要实现圆角阴影效果可以这样:
UIView *view = [[UIView alloc] initWithFrame:CGRectMake(100, 100, 100, 100)];
view.backgroundColor = [UIColor yellowColor];
// 圆角半径30,阴影为向下投射的浮起样式
[view.layer ax_cornerRadius:30 shadow:LayerShadowDownFloat];
[self.view addSubview:view];
想自定义阴影效果可以这样:
[view.layer ax_customShadowWithOpacity:0.2 radius:5 offset:CGSizeMake(0, 4)];
// 或者
CGMutablePathRef squarePath = CGPathCreateMutable();
CGPathAddRect(squarePath, NULL, view.bounds);
[view.layer ax_customShadowWithOpacity:0.2 radius:5 offset:CGSizeMake(0, 4) color:[UIColor blueColor] path:squarePath];
CGPathRelease(squarePath);
UIImage *img = UIImageFromView(self.view);
使用示例:
NSError *error = [NSError ax_errorWithMaker:^(NSErrorMaker * _Nonnull error) {
error.domain = @"my domain";
error.code = 123;
error.localizedDescription = @"desc123123";
error.localizedFailureReason = @"reason123123";
error.localizedRecoverySuggestion = @"suggestion123123";
[error.localizedRecoveryOptions addObject:@"1. xxx"];
[error.localizedRecoveryOptions addObject:@"2. xxx"];
}];
AXLogError(error);
当然,只写一个错误描述或者别的什么信息都是可以的:
NSError *error = [NSError ax_errorWithMaker:^(NSErrorMaker * _Nonnull error) {
error.localizedDescription = @"发生了未知错误";
}];
AXLogError(error);
为view增加了快速获取bounds center的方法:
#pragma mark bounds center
@property (nonatomic, readonly, assign) CGPoint boundsCenter;
@property (nonatomic, readonly, assign) CGFloat boundsCenterX;
@property (nonatomic, readonly, assign) CGFloat boundsCenterY;
更容易将某个控件放置到父视图中间
对比服务器端的版本(remoteVersion)和当前app版本([NSBundle ax_appVersion])
VersionLaterThanVersion(remoteVersion, [NSBundle ax_appVersion], ^(BOOL later) {
if (later) {
// @xaoxuu: 有新版本
} else {
// @xaoxuu: 有新版本
}
}, ^(NSError * _Nonnull error) {
AXLogError(error);
});
版本必须都以"."分隔,并且两个版本的"."的个数相同
目前这个bug已修复,并且限定AXLocalizeAllSubviewsInView()只能转换普通文本。
目前的方法是:
self.imageView.image = [UIImage ax_imageWithColor:axColor.theme size:self.imageView.frame.size alpha:1];
每次都要输入size和alpha很麻烦。
理想的方法应该是:
self.imageView = [UIImageView ax_imageViewWithColor:axColor.theme];
// 将self.testView中所有的UILabel中的文字转换支持多语言
[self.testView ax_eachSubview:[UILabel class] action:^(__kindof UIView * _Nonnull subview) {
UILabel *lb = subview;
AXLocalizedLabel(lb);
}];
// 将self.testView中所有的UITextField中的文字转换支持多语言
[self.local ax_eachSubview:[UITextField class] action:^(__kindof UIView * _Nonnull subview) {
UITextField *tf = subview;
AXLocalizedTextField(tf);
}];
// 将self.testView中所有的UITextView中的文字转换支持多语言
[self.local ax_eachSubview:[UITextView class] action:^(__kindof UIView * _Nonnull subview) {
UITextView *tv = subview;
AXLocalizedTextView(tv);
}];
注意:此方法生效的前提是你的
Localizable.strings
文件中有这些语言的翻译。
/**
将UILabel中的文字转换成NSLocalizedString
@param label 目标UILabel
*/
FOUNDATION_EXTERN void AXLocalizedLabel(UILabel *label);
/**
将UITextView中的文字转换成NSLocalizedString
@param textView 目标UITextView
*/
FOUNDATION_EXTERN void AXLocalizedTextView(UITextView *textView);
/**
将UITextField中的文字转换成NSLocalizedString
@param textField 目标UITextField
*/
FOUNDATION_EXTERN void AXLocalizedTextField(UITextField *textField);
inline void AXLocalizedLabel(UILabel *label){
label.text = NSLocalizedString(label.text, nil);
}
inline void AXLocalizedTextView(UITextView *textView){
textView.text = NSLocalizedString(textView.text, nil);
}
inline void AXLocalizedTextField(UITextField *textField){
textField.placeholder = NSLocalizedString(textField.placeholder, nil);
textField.text = NSLocalizedString(textField.text, nil);
}
首先我个人认为设计合理、逻辑严谨的代码是用不到这个机制的,但是我们不能保证我们面对的代码永远都是完美的,所以我就提供了这个冷却机制以延长那些癌症晚期的代码的寿命。
优点:执行代码像放技能一样,可以强行打破死循环、避免死循环、避免过高频率访问某一资源、从一定程度上缓解了内存、CPU压力。
缺点:治标不治本,最好是找出会产生问题的代码,从根源上解决问题。
某种耗时耗能操作,希望在某种条件下触发,但又担心用户频繁触发,就可以这样:
// @xaoxuu: 重新获取数据源并刷新tableView
- (void)reloadDataAndRefreshTableView{
// 无论如何,2秒内最多只会执行一次此方法。
[NSBlockOperation ax_delay:0 cooldown:2 token:@"reload data and refresh table view" performInMainQueue:^{
[self.dataList removeAllObjects];
[self reloadTableView];
}];
}
- (IBAction)btn1:(UIButton *)sender {
[NSBlockOperation ax_delay:0 cooldown:60 token:self performInMainQueue:^{
// @xaoxuu: 立即在主线程施放大招,冷却时间是60秒。
}];
}
- (IBAction)btn2:(UIButton *)sender {
[NSBlockOperation ax_delay:2 cooldown:120 token:self performInBackground:^{
// @xaoxuu: 延迟2秒后在后台默默施放大招,冷却时间是120秒。
}];
}
// @xaoxuu: 两者的token相同则共享冷却时间。
如何强行打破死循环?说实话我是没有遇到这种需求,仅仅是这个机制有这种能力,觉得挺有趣,就尝试一下:
// 自己调用自己,无限循环
- (void)loop{
AXLogFunc();
[self loop];
}
// 自己调用自己,但是发现代码在冷却,所以就失效了,一个环节被中断,死循环就被打破了
- (void)loop{
AXLogFunc();
[NSBlockOperation ax_delay:0 cooldown:0.0001 token:@"loop" performInMainQueue:^{
[self loop];
}];
}
给每一个block分配一个dispatch_after的函数,执行的时候开始计时,并且函数标记为disable,计时结束后重新enable。
目前可以根据子视图的类来只选择某些子视图,代码如下:
[self.topView ax_eachSubview:[UIImageView class] action:^(__kindof UIView * _Nonnull subview) {
}];
计划增加一种可以根据tag值或者selected状态来选定特定类型的子视图,如:
[self.view ax_eachSubview:[UIImageView class] tag:1 action:^(__kindof UIView * _Nonnull subview) {
}];
[self.view ax_eachSubview:[UIButton class] selected:YES action:^(__kindof UIView * _Nonnull subview) {
}];
增加了ax_cacheObject
,与ax_cacheValue
功能不同。区别参考系统的setObject
和setValue
。
增加了ax_removeObjectForKey
方法。
增加了NSStringFromASCIIValue(unsigned char ASCIIValue)
函数,快速将ASCII码值转换成OC字符串。
增加了一个快速输出百分比的函数,将浮点型CGFloat数据转换成0%~100%的格式化字符串
NSStringFromPercent(CGFloat x);
// 当传入x为小于或等于0的数时,NSStringFromPercent(x)为@"0%"。
// 当传入x为大于0并且小于1的数如0.3时,NSStringFromPercent(0.3)为@"30%"。
// 当传入x为大于或等于1的数时,NSStringFromPercent(x)为@"100%"。
增加了NSInteger类型和CGFloat类型的取值范围
增加了确保值在某个范围的方法,示例:
// 希望value在0~1之间
CGFloat value = sender.text.floatValue;
CGFloat result = AXFloatInRange(value, AXFloatRangeMake(0, 1));
// 当value取值小于0时,result为0;
// 当value取值大于0小于1时,result为value;
// 当value取值大于1时,result为1;
支持的数据类型有:
增加了万能控制器跳转方法,传入目标控制器名,跳转到目标控制器
此方法是安全的,会有失败回调
/**
push view controller
@param vcName view controller name
@param animated animated
*/
- (void)ax_pushViewControllerNamed:(NSString *)vcName animated:(BOOL)animated;
/**
push view controller
@param vcName view controller name
@param animated animated
@param completion completion
*/
- (void)ax_pushViewControllerNamed:(NSString *)vcName animated:(BOOL)animated completion:(void (^)(UIViewController *targetVC))completion;
/**
push view controller
@param vcName view controller name
@param animated animated
@param completion completion
@param fail error info
*/
- (void)ax_pushViewControllerNamed:(NSString *)vcName animated:(BOOL)animated completion:(void (^)(UIViewController *targetVC))completion fail:(void (^)(NSError *error))fail;
增加了方便的创建Error实例的构造方法
/**
创建一个error实例
@param domain 域
@param code 错误码
@param description 描述
@param reason 原因
@param suggestion 建议
@return error实例
*/
+ (instancetype)ax_errorWithDomain:(NSErrorDomain)domain code:(NSInteger)code description:(nullable NSString *)description reason:(NSString *)reason suggestion:(nullable NSString *)suggestion;
为AXLogError(NSError)
增加了一个输出内容,0.0.4版本及其之前只输出error.localizedDescription
,0.0.5及之后版本现在还会增加一行信息error.localizedFailureReason
增加了快速创建自定义BarItem的构造方法
/**
快速创建一个baritem
@param view 自定义视图
@param action 响应的事件
@return baritem实例
*/
+ (instancetype)ax_itemWithCustomView:(UIView *)view action:(void (^)(id sender))action;
删除了两个使用频率低的接口
更改这两个接口使其能够返回实例:
/**
弹窗(标题+消息+自定义按钮)(如果action为nil,则只有一个确定按钮)
@param title 标题
@param message 消息
@param action 按钮
@return 返回alert对象
*/
+ (instancetype)ax_showAlertWithTitle:(nullable NSString *)title message:(nullable NSString *)message actions:(void (^ __nullable)(UIAlertController *alert))actions;
/**
弹窗(标题+消息+自定义按钮)(如果action为nil,则只有一个确定按钮)
@param title 标题
@param message 消息
@param action 按钮
@return 返回alert对象
*/
+ (instancetype)ax_showActionSheetWithTitle:(nullable NSString *)title message:(nullable NSString *)message actions:(void (^ __nullable)(UIAlertController *alert))actions;
UIActivityIndicatorView *indicator = [UIActivityIndicatorView defaultIndicator];
// @xaoxuu: 显示到self.view中心
indicator.show(self.view);
// @xaoxuu: 隐藏
indicator.hide();
功能简单不需要解释,下面有效果图
快速
// @xaoxuu: 一行代码的消息弹窗
[UIAlertController ax_showAlertWithTitle:@"Hello Alert" message:@"这是用一行代码弹出来的只有一个按钮的窗口" action:nil];
// @xaoxuu: 最常用的【取消】+【确定】弹窗
[UIAlertController ax_showAlertWithTitle:@"Hello Alert" message:@"这是用一个方法弹出来的有两个按钮的窗口" ok:^(UIAlertAction * _Nonnull sender) {
AXLogFormat(@"点击了OK按钮");
}];
效果图:
只有一个按钮 | 两个按钮 |
---|---|
方法简单,但功能不受限
[UIAlertController ax_showAlertWithTitle:@"Hello Alert" message:@"这是用一个方法弹出来的完全自定义的系统弹窗" action:^(UIAlertController * _Nonnull alert) {
// @xaoxuu: 添加取消按钮
[alert ax_addCancelAction];
// @xaoxuu: 破坏性按钮(标题为【Confirm】)
[alert ax_addDestructiveActionWithTitle:nil handler:^(UIAlertAction * _Nonnull sender) {
}];
// @xaoxuu: 自定义标题的破坏性按钮
[alert ax_addDestructiveActionWithTitle:@"删除2" handler:^(UIAlertAction * _Nonnull sender) {
}];
// @xaoxuu: 普通按钮(默认标题为【OK】)
[alert ax_addDefaultActionWithTitle:nil handler:^(UIAlertAction * _Nonnull sender) {
}];
// @xaoxuu: 自定义标题的普通按钮
[alert ax_addDefaultActionWithTitle:@"确定2" handler:^(UIAlertAction * _Nonnull sender) {
}];
}];
// @xaoxuu: 自定义视图的系统弹窗
[UIAlertController ax_showAlertWithTitle:nil message:@"\n\n\n\n\n\n\n\n\n\n\n" action:^(UIAlertController * _Nonnull alert) {
UIView *view = [[UIView alloc] initWithFrame:CGRectMake(8, 8, 270-16, 222.3-16)];
view.backgroundColor = [UIColor md_yellow];
view.layer.masksToBounds = YES;
view.layer.cornerRadius = 8;
[UIActivityIndicatorView defaultIndicator].show(view);
[alert.view addSubview:view];
}];
效果图:
自定义按钮 | 自定义视图 |
---|---|
没有写入到本地
push到子控制器的时候隐藏底部tabbar。
此方法原本属于UIViewController
,写在要push的viewController
里。
如果一个导航控制器想要让所有push的子控制器都隐藏tabbar。
一般的做法是继承,在一个父类- (void)viewDidLoad
中加上这么一行代码:
[self hidesBottomBarWhenPushed]; // available(0.0.6)
现在你有了另一种选择,“设置”这个导航控制器,让它push的子控制器都隐藏tabbar。
在导航控制器的- (void)viewDidLoad
中加上这么一行代码:
[self ax_hidesBottomBarWhenPushed:YES]; // available(0.0.6)
作者注:
实现这个功能主要技术点是如何取消交换方法。
单纯地取消就是再交换一次,但是实际应用必须判断是否交换过,只有交换过才能再交换一次负负得正,否则会产生错乱。
为了判断是否交换过,我查阅了很多资料,也在很多技术群里询问,没有得到一个优雅的解决方案。只能采取比较笨的方法:就是在交换的时候做一个标记,通过标记值判断该方法指针是否指向原地址。
之前我们实现了将某个控件的文本转换成支持多语言的文本NSLocalizedString
详见 #3。
而在0.0.6
以后的版本,你可以用一行代码将本页面所有控件所有文本进行转换:
AXLocalizeAllSubviewsInView(self.view); // available(0.0.6)
这个方法建议在项目成型之前使用,避免了频繁更改造成代码混乱,也能够提高开发效率。
缺点是略微影响性能,可以在项目成型到无需大改的阶段之后删掉此代码,手动替换。
// @xaoxuu: 以下这些方法提供更加灵活的实现,可按需使用。
AXLocalizeLabel(self.label);
AXLocalizeTextField(self.textField);
AXLocalizeTextView(self.textView);
AXLocalizeAllLabelsInView(self.view);
AXLocalizeAllTextFieldsInView(self.view);
AXLocalizeAllTextViewsInView(self.view);
其实只要不那么极致要求性能的话,只要别用在tableview的cell里,一直留在项目里也是没有多大影响的。
之前我们实现了将某个控件的文本转换成支持多语言的文本NSLocalizedString
详见 #3。
而在0.0.6
以后的版本,你可以用一行代码将本页面所有控件所有文本进行转换:
AXLocalizeAllSubviewsInView(self.view); // available(0.0.6)
这个方法建议在项目成型之前使用,避免了频繁更改造成代码混乱,也能够提高开发效率。
缺点是略微影响性能,可以在项目成型�到无需大改的阶段之后删掉此代码,手动替换。
// @xaoxuu: 以下这些方法提供更加灵活的实现,可按需使用。
AXLocalizeLabel(self.label);
AXLocalizeTextField(self.textField);
AXLocalizeTextView(self.textView);
AXLocalizeAllLabelsInView(self.view);
AXLocalizeAllTextFieldsInView(self.view);
AXLocalizeAllTextViewsInView(self.view);
其实只要不那么极致要求性能的话,只要别用在tableview的cell里,一直留在项目里也是没有多大影响的。
计算了被遮挡的高度offset,将view上移offset的高度。而不是上移一个keyboard的高度。
// @xaoxuu: 获取view距离底部的高度
CGFloat superH = self.ax_superview.frame.size.height;
CGFloat superF = self.ax_superview.frame.origin.y;
CGFloat heightToBottom = kScreenH - superF - superH;
// @xaoxuu: 被遮挡的高度
CGFloat offset = keyBoardHeight - heightToBottom;
if (offset < 0) {
offset = 0;
}
现在也可以快速将BOOL值、float值转换成字符串了。
调整了将int值转换成字符串的函数命名
// available(0.0.6)
FOUNDATION_EXTERN NSString *NSStringFromInt(int x);
// deprecated(0.0.5)
FOUNDATION_EXTERN NSString *NSStringFromInt32(int x);
由于初代版本的疏忽,此功能理应成为UINavigationController
的方法,却错误地放在了UIViewController
的分类里。0.0.6修复了此bug,同时,为简版省去了animated:
参数,默认为YES
。
现在你可以通过如下方式调用:
简版:
// available(0.0.6)
[self.navigationController ax_pushViewControllerNamed:@"tmpVC"];
// deprecated(0.0.5)
[self ax_pushViewControllerNamed:@"tmpVC" animated:YES];
完整版:
// available(0.0.6)
[self.navigationController ax_pushViewControllerNamed:@"tmpVC" animated:YES completion:^(UIViewController * _Nonnull targetVC) {
// push completed call back
targetVC.title = @"tmp";
} fail:^(NSError * _Nonnull error) {
// push failed call back
AXLogError(error);
}];
// deprecated(0.0.5)
[self ax_pushViewControllerNamed:@"tmpVC" animated:YES completion:^(UIViewController * _Nonnull targetVC) {
// push completed call back
targetVC.title = @"tmp";
} fail:^(NSError * _Nonnull error) {
// push failed call back
AXLogError(error);
}];
push到子控制器的时候隐藏底部tabbar。
此方法本来属于UIViewController
,写在要push的viewController
里。
如果一个导航控制器想要让所有push的子控制器都隐藏tabbar。
一般的做法是继承,在一个父类- (void)viewDidLoad
中加上这么一行代码:
[self hidesBottomBarWhenPushed]; // available(0.0.6)
现在你有了另一种选择,“设置”这个导航控制器,让它push的子控制器都隐藏tabbar。
在导航控制器的- (void)viewDidLoad
中加上这么一行代码:
[self ax_hidesBottomBarWhenPushed:YES]; // available(0.0.6)
作者注:
实现这个功能主要技术点是如何取消交换方法。
单纯地取消就是再交换一次,但是实际应用必须判断是否交换过,只有交换过才能再交换一次负负得正,否则会产生错乱。
为了判断是否交换过,我查阅了很多资料,也在很多技术群里询问,没有得到一个优雅的解决方案。只能采取比较笨的方法:就是在交换的时候做一个标记,通过标记值判断该方法指针是否指向原地址。
之前我们只有一个方法来让某个view的每一个具有某些特征的子视图去执行一段代码,即:
// 以class来选定某些子视图,例如所有的button、所有的label等
// 让所有的按钮的标题为蓝色
[self.view ax_eachSubview:[UIButton class] action:^(__kindof UIView * _Nonnull subview) {
UIButton *btn = subview;
[btn setTitleColor:[UIColor md_blue] forState:UIControlStateNormal];
}];
现在你不仅可以通过类来选定,还可以通过tag值
、tag值区间
:
// 打印出所有tag为100的子视图
[self.view ax_eachSubviewWithTag:100 action:^(__kindof UIView * _Nonnull subview) {
AXLogOBJ(subview);
}];
// 打印出所有tag值在0~100的子视图
[self.view ax_eachSubviewWithTags:AXIntegerRangeMake(0, 100) action:^(__kindof UIView * _Nonnull subview) {
AXLogOBJ(subview);
}];
对于常用控件,可以更方便地选取:
// 让所有的按钮的标题为蓝色
[self.view ax_eachButtonInvokeAction:^(__kindof UIButton * _Nonnull button) {
[button setTitleColor:[UIColor md_blue] forState:UIControlStateNormal];
}];
支持的控件有:UIButton、UILabel、UITextField、UITextView、UIImageView
自己重写的基于这些控件的子控件也可以被选取出来。
在开发中我经常需要写这一段代码:
UIView *tmpView = [[NSBundle mainBundle] loadNibNamed:@"tmpView" owner:nil options:nil].firstObject;
于是就有了UIViewFromNibNamed
函数:
UIView *tmpView = UIViewFromNibNamed(@"tmpView"); // available(0.0.6)
我们经常把这几个宏作为开发必备的宏:
// available(0.0.6)
#define kScreenBounds [UIScreen mainScreen].bounds
// available(0.0.1)
#define kScreenW [UIScreen mainScreen].bounds.size.width
#define kScreenH [UIScreen mainScreen].bounds.size.height
#define kScreenCenterX (0.5 * kScreenW)
#define kScreenCenterY (0.5 * kScreenH)
在开发初期,美工的UI素材还没有做好,我们的ImageView不给图的时候一般都是空白,不利于测试。
自己去找的话,,,我真的没有时间。
但是写个工具的时间还是有的:
// 填充随机色
[self.imageView ax_fillWithRandomColor]; // available(0.0.6)
当然,你想填充指定的颜色也是可以的:
// 填充颜色
[self.imageView ax_fillWithColor:[UIColor md_green]]; // available(0.0.6)
接口:
@interface UINavigationItem (AXExtension)
/**
隐藏返回按钮的标题
*/
- (void)ax_hideBackBarButtonTitle;
/**
隐藏返回按钮(同时也不能右划返回)
*/
- (void)ax_hideBackBarButton;
@end
实现:
@implementation UINavigationItem (AXExtension)
/**
隐藏返回按钮的标题
*/
- (void)ax_hideBackBarButtonTitle{
self.backBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:@"" style:UIBarButtonItemStylePlain target:nil action:nil];
}
/**
隐藏返回按钮(同时也不能右划返回)
*/
- (void)ax_hideBackBarButton{
self.leftBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:@"" style:UIBarButtonItemStylePlain target:nil action:nil];
}
@end
如果项目中集成了AXKit,可以用这样一句代码打印testView在屏幕中的绝对frame。
AXLogCGRect(self.testView.frameInScreen);
有时候想pop到从RootVC开始数的第二个VC怎么办?虽然实现并不复杂,但是这些可自动化的工作能封装起来用着自然舒服很多。
于是我封装了两个更灵活的pop方法:
/**
pop到指定viewController
@param index 从rootVC开始向后数的index,rootVC为0
*/
- (void)ax_popToViewControllerWithIndexFromRoot:(NSUInteger)index;
/**
pop到指定viewController
@param index 从当前viewController开始向前数的index,当前VC为0
*/
- (void)ax_popToViewControllerWithIndexFromSelf:(NSUInteger)index;
使用示例:
我在一个view里放置了两列按钮,一列是从RootVC开始数index,另一列是反向从当前VC开始数index。
- (IBAction)popFromRoot:(UIButton *)sender {
[self.controller.navigationController ax_popToViewControllerWithIndexFromRoot:sender.titleLabel.text.integerValue];
// 传入参数为几,就pop到从rootVC开始向下数的第几层VC。
}
- (IBAction)popFromSelf:(UIButton *)sender {
[self.controller.navigationController ax_popToViewControllerWithIndexFromSelf:sender.titleLabel.text.integerValue];
// 传入参数为几,就向前pop几层。
}
字符串其实可以干更多事
- (nullable NSURL *)absoluteURL;
- (BOOL)isURLString;
- (nullable UIImage *)image;
例如我们获取到一个"URLString",用来显示用户头像
NSString *tmp = @"https://xaoxuu.com/images/avatar.png";
// 需要用到URL的话,就是tmp.absoluteURL
// 需要判断它是不是合法的URL就
if (tmp.isURLString) {
// 是URL
} else {
// 不是URL
}
例如资源图片名为"test.png"
// 有一个ImageView名为imgv
imgv.image = @"test".image;
做了一点简单的封装,让代码更简单
两个类都添加了一个移除分割线的方法:
/**
移除系统自带的分割线
*/
- (void)ax_hideSeparator;
注意:分割线不是一开始就有的,因此建议都写在
- viewDidLayoutSubviews
中。
使用示例:
- (void)viewDidLayoutSubviews{
[super viewDidLayoutSubviews];
[self.tabBar ax_hideSeparator];
}
/**
粗略判断颜色是不是浅色调
@return 是不是浅色
*/
- (BOOL)isLightColor;
例如判断背景颜色是浅色的话,文字颜色设为主题色,如果背景颜色是深色的话,文字颜色为白色:
// 假设view上面有一个label
if (view.backgroundColor.isLightColor) {
label.textColor = axColor.theme;
} else {
label.textColor = axColor.white;
}
函数很简单,能够提供一点便利,毕竟函数的调用比写宏更加快捷而且不易出错。
声明:
/**
只在debug模式下运行的函数
@param debug debug操作
*/
FOUNDATION_EXTERN void ax_debug_only(void (^debug)());
实现:
inline void ax_debug_only(void (^debug)()){
#ifdef DEBUG
if (debug) {
debug();
}
#endif
}
移除standardUserDefaults所有偏好设置
[NSUserDefaults ax_removeDefaultPersistentDomain];
声明:
/**
移除默认的[NSUserDefaults standardUserDefaults]的所有配置
*/
+ (void)ax_removeDefaultPersistentDomain;
// 启动图片
UIImage *img = [NSBundle ax_appLaunchImage];
声明:
/**
启动图片路径
@return 启动图片路径
*/
+ (NSString *)ax_appLaunchImagePath;
/**
启动图片
@return 启动图片
*/
+ (UIImage *)ax_appLaunchImage;
使用示例:
// 将textField的placeholder颜色设为主题色
textField.placeholderColor = axColor.theme;
声明:
FOUNDATION_EXTERN NSArray *NSClassGetAllSubclasses(Class cls);
示例:
NSArray *arr = NSClassGetAllSubclasses([UIColor class]);
AXLogOBJ(arr);
// LOG信息如下:
2017-06-30 10:42:42.380764+0800 AXKitDemo[5400:2416565]
➤ func:-[DebugVC viewDidLoad] line:22
💬[
NSColor,
UICIColor,
UIDisplayP3Color,
UICGColor,
UICachedDevicePatternColor,
UIDeviceWhiteColor,
UICachedDeviceWhiteColor,
UIDeviceRGBColor,
UICachedDeviceRGBColor,
UIPlaceholderColor
]
使用示例:
// 保存图片
[NSUserDefaults ax_setImage:newImage forKey:@"AVATAR"];
// 读取图片
[NSUserDefaults ax_readImageForKey:@"AVATAR" completion:^(UIImage * _Nonnull image) {
// 读取成功
self.avatar.image = image;
} failure:^(NSError * _Nonnull error) {
// 读取失败
AXLogOBJ(error);
}];
使用方法和alertView相同:(详情请见 #21 )
[UIAlertController ax_showActionSheetWithTitle:@"操作表" message:@"操作表描述" action:^(UIAlertController * _Nonnull alert) {
[alert ax_addCancelAction];
[alert ax_addDefaultActionWithTitle:@"确定" handler:^(UIAlertAction * _Nonnull sender) {
}];
[alert ax_addDestructiveActionWithTitle:@"删除" handler:^(UIAlertAction * _Nonnull sender) {
}];
}];
声明:
/**
弹窗(标题+消息+自定义按钮)(如果action为nil,则只有一个确定按钮)
@param title 标题
@param message 消息
@param action action
*/
+ (void)ax_showActionSheetWithTitle:(nullable NSString *)title message:(nullable NSString *)message action:(void (^ __nullable)(UIAlertController *alert))action;
/**
弹出一个【取消+确定】两个按钮的弹窗(如果action为nil,则只有一个确定按钮)
@param title 标题
@param message 消息内容
@param ok 确定按钮事件
*/
+ (void)ax_showActionSheetWithTitle:(nullable NSString *)title message:(nullable NSString *)message ok:(void (^ __nullable)(UIAlertAction *sender))ok;
示例:(AppDelegate.m)
// @xaoxuu: 配置主题色
[[UIColorManager sharedInstance] configDefaultTheme:^(UIThemeColorModel * _Nonnull color) {
color.theme = [UIColor md_amber];
color.accent = [UIColor md_lime];
color.background = [UIColor whiteColor];
}];
// 更改axColor的颜色将不会自动缓存,需要调用[axColor saveCurrentTheme]进行缓存。
[axColor saveCurrentTheme];
补充了部分接口的注释
NSString分类增加了拼接字符串的快捷方法
用法示例:
NSString *str = @"abc".append(@"d").appendCGFloat(1.2).appendReturn().appendNSInteger(50);
NSLog(@"%@",str);
控制台输出为:
2017-04-14 14:32:53.534 AXKitDemo[17111:290832] abcd1.2
50
接口:
/**
拼接字符串
*/
- (NSString *(^)(NSString *string))append;
/**
拼接NSInteger
*/
- (NSString *(^)(NSInteger x))appendNSInteger;
/**
拼接NSUInteger
*/
- (NSString *(^)(NSUInteger x))appendNSUInteger;
/**
拼接CGFloat
*/
- (NSString *(^)(CGFloat x))appendCGFloat;
/**
拼接@"\n"
*/
- (NSString *(^)())appendReturn;
修改了定时器重启方法使之更符合实际功能
// 0.0.3 定时器“恢复”,易产生歧义
- (BOOL)ax_resume;
// 0.0.4 定时器重新开始计时
- (BOOL)ax_restart;
增加了两个baritem方法
/**
创建一个baritem
@param image 图片名
@param action 响应的事件
@return baritem实例
*/
+ (instancetype)ax_itemWithImageName:(NSString *)image action:(void (^)(id sender))action;
/**
快速创建一个baritem
@param title 标题
@param action 响应的事件
@return baritem实例
*/
+ (instancetype)ax_itemWithTitle:(NSString *)title action:(void (^)(id sender))action;
更改了获取颜色某个通道的方法
0.0.3 | 0.0.4 |
---|---|
- (CGFloat)getRed; | - (CGFloat)redValue; |
- (CGFloat)getGreen; | - (CGFloat)greenValue; |
- (CGFloat)getBlue; | - (CGFloat)blueValue; |
- (CGFloat)getAlpha; | - (CGFloat)alphaValue; |
增加了配置全局hidesBottomBarWhenPushed的方法
需要隐藏时在所属的NavigationController中调用:
// 隐藏
[self ax_hidesBottomBarWhenPushed:YES];
// 不隐藏
[self ax_hidesBottomBarWhenPushed:NO];
接口:
- (void)ax_hidesBottomBarWhenPushed:(BOOL)hide;
增加了获取RootVC的方法
UIViewController、UIView、UIButton等类中均可使用self.rootVC
来获取它所在的根控制器
使用示例:
UIViewController *rootVC = self.rootVC;
接口:
- (UIViewController *)rootVC;
根据图片名快速创建imageview
UIImageViewWithImageNamed(NSString *name);
有时候你可能会需要pop到上上一层控制器,或者根控制器下的第二个控制器等等,
有了这两个方法,你可以pop到同一NavigationController下的任意一个控制器。
/**
pop到指定viewController
@param index 从rootVC开始向后数的index,rootVC为0
*/
- (void)ax_popToViewControllerWithIndexFromRoot:(NSUInteger)index;
/**
pop到指定viewController
@param index 从当前viewController开始向前数的index,当前VC为0
*/
- (void)ax_popToViewControllerWithIndexFromSelf:(NSUInteger)index;
详细使用请见 #14
封装了NSUserDefaults,对读取的值可能为空和不为空的情况分类处理,更安全和方便。例如:
// @xaoxuu: 将用户头像缓存到userdefault
[NSUserDefaults ax_setData:UIImagePNGRepresentation(image) forKey:@"avatar"];
// @xaoxuu: 从userdefault读取图片
[NSUserDefaults ax_readDataForKey:@"avatar" completion:^(NSData * _Nonnull data) {
// @xaoxuu: 读取到值
UIImage *image = [UIImage imageWithData:data];
avatar.image = image;
} fail:^(NSError * _Nonnull error) {
// @xaoxuu: 读取不到值
AXLogError(error);
}];
详细使用请见 #13
我个人认为设计合理的代码是用不到这个机制的,
但是不能保证我们永远不需要,所以我就提供了这个冷却机制。
优点:执行代码像放技能一样,可以强行打破死循环、避免死循环、避免过高频率访问某一资源、从一定程度上缓解了内存、CPU压力。
缺点:治标不治本,最好是找出会产生问题的代码,从根源上解决问题。
使用示例:
// @xaoxuu: 重新获取数据源并刷新tableView
- (void)reloadDataSourceAndTableView{
[NSBlockOperation ax_delay:0 cooldown:2 token:@"reload data source and refresh table view" performInMainQueue:^{
[self.dataList removeAllObjects];
[self reloadTableView];
}];
}
详细使用请见 #15
Convert a boolean value to Objective-C string.
将BOOL值转换成Objective-C字符串
NSString *string = NSStringFromBool(BOOL x);
// x = YES, string = @"1"
// x = NO, string = @"0"
Convert a float value to Objective-C string.
将float类型转换成Objective-C字符串
NSString *string = NSStringFromFloat(float x);
// x = 1, string = @"1"
// x = 3.14, string = @"3.14"
Convert a CGFloat value to Objective-C string.
将CGFloat类型转换成Objective-C字符串
NSString *string = NSStringFromCGFloat(CGFloat x);
// x = 1, string = @"1"
// x = 3.14, string = @"3.14"
Convert a int / NSInteger / NSUInteger to Objective-C string.
将int类型、NSInteger类型、NSUInteger类型转换成Objective-C字符串
NSString *string1 = NSStringFromInt(int x);
NSString *string2 = NSStringFromNSInteger(int x);
NSString *string3 = NSStringFromNSUInteger(int x);
// x = 1, string1 = @"1", string2 = @"1", string3 = @"1"
Convert a pointer to Objective-C string.
将id类型指针地址转换成Objective-C字符串
NSString *string = NSStringFromPointer(id x);
// string may be anything like @"0x10b70a5c0"...
Convert a percent to Objective-C string.
将百分比数值(float,取值0~1)转换成Objective-C字符串
NSString *string = NSStringFromPercent(id x);
// x < 0 or x = 0, string = @"0%"
// x = 0.123, string = @"12.3%"
// x > 1 or x = 1, string = @"100%"
Convert a ASCII value to Objective-C string.
将单个ASCII码转换成Objective-C字符串
NSString *string = NSStringFromASCIIValue(id x);
// x = 32, string = @" "
// x = 48, string = @"0"
// x = 65, string = @"A"
// x = 90, string = @"Z"
// x = 97, string = @"a"
// x = 122, string = @"z"
弹出键盘时调整高度,传入的View为self.view
时崩溃
[self.tf_desc ax_adjustViewFrameWithKeyboard:self.view];
报错:
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[UITextField setAx_superview:]: unrecognized selector sent to instance 0x1588d650'
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.