iPhone开发当中处于需求经常需要一些自定义控件。当然,处于成本和质量的考虑,请优先选择系统控件。当真正需要开发自定义控件的时候,通常又会有两种选择:重绘或者组合。重绘就是重写控件的绘制函数,在该函数中绘制期望的效果。而组合就是通过不同控件的搭配形成满足需求的控件。当然,根据自定义控件需求的不一样,有的适合用重绘,有的则是适合用组合,有时则是两种实现都适用。比如星级控件是项目中比较经常用到的但是系统没有提供的一种控件。对于这个一个控件我们又是要如何选择呢?

5-Star Rating System

 

 

为此我们就不惜血本一下,决定用两种方法实现看看:

重绘实现:

@interface StarRating:UIView{   
    int numberStars;   
    int rating;
}
@property int numberStars;
@property int rating;

- (id)initWithNumberOfStars:(int)numStars;
- (id)initWithNumberOfStars:(int)numStars initialRating:(int)initialRating;

@end

@implementation StarRating

- (void)drawRect:(CGRect)rect {   
    UIImage *onImage = [UIImage p_w_picpathNamed:@"on.png"];   
    UIImage *offImage = [UIImage p_w_picpathNamed:@"off.png"];   
    for (int i=1; i<=[self numberStars]; i++)    {       
        UIImage *img = (i <= [self rating]) ? onImage : offImage;       
        CGPoint p_w_picpathPoint;       
        p_w_picpathPoint.x = BTN_WIDTH * (i-1);       
        p_w_picpathPoint.y = 0.0f;       
        [img drawAtPoint:p_w_picpathPoint];   
    }
}
@end其中描绘部分是根据星级rating进行图片选择,星级以下的用on.png,星级以上的off.png。 组合实现:

@interface StarRating: UIControl {
    NSMutableArray            *starArray;
    NSInteger                     numberStars;
    NSInteger                     rating;
}

-(id)initWithFrame:(CGRect)frame andStars:(NSInteger)inNumStars;

@end

@implementation StarRating

-(id)initWithFrame:(CGRect)frame andStars:(int)inNumStars {  
    if (self = [super initWithFrame:frame])   
    {       
        approxMode = InterpolationMode_Half;       
        starNum = inNumStars;      
        [self prepareStars:starNum frame:frame];   
    }  
    return self;
}

-(void)setRating:(int)aRating{  
    rating= aRating;  
    [self fillStars];
}

- (void) prepareStars: (int)aStarNum frame: (CGRect)frame {
    starArray = [[NSMutableArray alloc] initWithCapacity:aStarNum];
    float width = frame.size.width/aStarNum;
    float height = frame.size.height;
    for(int i=0; i < aStarNum; i++) {
        UIImageView * star = [[UIImageView alloc] initWithFrame:CGRectMake(0+(i*width), 0, width, height)];
        [starArray addObject:star];
        [self addSubview:star];
        [star release];
    }
}

- (void)fillStars{   
    UIImage *onImage = [UIImage p_w_picpathNamed:@"on.png"];   
    UIImage *offImage = [UIImage p_w_picpathNamed:@"off.png"];   
    for (int i=1; i<=[self numberStars]; i++)    {          
       UIImage *img = (i <= [self rating]) ? onImage : offImage;  
       UIImageView *star = (UIImageView *)[self subViewAtIndex:i];
    [star setImage:img];
    }

其中是预先创建五个UIImageView的子控件,然后根据星级rating进行子控件的图片属性设定。 

 

对比:

1 重绘方案只有自身一个控件,而组合实现则是包含五个子控件。资源和效率上重绘的方案会比较有优势。

2 重绘需要处理描绘,而组合则是由子控件负责描绘。因此从描绘处理上,组合方案比较简单

3 需求变更时,重绘方案可能需要修改描绘代码,而组合方案在设计合理的情况下是可以轻松替换子控件的类型。