Expanding User-Defined Runtime Attributes in Xcode with Objective-C

When building a user interface, I appreciate an IDE that allows me to easily change visual elements without having to write code. Writing code for simple things like colors, borders, fonts, or shadows clutters my project. Fortunately, I work with talented designers at Atomic Object who can already use Xcode to make some of these aesthetic changes in the UI without needing to write extra code.

However, while these designers can currently make selective changes to some controls, not all of what they want to do is possible in the IDE. For instance, I cannot set a border or shadow on a UIView without writing code or change the font of a UISegmentedControl. I wish Xcode’s interface builder was more capable of changing simple properties as these.  

Fortunately, there is a feature of Xcode’s interface builder that will allow you to manually add user defined runtime attributes. You tell it the name of the property you want to change then specify the type of the property and finally the value.

Add runtime attributes

The user-defined runtime attributes feature limits the type of properties that can be changed to Boolean, NSNumber, NSString, CGPoint, CGSize, CGRect, NSRange, and UIColor. If the property you want to change has a different type, then you have to write code to modify the property.

This is the problem, for example, when setting the color on a border. The type of a layer’sborderColorproperty is CGColor, which is not one of the types allowed. With the help of an Objective-C category, you can get around this limitation and modify properties of different types.

The Objective-C Category that Makes It Possible

The first example I will show you is how to change the border and shadow color of any UIView. The runtime attribute feature allows us to set a UIColor type, which we need to translate to a CGColor type. To accomplish this, we need to extend theCALayerclass with a property that will translate the UIColor to the CGColor we need for the border and shadow.  

You can extend classes in Objective-C using a category. I added two properties calledborderIBColorandshadowIBColorthat are of type UIColor. The IB stands for interface builder. I have to give these properties a unique name to avoid name conflicts with the original properties called borderColor and shadowColor that are of the type CGColor.

CALayer+RuntimeAttribute.h

 
@import QuartzCore; @interface CALayer (IBConfiguration) @property(nonatomic, assign) UIColor* borderIBColor;@property(nonatomic, assign) UIColor* shadowIBColor; @end

CALayer+RuntimeAttribute.m

 
#import "CALayer+RuntimeAttribute.h" @implementation CALayer (IBConfiguration) -(void)setBorderIBColor:(UIColor*)color{	self.borderColor = color.CGColor;} -(UIColor*)borderIBColor{	return [UIColor colorWithCGColor:self.borderColor];} -(void)setShadowIBColor:(UIColor*)color{	self.shadowColor = color.CGColor;} -(UIColor*)shadowIBColor{	return [UIColor colorWithCGColor:self.shadowColor];} @end

The setters forborderIBColorandshadowIBColortake in the UIColor value and set the layer’s shadow and border color properties appropriately.  The iOS runtime will set the value based on what you have defined in the runtime attributes.

Sample UI

Here is a test UI that I put together to test our new runtime attributes. The gray rectangle is a UIView that we will add a border and shadow to. I also have a couple UISegmentedControls that we will customize later in this post.

initial view

Make sure the gray UIView is selected, and add the following runtime attributes:

Runtime attributes for border and shadow

Notice that we are using our new properties on UILayerborderIBColorandshadowIBColor. You can set these to any color value you want. I used black for the shadow and red for the border. I also set theborderWidth,shadowOpacity,shadowOffset, andcornerRadiusto give you an example of what other properties you can modify using the runtime attributes feature.  

Please note that you will not see any changes to the UI in interface builder when you change the value of a property in the runtime attributes. Your view will still look like a plain gray rectangle. These properties are set at runtime, so you have to run the simulator to see your changes at runtime.

You should see a view like this:

Change border and shadow

Change Segmented Control Font Family and Size

Next we will configure the font of a UISegmentedControl. I can change the tint color using a runtime attribute, but I can’t change the font size or font family. The title font is more complicated to set because you can have different text based on the selected state. We can use the same technique, using a category to extend UISegmented control, and change the font family and size with the runtime attributes and assume we are setting the title font for the normal state.

UISegmentedControl+RuntimeAttribute.h

 
@import UIKit; @interface UISegmentedControl (IBConfiguration) @property(nonatomic, assign) NSNumber *fontIBSize;@property(nonatomic, assign) NSString *fontIBName; @end

UISegmentedControl+RuntimeAttribute.m

 
#import "UISegmentedControl+RuntimeAttribute.h" @implementation UISegmentedControl (IBConfiguration) -(void)setFontIBName:(NSString*)name{	CGFloat cgSize = [self.fontIBSize floatValue];	[self setTitleTextAttributes:@{NSFontAttributeName:[UIFont fontWithName:name size:cgSize]} forState:UIControlStateNormal];} -(NSString *)fontIBName{	NSDictionary *attributes = [self titleTextAttributesForState:UIControlStateNormal];	UIFont *font = attributes[NSFontAttributeName];	return font.familyName;} -(void)setFontIBSize:(NSNumber *)size{	CGFloat cgSize = [size floatValue];	[self setTitleTextAttributes:@{NSFontAttributeName:[UIFont fontWithName:self.fontIBName size:cgSize]} forState:UIControlStateNormal];} -(NSNumber *)fontIBSize{	NSDictionary *attributes = [self titleTextAttributesForState:UIControlStateNormal];	UIFont *font = attributes[NSFontAttributeName];	return (font != nil) ? @(font.pointSize) : @15.0;} @end

Now select one of the segmented controls and add the following runtime attributes. You can select any color you want. If you want a list of possible font family names, you can go to iosfonts.com.

runtime attributes for segmentedcontrol

You should see a view like this:

Change font name and family segmentedcontrol

My example is a bit ugly, but you get the point. You can now change all of these properties without having to modify code. If you would like to try this code out yourself to see it in action, I havethe entire project on GitHub. Using the same technique, can you think of other customizations to change at runtime for other controls?

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值