美文网首页iOS进阶iOSer 干货部落iOS
谈不完美的IBDesignable/IBInspectable可

谈不完美的IBDesignable/IBInspectable可

作者: minggo | 来源:发表于2016-05-14 09:49 被阅读4195次

我们好像慢慢地习惯了“理想很丰满,现实很骨感”这样顺序这样的转折这样常态,那么如果是“现实很丰满,理想很骨感”,我们能接受吗?现实丰满可以,但是理想很骨感那就不要将就了。就像薛之谦希望是能通过“丑八怪 呀啊呀啊呀哎呀”来唱红的自己,而不是上综艺做直男直到没朋友的谐星来笑红自己却跟他的歌关系不大。

苹果开发中使用的XCode也有这样的“现实丰满,理想骨感”例子,苹果公司在2011年就推出了UIStoryboard技术,到现在已经6年了。苹果还不在xcode的Interface Builder上直接提供修改控件的圆角,边框设置,而是提供IBDesignable/IBInspectable这样的技术让这些重复简单的工作由开发者来实现圆角外框,最后category上使用IBDesignable/IBInspectable却不能直接现实想要的结果。

那边我们来体验一下薛之谦的“人红歌不红”的“现实很丰满,理想很骨感”感觉。


文章思维导图.png

一.我们想要很简单

在Storyboard中的所有控件能通过Interface builder直接设置最基本圆角,边框和边框颜色属性,表达理想的Storyboard能显示出我要的渲染效果,而不是编写代码后只能在运行在手机或模拟器时才出现我们想要的效果。就像薛之谦想通唱歌红了自己,简单明了。

二.基本概念

  1. IB_DESIGNABLE的宏的功能就是让XCode动态渲染出该类图形化界面。UIView 或 NSView使用IB_DESIGNABLE宏声明时候,就是让Interface Builder知道它应该在UIStoryboard或者Xib中画布上直接渲染视图,不需要等到编译运行后就能预先展示出来效果 。
  1. IBInspectable修饰属性,可以是用户自定义的运行时属性,让支持KVC的属性能够在Attribute Inspector中配置。

三.使用方式

1.IB_DESIGNABLE放在@interface或者@implement都可以,申明这个类在XCode直接看到渲染的效果。
IB_DESIGNABLE
@interface IBDesignableImageView : UIImageView
2.IBInspectable 修饰属性,使属性能在XCode中直接设置。**
@property(nonatomic,assign) IBInspectable CGFloat cornerRadius;

四 .普通类继承关系实现渲染效果

根据第三所列出的2个关键点,详细具体实现:

1.自定义IBDesignableImageView 继承UIImageView。
#import <UIKit/UIKit.h>
IB_DESIGNABLE
@interface IBDesignableImageView : UIImageView
    @property(nonatomic,assign) IBInspectable CGFloat cornerRadius;
@end
2.接着在IBDesignableImageView.m文件实现下set方法
#import "IBDesignableImageView.h"
@implementation IBDesignableImageView
-(void)setCornerRadius:(CGFloat)cornerRadius{
    _cornerRadius = cornerRadius;//不要使用self.cornerRadius = cornerRadius;这样会死循环
    self.layer.masksToBounds = YES;
    self.layer.cornerRadius = cornerRadius;
}
@end
3.接着,XCode中Customer Class选择IBDesignableImageView。
4.最后,interface builder属性栏中设置你刚刚属性。
类继承关系实现效果图

主要就是以上四步基本满足一下下storyboard成功展示一种View实时渲染效果的快感,犹如薛之谦尝试到一首《丑八怪》火一阵子,爽一阵子的快感,并且不会让人误认为这是赵全的《我很丑可是我很温柔》的续本。

五.UIView的Category实现渲染效果

尝到了好处,自然想到实现通用的方式给需要控件都加上interface builder可设置相关属性。所以,我们自认为UIView其他子View父类,那么如果UIView可是直接在XCode上设置属性实现渲染,那么其他子View随之得到渲染效果。

1.我们最想看到的结果是

我们最想看到结果是,UIImageView、UITextField、UIButton等等都能如愿的被interface builder直接修改相关圆角,边框等等属性。噔噔,我们脑海浮现以下画面:


