Runtime实战之定制TabBarItem大小
方案一:UIEdgeInsets
适用场景:
适合APP的TabBarItemImage的图片资源放在本地
图片超出tabbar的高度,需移动其位置,来进行适应
弊端:
若在本地配置好后,tabbar的图片就不能改动了,若tabbar的图片来自服务端,且不停的切换图片的大小,以上则很难满足。若有此方面的需求请看方案二。
实现:
[tabbarItem setImageInsets:UIEdgeInsetsMake(<#CGFloat top#>, <#CGFloat left#>, <#CGFloat bottom#>, <#CGFloat right#>)]
注:图片太大超出tabbar时,系统并不会调整image和title的位置,你需要根据图片的高度,计算出需要往上移动的高度,然后设置top和bottom属性即可。切记top = - bottom,否则image将会被拉伸或者被压缩。
方案二:Runtime
利用runtime的话相对方案一来说要比较复杂一点,但其灵活度比较高,我们能够根据服务端所给的image来动态的变化TabBarItem的大小,类似像淘宝、京东活动时。思想:主要是利用runtime对UITabBar的layoutSubviews进行重写,然后调整UITabBarItem的位置。另外,当时在做的APP已经有4-5年的历史了,一开始打算自已定制tabbar,发现要改动的还是挺多的,于是就放弃了。做之前也看了前辈iOS程序犭袁的CYLTabBarController,从中也学到了不少思路。
实现:
首先我们使用runtime method swizzling交换系统的- (void)layoutSubviews;
使用KVC对系统的UITabBarButton、UITabBarSwappableImageView、UITabBarButtonLabel、_UIBadgeView进行捕获
拿到控件后我们对其的frame进行计算,判断当前有没有超出tabbar的高度,若超出则进行处理
再次利用runtime method swizzling交换系统的- (nullable UIView *)hitTest:(CGPoint)point withEvent:(nullable UIEvent *)event;使图片超过后也能接受点击
代码:
method swizzling:
static void ExchangedMethod(SEL originalSelector, SEL swizzledSelector, Class class) {
Method originalMethod = class_getInstanceMethod(class, originalSelector);
Method swizzledMethod = class_getInstanceMethod(class, swizzledSelector);
BOOL didAddMethod =
class_addMethod(class,
originalSelector,
method_getImplementation(swizzledMethod),
method_getTypeEncoding(swizzledMethod));
if (didAddMethod) {
class_replaceMethod(class,
swizzledSelector,
method_getImplementation(originalMethod),
method_getTypeEncoding(originalMethod));
}
else {
method_exchangeImplementations(originalMethod, swizzledMethod);
}
}
计算frame,并对其重新布局
UIView *tabBarImageView, *tabBarButtonLabel, *tabBarBadgeView;
for (UIView *sTabBarItem in childView.subviews) {
if ([sTabBarItem isKindOfClass:NSClassFromString(@"UITabBarSwappableImageView")]) {
tabBarImageView = sTabBarItem;
}
else if ([sTabBarItem isKindOfClass:NSClassFromString(@"UITabBarButtonLabel")]) {
tabBarButtonLabel = sTabBarItem;
}
else if ([sTabBarItem isKindOfClass:NSClassFromString(@"_UIBadgeView")]) {
tabBarBadgeView = sTabBarItem;
}
}
NSString *tabBarButtonLabelText = ((UILabel *)tabBarButtonLabel).text;
CGFloat y = CGRectGetHeight(self.bounds) - (CGRectGetHeight(tabBarButtonLabel.bounds) + CGRectGetHeight(tabBarImageView.bounds));
if (y < 3) {
if (!tabBarButtonLabelText.length) {
space -= tabBarButtonLabelHeight;
}
childView.frame = CGRectMake(childView.frame.origin.x,
y - space,
childView.frame.size.width,
childView.frame.size.height - y + space);
}
让图片超出部分也能响应点击事件
- (UIView *)s_hitTest:(CGPoint)point withEvent:(UIEvent *)event {
if (!self.clipsToBounds && !self.hidden && self.alpha > 0) {
UIView *result = [super hitTest:point withEvent:event];
if (result) {
return result;
}
else {
for (UIView *subview in self.subviews.reverseObjectEnumerator) {
CGPoint subPoint = [subview convertPoint:point fromView:self];
result = [subview hitTest:subPoint withEvent:event];
if (result) {
return result;
}
}
}
}
return nil;
}
注意事项
在给tabbar设置图片的时候一定要设置图片的renderingMode,否则就会出现下图中图片丢失的现象
UITabBarButton被修改frame之后,仅有UITabBarSwappableImageView能够响应点击事件,不过我们能够在UITabBar的- (void)touchesBegan:(NSSet *)touches withEvent:(nullable UIEvent *)event;方法中捕获到
当适配图片后不要忘记适配_UIBadgeView的frame
Runtime实战之定制TabBarItem大小的更多相关文章
- 包建强的培训课程(11):iOS Runtime实战
@import url(http://i.cnblogs.com/Load.ashx?type=style&file=SyntaxHighlighter.css);@import url(/c ...
- Spring Boot实战之定制URL匹配规则
本文首发于个人网站:Spring Boot实战之定制URL匹配规则 构建web应用程序时,并不是所有的URL请求都遵循默认的规则.有时,我们希望RESTful URL匹配的时候包含定界符". ...
- Spring Boot实战之定制type Formatters
本文首发于个人网站:Spring Boot实战之定制type Formatters 前面我们有篇文章介绍了PropertyEditors,是用来将文本类型转换成指定的Java类型,不过,考虑到Prop ...
- iOS:定制自适应大小的透明吐司弹框
一.简单介绍 创建一个吐司消息的黑色透明弹框,可以根据消息长短自适应大小. 可以手动创建手动显示手动关闭,也可以手动创建自动显示自动关闭. 简单好用. 二.代码使用 .h文件 // // LiveHU ...
- Spring Boot实战之定制自己的starter
本文首发于个人网站,原文地址:http://www.javaadu.online/?p=535,如需转载,请注明出处 在学习Spring Boot的过程中,接触最多的就是starter.可以认为sta ...
- 黑客攻防技术宝典web实战篇:定制攻击自动化习题
猫宁!!! 参考链接:http://www.ituring.com.cn/book/885 随书答案. 1. 指出使用自动技巧在应用程序中枚举标识符时用到的 3 个标识符“触点”. (a) HTTP ...
- iOS 收藏的笔记
目录 UI 资料类 网络篇 图表 动画 菜单栏 数据存储和数据库 第三方库 社交分享 刷新 视频音频 其他 阅读 JS 导航 系统 支付 书籍 工具类 完整项目收集 DEMO UI http://ww ...
- iOS 自定义UITabBar
推荐一篇非常好的集成各种UITabBar的三方库 <点击这里直取demo> 另外一篇根据runtime定制了一款可以出轨的UITarBar <Runtime实战之定制TabBarIt ...
- iOS 开发-- Runtime 1小时入门教程
1小时让你知道什么是Objective-C Runtime,并对它有一定的基本了解,可以在开发过程中运用自如. 三.Objective-C Runtime到底是什么东西? 简而言之,Objective ...
随机推荐
- C实现栈和队列
这两天再学习了数据结构的栈和队列,思想很简单,可能是学习PHP那会没有直接使用栈和队列,写的太少,所以用具体代码实现的时候出现了各种错误,感觉还是C语言功底不行.栈和队列不论在面试中还是笔试中都很重要 ...
- Borland C++建立工程菜鸟教程
实在不敢相信,学校里现在教学用的编译器还是七八十年代的老古董,难道这东西更能培养从没接触过代码的学生深刻理解c语言的运行流程,不得不说像VisualStdio这样的重量级开发环境确实屏蔽了很多底层的运 ...
- android中设置控件获得焦点 (转)
android中,要使控件获得焦点,需要先setFocus,再requestFocus. 以Button为例: btn.setFocusable(true); ...
- VMware下虚拟机的转移
将虚拟机文件夹整个拷贝到另一台电脑上: 打开.vmx文件 打开即可: 注意:Mac系统的虚拟机要先用unlocker206破解,才能运行OS系统.
- ChannelPipeline
Netty的ChannelPipeline和ChannelHandler机制类似于Servlet和Filter过滤器,这类拦截器实际上是职责链模式的一种变形,主要是为了方便事件的拦截和用户业务逻辑的定 ...
- [LeetCode] Single Number
Given an array of integers, every element appears twice except for one. Find that single one. Note: ...
- 使用python解析Json字符串-获取Json字符串关键字
import json data = { "statusCode": 0, "data": { ", "height": &quo ...
- nodejs 提示‘xxx’ 不是内部或外部命令解决方法
本文介绍了node.js包管理工具npm安装模块后,无法通过命令行执行命令,提示‘xxx’ 不是内部或外部命令的解决方法,给需要的小伙伴参考下. 一般出现这样的问题原因是npm安装出现了问题,全局 ...
- java-集合2
浏览以下内容前,请点击并阅读 声明 下面对集中核心集合的接口分别总结 Collection接口 一般情况下,集合的实现类会有一个含有Collection类型为参数的构造器,可以由一个指定的集合类创建该 ...
- python 安装模块
python安装模块的方法很多,在此仅介绍一种,不需要安装其他附带的pip等,python安装完之后,配置环境变量,我由于中英文分号原因,环境变量始终没能配置成功汗. 1:下载模块的压缩文件解压到任意 ...