Cyr*_*lle 7 cocoa-touch objective-c styling ios
我正在为我的iOS应用程序的本机控件实现类似CSS的样式引擎,以避免从plist中读取一大堆样式属性并在每个控件上应用每一个.
(编辑:不,我不想要UIWebView,我需要自定义本机控件.我不想实现纯CSS,只是看起来像CSS的东西,并使用简单的CSS.)
说我有一个像这样结构的plist:
closeButtonStyle = "background:transparent;font:Georgia/14;textColor:#faa"
titleLabelStyle = "background:transparent;font:Helvetica/12;textAlignment:left"
Run Code Online (Sandbox Code Playgroud)
你可以很容易想象我在这里填充了什么样的属性.
到目前为止,一切正常,我有一个UIStyle类解析这样的声明并将所有找到的值存储在其ivars中; 我也有类别UIView,UILabel,UIButton,...只申报一个-(void)setStyle:(UIStyle *)style方法.仅当定义了样式变量时,此方法才应用样式变量.
正如我所说,一切正常.
我唯一的问题是关于样式字符串的解析.我选择使用NSScanner,但我不确定它是否是最佳选择,并希望得到您的意见.
为了记录,这是我实现我的方式UIStyle:
- UIStyle.h
typedef struct {
BOOL frame:1;
BOOL font:1;
BOOL textColor:1;
BOOL backgroundColor:1;
BOOL shadowColor:1;
BOOL shadowOffset:1;
BOOL textAlignment:1;
BOOL titleEdgeInsets:1;
BOOL numberOfLines:1;
BOOL lineBreakMode:1;
} UIStyleFlags;
@interface UIStyle: NSObject {
UIStyleFlags _has;
CGRect _frame;
UIFont *_font;
UIColor *_textColor;
UIColor *_backgroundColor;
UIColor *_shadowColor;
CGSize _shadowOffset;
UITextAlignment _textAlignment;
UIEdgeInsets _titleEdgeInsets;
NSInteger _numberOfLines;
UILineBreakMode _lineBreakMode;
}
@property (readonly, nonatomic) UIStyleFlags has;
@property (readonly, nonatomic) CGRect frame;
@property (readonly, nonatomic) UIFont *font;
@property (readonly, nonatomic) UIColor *textColor;
@property (readonly, nonatomic) UIColor *backgroundColor;
@property (readonly, nonatomic) UIColor *shadowColor;
@property (readonly, nonatomic) CGSize shadowOffset;
@property (readonly, nonatomic) UITextAlignment textAlignment;
@property (readonly, nonatomic) UIEdgeInsets titleEdgeInsets;
@property (readonly, nonatomic) NSInteger numberOfLines;
@property (readonly, nonatomic) UILineBreakMode lineBreakMode;
- (id)initWithString:(NSString *)string;
+ (id)styleWithString:(NSString *)string;
+ (id)styleInDict:(NSDictionary *)dict key:(NSString *)key;
@end
@interface UIView (UIStyle)
- (void)setStyle:(UIStyle *)style;
@end
@interface UILabel (UIStyle)
- (void)setStyle:(UIStyle *)style;
@end
@interface UIButton (UIStyle)
- (void)setStyle:(UIStyle *)style;
@end
Run Code Online (Sandbox Code Playgroud)
- UIStyle.m
#import "UIStyle.h"
@implementation UIStyle
@synthesize has = _has;
@synthesize frame = _frame;
@synthesize font = _font;
@synthesize textColor = _textColor;
@synthesize backgroundColor = _backgroundColor;
@synthesize shadowColor = _shadowColor;
@synthesize shadowOffset = _shadowOffset;
@synthesize textAlignment = _textAlignment;
@synthesize titleEdgeInsets = _titleEdgeInsets;
@synthesize numberOfLines = _numberOfLines;
@synthesize lineBreakMode = _lineBreakMode;
- (id)initWithString:(NSString *)string {
if ((self = [super init])) {
_has.frame = NO;
_has.font = NO;
_has.textColor = NO;
_has.backgroundColor = NO;
_has.shadowColor = NO;
_has.shadowOffset = NO;
_has.textAlignment = NO;
_has.titleEdgeInsets = NO;
_has.numberOfLines = NO;
_has.lineBreakMode = NO;
_frame = CGRectZero;
_font = nil;
_textColor = nil;
_backgroundColor = nil;
_shadowColor = nil;
_shadowOffset = CGSizeZero;
_textAlignment = UITextAlignmentLeft;
_titleEdgeInsets = UIEdgeInsetsZero;
_numberOfLines = 1;
_lineBreakMode = UILineBreakModeClip;
NSScanner *scanner = [[NSScanner alloc] initWithString:string];
NSMutableDictionary *dict = [[NSMutableDictionary alloc] init];
NSCharacterSet *keyEndSet = [NSCharacterSet characterSetWithCharactersInString:@":"];
NSCharacterSet *valueEndSet = [NSCharacterSet characterSetWithCharactersInString:@";"];
while (![scanner isAtEnd]) {
NSString *key;
NSString *value;
[scanner scanUpToCharactersFromSet:keyEndSet intoString:&key];
[scanner scanCharactersFromSet:keyEndSet intoString:NULL];
[scanner scanUpToCharactersFromSet:valueEndSet intoString:&value];
[scanner scanCharactersFromSet:valueEndSet intoString:NULL];
[dict setValue:value forKey:key];
}
[scanner release];
for (NSString *key in dict) {
NSString *value = (NSString *)[dict objectForKey:key];
if ([key isEqualToString:@"frame"]) {
_frame = CGRectFromString(value);
_has.frame = YES;
}
else if ([key isEqualToString:@"font"]) {
NSArray *font = [value componentsSeparatedByString:@"/"];
NSString *fontName = (NSString *)[font objectAtIndex:0];
CGFloat fontSize = (CGFloat)[(NSString *)[font objectAtIndex:1] floatValue];
_font = [[UIFont fontWithName:fontName size:fontSize] retain];
_has.font = YES;
}
else if ([key isEqualToString:@"textColor"]) {
_textColor = [[UIColor colorWithString:value] retain];
_has.textColor = YES;
}
else if ([key isEqualToString:@"backgroundColor"]) {
_backgroundColor = [[UIColor colorWithString:value] retain];
}
else if ([key isEqualToString:@"shadow"]) {
NSArray *shadow = [value componentsSeparatedByString:@"/"];
_shadowColor = [[UIColor colorWithString:(NSString *)[shadow objectAtIndex:0]] retain];
_shadowOffset = CGSizeMake((CGFloat)[(NSString *)[shadow objectAtIndex:1] floatValue], (CGFloat)[(NSString *)[shadow objectAtIndex:2] floatValue]);
_has.shadowColor = YES;
_has.shadowOffset = YES;
}
else if ([key isEqualToString:@"textAlignment"]) {
if ([value isEqualToString:@"center"]) {
_textAlignment = UITextAlignmentCenter;
}
else if ([value isEqualToString:@"right"]) {
_textAlignment = UITextAlignmentRight;
}
else {
_textAlignment = UITextAlignmentLeft;
}
_has.textAlignment = YES;
}
else if ([key isEqualToString:@"titleEdgeInsets"]) {
_titleEdgeInsets = UIEdgeInsetsFromString(value);
_has.titleEdgeInsets = YES;
}
else if ([key isEqualToString:@"numberOfLines"]) {
_numberOfLines = (NSInteger)[value integerValue];
_has.numberOfLines = YES;
}
else if ([key isEqualToString:@"lineBreakMode"]) {
if ([value isEqualToString:@"character"]) {
_lineBreakMode = UILineBreakModeCharacterWrap;
}
else if ([value isEqualToString:@"clip"]) {
_lineBreakMode = UILineBreakModeClip;
}
else if ([value isEqualToString:@"head"]) {
_lineBreakMode = UILineBreakModeHeadTruncation;
}
else if ([value isEqualToString:@"tail"]) {
_lineBreakMode = UILineBreakModeTailTruncation;
}
else if ([value isEqualToString:@"middle"]) {
_lineBreakMode = UILineBreakModeMiddleTruncation;
}
else {
_lineBreakMode = UILineBreakModeWordWrap;
}
_has.lineBreakMode = YES;
}
}
[dict release];
}
return self;
}
- (void)dealloc {
[_font release];
[_textColor release];
[_backgroundColor release];
[_shadowColor release];
[super dealloc];
}
+ (id)styleWithString:(NSString *)string {
return [[[UIStyle alloc] initWithString:string] autorelease];
}
+ (id)styleInDict:(NSDictionary *)dict key:(NSString *)key {
return [[[UIStyle alloc] initWithString:(NSString *)[dict objectForKey:key]] autorelease];
}
@end
@implementation UIView (UIStyle)
- (void)setStyle:(UIStyle *)style {
if (style.has.frame) {
[self setFrame:style.frame];
}
if (style.has.backgroundColor) {
[self setBackgroundColor:style.backgroundColor];
}
}
@end
@implementation UILabel (UIStyle)
- (void)setStyle:(UIStyle *)style {
[super setStyle:style];
if (style.has.font)
[self setFont:style.font];
if (style.has.textColor)
[self setTextColor:style.textColor];
if (style.has.shadowColor)
[self setShadowColor:style.shadowColor];
if (style.has.shadowOffset)
[self setShadowOffset:style.shadowOffset];
if (style.has.textAlignment)
[self setTextAlignment:style.textAlignment];
if (style.has.numberOfLines)
[self setNumberOfLines:style.numberOfLines];
if (style.has.lineBreakMode)
[self setLineBreakMode:style.lineBreakMode];
}
@end
@implementation UIButton (UIStyle)
- (void)setStyle:(UIStyle *)style {
[super setStyle:style];
if (style.has.titleEdgeInsets)
[self setTitleEdgeInsets:style.titleEdgeInsets];
}
@end
Run Code Online (Sandbox Code Playgroud)
这是最好的方式吗?特别是,我希望您对代码的扫描部分(while (![scanner isAtEnd])循环)有所了解.