最理想状态
2.编写UIView的Category类UIView+MGO.h
#import <UIKit/UIKit.h>
IB_DESIGNABLE
@interface UIView (MGO)
    @property(nonatomic,assign) IBInspectable CGFloat cornerRadius;
    @property(nonatomic,assign) IBInspectable CGFloat borderWidth;
    @property(nonatomic,assign) IBInspectable UIColor *borderColor;
    @property(nonatomic,assign) IBInspectable CGFloat defineValue;
@end
3.编写UIView+MGO.m中的实现
#import "UIView+MGO.h"
#import <objc/runtime.h>
@implementation UIView (MGO)
-(void)setCornerRadius:(CGFloat)cornerRadius{
    self.layer.masksToBounds = YES;
    self.layer.cornerRadius = cornerRadius;
}
-(void)setBorderColor:(UIColor *)borderColor{
    self.layer.borderColor = borderColor.CGColor;
}
-(void)setBorderWidth:(CGFloat)borderWidth{
    self.layer.borderWidth = borderWidth;
}
-(void)setDefineValue:(CGFloat)defineValue{
    objc_setAssociatedObject(self, @selector(defineValue), @(defineValue),OBJC_ASSOCIATION_ASSIGN);
}
-(CGFloat)cornerRadius{
    return self.layer.cornerRadius;
}
-(CGFloat)borderWidth{
    return self.layer.borderWidth;
}
-(UIColor *)borderColor{
    return [UIColor colorWithCGColor:self.layer.borderColor];
}
-(CGFloat)defineValue{
    return [objc_getAssociatedObject(self, @selector(defineValue)) floatValue];
}
@end

这个.m的实现类,有几个知识点要注意:
1).category中添加IBInspectable修饰属性,必须带有set和get的方法,不然编译都通过。
2).KVC观察属性值变化,从而得到即时刷新效果。
3).category中自定义属性如上边defineValue属性,使用runtime方式赋值。所以会有objc_setAssociatedObject(self, @selector(defineValue), @(defineValue),OBJC_ASSOCIATION_ASSIGN);这样的代码。_defineValue = defineValue;这样也是行,这样是有语法问题的。
详细的runtime和KVC知识点可以查看《谈Runtime机制和使用的整体化梳理》《谈KVC、KVO(重点观察者模式)机制编程》

4.在interface builder设置相关属性

1).属性栏可以看可设置圆角,边框宽度等


设置UIView(MGO定义出来属性)

2).Runtime Attribute栏中也能自动生成刚刚设置的属性值


Runtime Attribute显示属性值
5.查看storyboard上的头像有没有显示设置的属性值
UIView(MGO)展示的效果

Oh。。。my god!storyboard上一点效果也没显示出来,反而模拟器运行效果确实理想的状态。活生生的“现实很丰满,理想很骨感”表现得淋漓尽致。难道要硬着头皮瞬间退回到解放前,重复不断的写继承代码。。。打死也不,,,告诉你淘宝发过来的验证码!

六.曲线救国处理Category不显示效果问题

曲线救国生活中可以,国就是救那么一两次,没国了也没办法。程序中,每时每刻都在救国,明摆着这欺负人嘛!不过,国我们还是得救的,歌薛之谦还是要唱的,先找到两者的微妙关系,串成曲线才行。于是乎,薛之谦将段子手的头衔发挥到极致,参加各大综艺,《火星情报站》《极限挑战》《大学生来了》等等,趁机唱唱“丑八怪 呀啊呀啊哎呀”,道理就明了了,就是死活出现在人面前晃来晃去。
哟,那会不会interface builder死活要看到UIView的自定义子类的继承类,设置在Customer Class中才行啊。试试?

1.编写一个 空白MGOImageView继承UIImageView。
#import <UIKit/UIKit.h>
@interface MGOImageView : UIImageView
@end
2.MGOImageView.m文件什么也不干,就是等机会对接UIView(MGO)自定义属性。
#import "MGOImageView.h"
@implementation MGOImageView
@end
3.选中storyboard中的UIImageView在Customer Class选择 MGOImageView。
编写空白MGOImageView尝试

噢,,,了个天啊!storyboard上一点效果都没有少显示出来,反而吓到了现实中的我。那就趁热吃豆腐了,把其他控件都写一个对应空白的子类,设置在customer class上。


其他控件都添加对应的子类

