我正在为我的iOS应用程序的本机控件实现类似CSS的样式引擎,以避免从plist中读取一大堆样式属性并在每个控件上应用每一个.
(编辑:不,我不想要UIWebView,我需要自定义本机控件.我不想实现纯CSS,只是看起来像CSS的东西,并使用简单的CSS.)
说我有一个像这样结构的plist:
closeButtonStyle = "background:transparent;font:Georgia/14;textColor:#faa" titleLabelStyle = "background:transparent;font:Helvetica/12;textAlignment:left"
你可以很容易想象我在这里填充了什么样的属性.
到目前为止,一切正常,我有一个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
- 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
这是最好的方式吗?特别是,我希望您对代码的扫描部分(while (![scanner isAtEnd])
循环)有所了解.