星星评分定制
有响应的星星.zip
无响应的星星进度条.zip
代码分析
#import <UIKit/UIKit.h>
@class CWStarRateView; //引用星星比例view
@protocol CWStarRateViewDelegate <NSObject> //创建代理
@optional
//当比例真正改变时向外提供新的百分比
- (void)starRateView:(CWStarRateView *)starRateView scroePercentDidChange:(CGFloat)newScorePercent;
@end
@interface CWStarRateView : UIView
@property (nonatomic, assign) CGFloat scorePercent;//得分值,范围为0--1,默认为1
@property (nonatomic, assign) BOOL hasAnimation;//是否允许动画,默认为NO
@property (nonatomic, assign) BOOL allowIncompleteStar;//评分时是否允许不是整星,默认为NO
@property (nonatomic, weak) id<CWStarRateViewDelegate>delegate;
- (instancetype)initWithFrame:(CGRect)frame numberOfStars:(NSInteger)numberOfStars;
@end
#import "CWStarRateView.h"
#define FOREGROUND_STAR_IMAGE_NAME @"raise03_star_gr.png" //绿色星星
#define BACKGROUND_STAR_IMAGE_NAME @"raise03_star_whi.png" //白色星星
#define DEFALUT_STAR_NUMBER 5 //默认5个星星
#define ANIMATION_TIME_INTERVAL 0.2 //动画间隔0.2
@interface CWStarRateView ()
@property (nonatomic, strong) UIView *foregroundStarView; //前方的view
@property (nonatomic, strong) UIView *backgroundStarView; //后方的view
@property (nonatomic, assign) NSInteger numberOfStars; //星星的个数
@end
@implementation CWStarRateView
#pragma mark 重新init提醒只能用initWithFrame
- (instancetype)init {
NSAssert(NO, @"You should never call this method in this class. Use initWithFrame: instead!");
return nil;
}
#pragma mark 重写initWithFrame
- (instancetype)initWithFrame:(CGRect)frame {
return [self initWithFrame:frame numberOfStars:DEFALUT_STAR_NUMBER];
}
#pragma mark 初始化编码器
- (instancetype)initWithCoder:(NSCoder *)aDecoder {
if (self = [super initWithCoder:aDecoder]) {
// 将星星数量赋值给变量_numberOfStars
_numberOfStars = DEFALUT_STAR_NUMBER;
[self buildDataAndUI];
}
return self;
}
#pragma mark 向外提供接口
- (instancetype)initWithFrame:(CGRect)frame numberOfStars:(NSInteger)numberOfStars {
if (self = [super initWithFrame:frame]) {
_numberOfStars = numberOfStars;
[self buildDataAndUI];
}
return self;
}
#pragma mark - Private Methods
- (void)buildDataAndUI {
_scorePercent = 1;//百分比默认为1
_hasAnimation = NO;//默认为NO没有动画
_allowIncompleteStar = NO;//默认为NO默认不允许有不完整的星星
// 对前面的星星进行赋值
self.foregroundStarView = [self createStarViewWithImage:FOREGROUND_STAR_IMAGE_NAME];
// 对后面的星星进行赋值
self.backgroundStarView = [self createStarViewWithImage:BACKGROUND_STAR_IMAGE_NAME];
[self addSubview:self.backgroundStarView];
[self addSubview:self.foregroundStarView];
// 添加点击手势
UITapGestureRecognizer *tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(userTapRateView:)];
tapGesture.numberOfTapsRequired = 1;
[self addGestureRecognizer:tapGesture];
}
#pragma mark 点击手势触发事件
- (void)userTapRateView:(UITapGestureRecognizer *)gesture {
CGPoint tapPoint = [gesture locationInView:self]; //获取手势点击的点
CGFloat offset = tapPoint.x; //获取手势偏移量
CGFloat realStarScore = offset / (self.bounds.size.width / self.numberOfStars); //获取这个偏移量占星星宽度的比例
CGFloat starScore = self.allowIncompleteStar ? realStarScore : ceilf(realStarScore); //如果允许使用不完整星星,则用realStarScore数据,否则用ceilf(realStarScore)
self.scorePercent = starScore / self.numberOfStars; //星星百分比 = 偏移量 / 星星数
}
#pragma mark 开始创建星星图片
- (UIView *)createStarViewWithImage:(NSString *)imageName {
UIView *view = [[UIView alloc] initWithFrame:self.bounds];
// 当返回yes时对边界进行修剪,返回no时不对边界修剪
view.clipsToBounds = YES;
view.backgroundColor = [UIColor clearColor];
// 根据星星的个数用for循环创建星星
for (NSInteger i = 0; i < self.numberOfStars; i ++)
{
UIImageView *imageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:imageName]];
imageView.frame = CGRectMake(i * self.bounds.size.width / self.numberOfStars, 0, self.bounds.size.width / self.numberOfStars, self.bounds.size.height);
// 内部图片适应imageView比例
imageView.contentMode = UIViewContentModeScaleAspectFit;
[view addSubview:imageView];
}
return view;
}
#pragma mark
- (void)layoutSubviews {
[super layoutSubviews];
__weak CWStarRateView *weakSelf = self; //方法中弱引用自己
CGFloat animationTimeInterval = self.hasAnimation ? ANIMATION_TIME_INTERVAL : 0; //如果设置了动画间隔时间久用,如果没有设置就默认为0
[UIView animateWithDuration:animationTimeInterval animations:^{
// 为前面的星星view添加动画效果
weakSelf.foregroundStarView.frame = CGRectMake(0, 0, weakSelf.bounds.size.width * weakSelf.scorePercent, weakSelf.bounds.size.height);
}];
}
#pragma mark
- (void)setScorePercent:(CGFloat)scroePercent {
/**
如果传过来的百分比与变量数值相等,则直接返回,
如果传过来的百分比<0,则直接对变量_scorePercent赋0
如果传过来的百分比>1,则对变量赋1
如果传过来的百分比在0和1之间,则对变量进行赋值
*/
if (_scorePercent == scroePercent) {
return;
}
if (scroePercent < 0) {
_scorePercent = 0;
} else if (scroePercent > 1) {
_scorePercent = 1;
} else {
_scorePercent = scroePercent;
}
#pragma mark 当代理响应了代理方法,则将参数scroePercent通过代理方法直接传过去
if ([self.delegate respondsToSelector:@selector(starRateView:scroePercentDidChange:)]) {
[self.delegate starRateView:self scroePercentDidChange:scroePercent];
}
[self setNeedsLayout];
}
@end