实现思路
starGrame.png1、使用互相重叠的两套星星,将上面的一套星星添加到一个clipsToBounds = YES的容器视图V1中,改变容器视图的宽度可以达到显示亮星星的数量。
2、点击事件使用UITapGestureRecognizer添加到最底层的父视图,根据点击的locationInView:判断点击的位置,移动V1的宽度,同时可添加动画
主要代码
视图初始化代码
- (void)setUpNormalStars {//初始化灰色星星
NSMutableArray *array = [NSMutableArray array];
for (NSInteger index = 0; index < _totalStars; index ++) {
UIImageView *star = [[UIImageView alloc] initWithImage:_normalImage];
[self addSubview:star];
[array addObject:star];
}
_normalStars = array.copy;
}
- (void)setUpSelectedStars {//初始化亮星星,及其容器
_progressView = [[UIView alloc] initWithFrame:CGRectMake(0, (self.bounds.size.height - _starSize.height) / 2, [self progressWidth], _starSize.height)];
_progressView.backgroundColor = [UIColor clearColor];
//裁切属性,实现星星数量的展示
_progressView.clipsToBounds = YES;
[self addSubview:_progressView];
NSMutableArray *array = [NSMutableArray array];
for (NSInteger index = 0; index < _totalStars; index ++) {
UIImageView *star = [[UIImageView alloc] initWithImage:_selectedImage];
[_progressView addSubview:star];
[array addObject:star];
}
_selectedStars = array.copy;
}
设置得分
- (void)setCurrentScores:(CGFloat)currentScores {//星星显示逻辑
_currentScores = [self translateScore:currentScores];
if (_progressView) {
[UIView animateWithDuration:(_hasAnimation ? 0.2 : 0) animations:^{
_progressView.frame = CGRectMake(0, (self.bounds.size.height - _starSize.height) / 2, [self progressWidth], _starSize.height);
}];
}
}
- (CGFloat )translateScore:(CGFloat )score {//将分数转化为符合当前显示模式的分数
if (score < 0) {
return 0;
}
if (score > _totalStars) {
return _totalStars;
}
if (self.style == ZJRateStarStyleTotalOnly) {//只显示整数
return ceil(score);
}
else if (self.style == ZJRateStarStyleAllowHalf) {//精确为0.5
return ceil(score * 2) / 2.0;
}
else if (self.style == ZJRateStarStyleAllowFloat) {//精确为0.1
return ceil(score * 10) / 10.0;
}
return score;
}
- (CGFloat )progressWidth { //得分显示容器的计算宽度
CGFloat score = [self translateScore:_currentScores];
NSInteger total = floor(score);
CGFloat more = score - total;
return total * (_paddingWidth + _starSize.width) + more * _starSize.width;
}
点击事件
- (void)tapGestureDidTap:(UITapGestureRecognizer *)tap {
if (!_allowRate) {//不允许点击事件,只显示
return;
}
CGFloat tapOffsetX = [tap locationInView:self].x;
NSInteger totalSores = floor(tapOffsetX / (_starSize.width + _paddingWidth));
CGFloat more = tapOffsetX - totalSores * (_starSize.width + _paddingWidth);
if (more > _starSize.width) {//点击空白间隔处
return;
}
//调用上面的得分方法实现打分
self.currentScores = [self translateScore:totalSores + more / _starSize.width];
//todo: 代理事件
}
demo地址
github地址
以下为可自定义属性 可使用autolayout布局
//星星总数
@property (nonatomic, assign) NSInteger totalStars;
//显示星星的类型 整星,半星,小数星
@property (nonatomic, assign) ZJRateStarStyle style;
//当前得分
@property (nonatomic, assign) CGFloat currentScores;
//星星的大小
@property (nonatomic, assign) CGSize starSize;
//星星的间隔
@property (nonatomic, assign) CGFloat paddingWidth;
//两种状态星星的图片
@property (nonatomic, strong) UIImage *normalImage;
@property (nonatomic, strong) UIImage *selectedImage;
//是否允许点击事件进行评分
@property (nonatomic, assign) BOOL allowRate;
//是否需要动画
@property (nonatomic, assign) BOOL hasAnimation;
网友评论