第一种:
view.h:
//
// XHStarRateView.h
// XHStarRateView
//
// Created by 江欣华 on 16/4/1.
// Copyright © 2016年 jxh. All rights reserved.
//
#import <UIKit/UIKit.h>
@class XHStarRateView;
typedef void(^finishBlock)(CGFloat currentScore);
typedef NS_ENUM(NSInteger, RateStyle)
{
WholeStar = 0, //只能整星评论
HalfStar = 1, //允许半星评论
IncompleteStar = 2 //允许不完整星评论
};
@protocol XHStarRateViewDelegate <NSObject>
-(void)starRateView:(XHStarRateView *)starRateView currentScore:(CGFloat)currentScore;
@end
@interface XHStarRateView : UIView
@property (nonatomic,assign)BOOL isAnimation; //是否动画显示,默认NO
@property (nonatomic,assign)RateStyle rateStyle; //评分样式 默认是WholeStar
@property (nonatomic, weak) id<XHStarRateViewDelegate>delegate;
-(instancetype)initWithFrame:(CGRect)frame;
-(instancetype)initWithFrame:(CGRect)frame withCurrentScore:(NSInteger)currentScore;
-(instancetype)initWithFrame:(CGRect)frame numberOfStars:(NSInteger)numberOfStars rateStyle:(RateStyle)rateStyle isAnination:(BOOL)isAnimation delegate:(id)delegate;
-(instancetype)initWithFrame:(CGRect)frame finish:(finishBlock)finish;
-(instancetype)initWithFrame:(CGRect)frame numberOfStars:(NSInteger)numberOfStars rateStyle:(RateStyle)rateStyle isAnination:(BOOL)isAnimation finish:(finishBlock)finish;
@end
view.m:
//
// XHStarRateView.m
// XHStarRateView
//
// Created by 江欣华 on 16/4/1.
// Copyright © 2016年 jxh. All rights reserved.
//
#import "XHStarRateView.h"
#define ForegroundStarImage @"star"
#define BackgroundStarImage @"unstar"
typedef void(^completeBlock)(CGFloat currentScore);
@interface XHStarRateView()
@property (nonatomic, strong) UIView *foregroundStarView;
@property (nonatomic, strong) UIView *backgroundStarView;
@property (nonatomic, assign) NSInteger numberOfStars;
@property (nonatomic,assign)CGFloat currentScore; // 当前评分:0-5 默认0
@property (nonatomic,strong)completeBlock complete;
@end
@implementation XHStarRateView
#pragma mark - 代理方式
-(instancetype)initWithFrame:(CGRect)frame{
if (self = [super initWithFrame:frame]) {
_numberOfStars = 5;
_rateStyle = WholeStar;
[self createStarView];
}
return self;
}
-(instancetype)initWithFrame:(CGRect)frame withCurrentScore:(NSInteger)currentScore{
if (self = [super initWithFrame:frame]) {
_numberOfStars = 5;
_currentScore = currentScore;
_rateStyle = WholeStar;
[self createStarViewWithCurrentScore];
}
return self;
}
-(instancetype)initWithFrame:(CGRect)frame numberOfStars:(NSInteger)numberOfStars rateStyle:(RateStyle)rateStyle isAnination:(BOOL)isAnimation delegate:(id)delegate{
if (self = [super initWithFrame:frame]) {
_numberOfStars = numberOfStars;
_rateStyle = rateStyle;
_isAnimation = isAnimation;
_delegate = delegate;
[self createStarView];
}
return self;
}
#pragma mark - block方式
-(instancetype)initWithFrame:(CGRect)frame finish:(finishBlock)finish{
if (self = [super initWithFrame:frame]) {
_numberOfStars = 5;
_rateStyle = WholeStar;
_complete = ^(CGFloat currentScore){
finish(currentScore);
};
[self createStarView];
}
return self;
}
-(instancetype)initWithFrame:(CGRect)frame numberOfStars:(NSInteger)numberOfStars rateStyle:(RateStyle)rateStyle isAnination:(BOOL)isAnimation finish:(finishBlock)finish{
if (self = [super initWithFrame:frame]) {
_numberOfStars = numberOfStars;
_rateStyle = rateStyle;
_isAnimation = isAnimation;
_complete = ^(CGFloat currentScore){
finish(currentScore);
};
[self createStarView];
}
return self;
}
#pragma mark - private Method
-(void)createStarView{
self.foregroundStarView = [self createStarViewWithImage:ForegroundStarImage];
self.backgroundStarView = [self createStarViewWithImage:BackgroundStarImage];
self.foregroundStarView.frame = CGRectMake(0, 0, self.bounds.size.width*_currentScore/self.numberOfStars, self.bounds.size.height);
[self addSubview:self.backgroundStarView];
[self addSubview:self.foregroundStarView];
UITapGestureRecognizer *tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(userTapRateView:)];
tapGesture.numberOfTapsRequired = 1;
[self addGestureRecognizer:tapGesture];
}
-(void)createStarViewWithCurrentScore{
self.foregroundStarView = [self createStarViewWithImage:ForegroundStarImage];
self.backgroundStarView = [self createStarViewWithImage:BackgroundStarImage];
self.foregroundStarView.frame = CGRectMake(0, 0, self.bounds.size.width*_currentScore/self.numberOfStars, self.bounds.size.height);
[self addSubview:self.backgroundStarView];
[self addSubview:self.foregroundStarView];
}
- (UIView *)createStarViewWithImage:(NSString *)imageName {
UIView *view = [[UIView alloc] initWithFrame:self.bounds];
view.clipsToBounds = YES;
view.backgroundColor = [UIColor clearColor];
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.contentMode = UIViewContentModeScaleAspectFit;
[view addSubview:imageView];
}
return view;
}
- (void)userTapRateView:(UITapGestureRecognizer *)gesture {
CGPoint tapPoint = [gesture locationInView:self];
CGFloat offset = tapPoint.x;
CGFloat realStarScore = offset / (self.bounds.size.width / self.numberOfStars);
switch (_rateStyle) {
case WholeStar:
{
self.currentScore = ceilf(realStarScore);
break;
}
case HalfStar:
self.currentScore = roundf(realStarScore)>realStarScore ? ceilf(realStarScore):(ceilf(realStarScore)-0.5);
break;
case IncompleteStar:
self.currentScore = realStarScore;
break;
default:
break;
}
}
- (void)layoutSubviews {
[super layoutSubviews];
__weak XHStarRateView *weakSelf = self;
CGFloat animationTimeInterval = self.isAnimation ? 0.2 : 0;
[UIView animateWithDuration:animationTimeInterval animations:^{
weakSelf.foregroundStarView.frame = CGRectMake(0, 0, weakSelf.bounds.size.width * weakSelf.currentScore/self.numberOfStars, weakSelf.bounds.size.height);
}];
}
-(void)setCurrentScore:(CGFloat)currentScore {
if (_currentScore == currentScore) {
return;
}
if (currentScore < 0) {
_currentScore = 0;
} else if (currentScore > _numberOfStars) {
_currentScore = _numberOfStars;
} else {
_currentScore = currentScore;
}
if ([self.delegate respondsToSelector:@selector(starRateView:currentScore:)]) {
[self.delegate starRateView:self currentScore:_currentScore];
}
if (self.complete) {
_complete(_currentScore);
}
[self setNeedsLayout];
}
@end
第二种:
//
// TTStarEvaluationView.h
// OCTest
//
// Created by rollingstoneW on 2018/9/7.
// Copyright © 2018年 zyb. All rights reserved.
//
#import <UIKit/UIKit.h>
@interface TTStarEvaluationView : UIView
@property (nonatomic, strong, nullable) UIImage *starImage; // 星星图片,默认为21*21的星星图片
@property (nonatomic, strong, nullable) UIImage *starImageForHalf; // 半星图片
@property (nonatomic, strong, nullable) UIImage *unstarImage; // 未选的星星图片
/**
在unstarImage为空的时候才会起作用,自动绘制选中和未选中的星星
*/
@property (nonatomic, strong, nullable) UIColor *starColor; // 星星颜色,默认为黄色
@property (nonatomic, strong, nullable) UIColor *unstarColor; // 未选的星星颜色,默认为浅灰色
@property (nonatomic, assign) CGFloat starSpace; // 间距 默认为图片宽度的一半
@property (nonatomic, assign) CGFloat horiInset; // 前后缩进,默认为10,建议不要设置为0,否则满星和0星不容易选中
@property (nonatomic, assign) NSInteger numberOfStars; // 星星数量,默认为5
@property (nonatomic, assign) NSInteger scorePerStar; // 一个星星代表的分数,默认为1
@property (nonatomic, assign) CGFloat currentScore; // 当前分数
@property (nonatomic, assign) CGFloat scoreMinPace; // 分数的最小刻度,默认,有半星图片时为半星分数,否则为1星分数,取值范围0.1-0.5,整数
@property (nonatomic, assign) BOOL canBeZero; // 是否可以选中0星,默认YES
@property (nonatomic, strong, nullable) void(^didEvaluateBlock)(CGFloat score); // 选中星星后的回调
@end
//
// TTStarEvaluationView.m
// OCTest
//
// Created by rollingstoneW on 2018/9/7.
// Copyright © 2018年 zyb. All rights reserved.
//
#import "TTStarEvaluationView.h"
static NSString *const DefaultStarImageBase64 = @"aaaaaaaa";
@implementation TTStarEvaluationView
@synthesize scoreMinPace = _scoreMinPace;
@synthesize starSpace = _starSpace;
- (instancetype)initWithFrame:(CGRect)frame {
if (self = [super initWithFrame:frame]) {
[self commonInit];
}
return self;
}
- (instancetype)initWithCoder:(NSCoder *)aDecoder {
if (self = [super initWithCoder:aDecoder]) {
[self commonInit];
}
return self;
}
- (void)commonInit {
NSData *imageData = [[NSData alloc] initWithBase64EncodedString:DefaultStarImageBase64 options:NSDataBase64DecodingIgnoreUnknownCharacters];
self.starImage = [UIImage imageWithData:imageData scale:3];
self.backgroundColor = [UIColor clearColor];
self.starColor = [UIColor orangeColor];
self.unstarColor = [UIColor lightGrayColor];
self.numberOfStars = 5;
self.scorePerStar = 1;
self.starSpace = -1;
self.horiInset = 10;
self.canBeZero = YES;
}
#define RedrawWithVar(var, ...) if (_##var != var) { \
_##var = var; \
{__VA_ARGS__; }\
[self setNeedsDisplay]; \
}
- (void)setStarImage:(UIImage *)starImage {
RedrawWithVar(starImage, [self sizeToFit]);
}
- (void)setStarImageForHalf:(UIImage *)starImageForHalf {
RedrawWithVar(starImageForHalf);
}
- (void)setUnstarImage:(UIImage *)unstarImage {
RedrawWithVar(unstarImage);
}
- (void)setStarSpace:(CGFloat)starSpace {
RedrawWithVar(starSpace, [self sizeToFit]);
}
- (void)setHoriInset:(CGFloat)horiInset {
RedrawWithVar(horiInset);
}
- (void)setNumberOfStars:(NSInteger)numberOfStars {
RedrawWithVar(numberOfStars, [self sizeToFit]);
}
- (void)setCurrentScore:(CGFloat)currentScore {
currentScore = floorf(MIN(currentScore, self.numberOfStars) / self.scoreMinPace) * self.scoreMinPace;
if (!self.canBeZero) {
currentScore = MAX(currentScore, self.scoreMinPace);
}
RedrawWithVar(currentScore);
}
- (void)setScoreMinPace:(CGFloat)scoreMinPace {
if (scoreMinPace >= 1) {
scoreMinPace = floor(scoreMinPace);
} else {
scoreMinPace = MIN(MAX(0.1, scoreMinPace), 0.5);
}
if (_scoreMinPace != scoreMinPace) {
_scoreMinPace = scoreMinPace;
[self setCurrentScore:self.currentScore];
}
}
#undef SetPropertyAndSizeToFit
- (CGSize)intrinsicContentSize {
return [self sizeThatFits:CGSizeZero];
}
- (void)sizeToFit {
self.bounds = (CGRect){CGPointZero, [self sizeThatFits:CGSizeZero]};
}
- (CGSize)sizeThatFits:(CGSize)size {
return CGSizeMake(self.starImage.size.width * self.numberOfStars + MAX(self.numberOfStars - 1, 0) * self.starSpace + self.horiInset * 2,
self.starImage.size.height);
}
- (void)drawRect:(CGRect)rect {
[super drawRect:rect];
CGFloat left = self.horiInset;
CGSize imageSize = self.starImage.size;
for (NSInteger i = 0; i < self.numberOfStars; i++) {
UIImage *image = self.starImage;;
if (i <= self.currentScore - 1) {
image = self.starImage;
} else if (i > ceilf(self.currentScore - 1)) {
image = self.unstarImage ?: self.starImage;
} else {
image = self.starImageForHalf ?: self.starImage;
}
CGRect rect = CGRectMake(left, 0, imageSize.width, imageSize.height);
[image drawInRect:rect];
left = CGRectGetMaxX(rect) + self.starSpace;
}
if (!self.unstarImage) {
NSInteger spaceCount = MAX(ceilf(self.currentScore) - 1, 0);
CGFloat starColorWidth = self.horiInset + spaceCount * self.starSpace + self.starImage.size.width * self.currentScore;
[self.unstarColor set];
UIRectFillUsingBlendMode(CGRectMake(starColorWidth, 0, CGRectGetWidth(self.bounds) - starColorWidth, CGRectGetHeight(self.bounds)),
kCGBlendModeSourceIn);
[self.starColor set];
UIRectFillUsingBlendMode(CGRectMake(0, 0, starColorWidth, CGRectGetHeight(self.bounds)), kCGBlendModeSourceIn);
}
}
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
[self calculateScoreAtLocation:[[touches anyObject] locationInView:self]];
}
- (void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
[self calculateScoreAtLocation:[[touches anyObject] locationInView:self]];
}
- (void)calculateScoreAtLocation:(CGPoint)location {
CGFloat locationX = MIN(MAX(location.x - self.horiInset, 0), CGRectGetWidth(self.bounds));
NSInteger intPart = 0;
CGFloat decimalPart = 0;
if (self.scoreMinPace >= self.scorePerStar) {
intPart = ceilf(locationX / (self.starImage.size.width + self.starSpace));
} else if (self.scoreMinPace == .5 * self.scorePerStar) {
intPart = floorf(locationX / (self.starImage.size.width + self.starSpace));
decimalPart = MIN((locationX - intPart * (self.starImage.size.width + self.starSpace)) / self.starImage.size.width, 1);
if (decimalPart >= .5) {
decimalPart = 1;
} else {
decimalPart = .5;
}
} else {
intPart = floorf(locationX / (self.starImage.size.width + self.starSpace));
decimalPart = MIN((locationX - intPart * (self.starImage.size.width + self.starSpace)) / self.starImage.size.width, 1);
}
self.currentScore = intPart + decimalPart;
!self.didEvaluateBlock ?: self.didEvaluateBlock(self.currentScore);
}
- (CGFloat)scoreMinPace {
if (_scoreMinPace) {
return _scoreMinPace;
}
if (self.unstarImage && self.starImageForHalf) {
return .5 * self.scorePerStar;
}
return self.scorePerStar;
}
- (CGFloat)starSpace {
if (_starSpace <= 0) {
return self.starImage.size.width / 2;
}
return _starSpace;
}
@end
实现:
//
// ViewController.m
// TTStarEvaluationView
//
// Created by rollingstoneW on 2018/9/7.
// Copyright © 2018年 demo. All rights reserved.
//
#import "ViewController.h"
#import "TTStarEvaluationView.h"
#import "XHStarRateView.h"
@interface ViewController ()<XHStarRateViewDelegate>
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
TTStarEvaluationView *star = [[TTStarEvaluationView alloc] init];
star.starImage = [UIImage imageNamed:@"star"];
star.starImageForHalf = [UIImage imageNamed:@"half-star"];
star.unstarImage = [UIImage imageNamed:@"unstar"];
star.currentScore = 2;
star.center = CGPointMake(self.view.center.x, self.view.center.y - 30);
[self.view addSubview:star];
UILabel *label1 = [[UILabel alloc] init];
label1.center = CGPointMake(star.center.x, star.center.y + 40);
[self.view addSubview:label1];
star.didEvaluateBlock = ^(CGFloat score) {
label1.text = [NSString stringWithFormat:@"%.1f分", score];
[label1 sizeToFit];
};
star.didEvaluateBlock(star.currentScore);
TTStarEvaluationView *star2 = [[TTStarEvaluationView alloc] init];
star2.starImage = [UIImage imageNamed:@"star"];
star2.scoreMinPace = 1;
star2.scorePerStar = 1;
star2.starSpace = 20;
star2.center = CGPointMake(self.view.center.x, self.view.center.y + 60);
[self.view addSubview:star2];
UILabel *label2 = [[UILabel alloc] init];
label2.center = CGPointMake(star2.center.x, star2.center.y + 40);
[self.view addSubview:label2];
star2.didEvaluateBlock = ^(CGFloat score) {
label2.text = [NSString stringWithFormat:@"%.1f分", score];
[label2 sizeToFit];
};
star2.didEvaluateBlock(star2.currentScore);
for (int i=0; i<2; i++) {
XHStarRateView *starRateView = [[XHStarRateView alloc] initWithFrame:CGRectMake(50, (50 + 8) * i/1 + 60, 180, 50)];
starRateView.isAnimation = YES;
starRateView.rateStyle = WholeStar;
starRateView.tag = I;
starRateView.delegate = self;
[self.view addSubview:starRateView];
}
}
#pragma mark - XHStarRateViewDelegate
-(void)starRateView:(XHStarRateView *)starRateView currentScore:(CGFloat)currentScore{
//NSLog(@"%ld---- %f",starRateView.tag,currentScore);
NSString *appraise_res = [NSString stringWithFormat:@"%d",(int)currentScore];
}
@end
![](https://img.haomeiwen.com/i2127575/855cfd4dd85b900c.jpg)
注意:图片换成自己的
网友评论