В настоящее время я реализую движок стилей в стиле CSS для собственных элементов управления моего приложения iOS, чтобы избежать считывания целой пачки свойств стилей из plist и применения каждого из них к каждому элементу управления.
(Изменить: нет, Я не хочу UIWebView , мне нужно настроить собственные элементы управления. Я не хочу достигать чистого CSS, просто что-то, что выглядит как CSS и работаетс простотой CSS.)
Скажем, у меня составлен список, подобный следующему:
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])
).