好像幸福就是来得那么突然,伤心的小船说翻就翻了。会不会有更大幸福,于是乎,小明在google上搜索“IBDesignable/IBInspectable在Category中没有效果”。看了两三页搜索结果,最后比较接近的是Cocachina中也有一个没有人回复的相关帖子,和另外一篇跟我的发现一样要写一个空白的子类设置在Customer Class 中才行。

七.对比总结

经过以上一系列折腾,最后的结果确认令我觉得“不完美的IBDesignable/IBInspectable”。有些对XCode,Storyboard项目者有些一丁点的期待外,同时也是希望有开发者提供更好的处理方式。对比其他IDE,,就算了。追求完美我们是天生的,尽情开发我们也是认真的。

八.源码下载

https://github.com/minggo620/iOSDesignable.git
好想要到薛之谦的微信,向他发1毛钱的红包,然后他会一如既往地回“不好意思,我不收别人的微信红包”,接着我收到了200块红包。

【原创出品 未经授权 禁止转载】
【欢迎微友分享转发 禁止公号等未经授权的转载】

微信公众号:minggo_dev

相关文章

网友评论

  • TEASON:很好的解决了我的问题, 一个cls in cls 带着一个category . 一个文件解决
  • 对酒当歌的夜:看了一下午,总结出来的方法基本上也是你说的这样,(强迫症好不爽啊..)不过写一个空白的View也不是什么事都不做吧需要把IB_DESIGNABLE这个加到空白的View里面吧
    minggo:??
  • 汤建华:很适合
  • PlusNie:滴!老人卡!
    minggo:@NiePlus 好吧,上来
    minggo: @NiePlus 没看懂!
  • 這Er:Xcode一直indexing怎么解决? 都不能好好的写代码了 :sweat:
    minggo: @這Er 你是更新到7.3的Xcode?
    這Er:对,弄过这个以后一直indexing, 写代码不提示了。按照网上的方法关闭了在打开,xcode就又好使了:grin:, 还没腾出时间有再试试IB看看是不是它的毛病
    minggo:@這Er 你是说使用IBDesignable一直index?
  • 梦里风吹过:真的很不错,一直以为只有swift才支持可视化,找相关的代码又很少,直到发现这一篇,真的很赞.我最近使用storyboard比较多,有空希望可以交流下.我QQ923925522
  • loongod:直接把layer属性变现成可视化。赞,喜欢技术,更喜欢薛之谦。 :grin:
    minggo: @god_long 他确实是个才子!!
  • xxttw:你把薛之谦黑的一比
    minggo:@Unc1eWang 那叫欣赏
  • 9f36c4ad060b:同感。另外,博主思维好强大,信息随时切换跳跃!
    minggo:@WangLinHai 呵呵,谢谢支持
  • d696133f00e5:膜拜大神
    minggo:@SnowChen 谢谢支持,不是什么大神,我还差远呢
  • 611b9f8f5517:最后的对比,可以写出来,Xcode上确实有不如其他IDE地方。整体赞一个 :clap:
    minggo:@iOS编辑 不想变成吐槽性质,谢谢支持
  • ab3677c792df: :+1: 思路不错,建议减少些口语化。
    115a6027f65e:蛮好的,这是你的个人特色
    minggo:@唐人欣_Judy 嗯,好!接受
  • e73559e118ad:没多大留意IBDesignbale,mark。文章写的很乐,博主想象力挺丰富!
    minggo:@_LiYong 呵呵!!
  • c37e3f987f84: :+1: :+1: :pray:
    minggo:@图涨的空杯 谢谢支持
  • 869d429a7837:很接地气,赞!技术文章也可以这么写,授教了
    minggo:@JackJim 谢谢支持
  • 3381357d211c:才子遇才子!IB Designable其实很多开发者都不意会到的!习惯了现状!
    3381357d211c:@minggo 还是得靠你们啊
    minggo:@曾经的程序员 走出习惯,改变一点可能影响帮助很多开发者人!
    minggo:@曾经的程序员 谢谢夸奖!
  • 1dd718fdc2b3:哈哈,不错不错,一路看完!幽默,也让人思考,Xcode是应为做这事!
    1dd718fdc2b3:@minggo 向你学习,很适合讲课方式!
    minggo:@码车上 哈哈

本文标题:谈不完美的IBDesignable/IBInspectable可

本文链接:https://www.haomeiwen.com/subject/bzmmrttx.html