最近项目需要实现X宝,X东上面的的收货物品的星级评价功能,首先当然是搜索大法了,找了两三个初看还可以的,体验了下,结果就是用是能用,但是有些细节上还是不太符合自己的需求。我这要达到的功能是:
1、能实现整颗星、半颗星的显示。需求要求点评的时候是只能选择整颗星,展示的时候可以显示到半颗星。
2、能拖动、能点击显示。
3、其他细节。
最终还是在WTKStarView的参考上自己实现了一个星级评分。
这里说下本控件的功能:
1、支持整颗星、半颗星的显示,包括2.3、3.6这样的。
2、支持拖动、点击。
3、支持设置一颗星星的Size,星星之间的间距。
4、支持先初始化,在传Frame布局。
下面上代码示范:
先看看整体的代码.h
#import <UIKit/UIKit.h>
@class ABStarLevelView;
typedef NS_ENUM(NSInteger, ABStarLevelType) {
ABStarLevelTypeFull = 0, //满星
ABStarLevelTypeHalf, //半星
};
@interface ABStarLevelStyle : NSObject
/**
类型(默认是满星)
*/
@property (nonatomic, assign) ABStarLevelType starType;
/**
亮起的星星图片名字
*/
@property (nonatomic, copy) NSString *highlightStarImageName;
/**
暗的星星图片名字
*/
@property (nonatomic, copy) NSString *normalStarImageName;
/**
星星大小(默认CGSizeZero)
*/
@property (nonatomic, assign) CGSize starSize;
/**
星星间距(默认0,即根据给的宽度来划分)
*/
@property (nonatomic, assign) CGFloat starInterval;
@end
@protocol ABStarLevelViewDelegate <NSObject>
@optional
- (void)starLevelView:(ABStarLevelView *)starLevelView currentStarLevel:(CGFloat)currentStarLevel;
@end
@interface ABStarLevelView : UIView
/**
星级 0-5(默认0星)
*/
@property (nonatomic, assign) CGFloat starLevel;
/**
是否允许交互(拖动、点击)
*/
@property (nonatomic, assign) BOOL touchEnabled;
/**
当前设置的星级
*/
@property (nonatomic, assign, readonly) CGFloat currentSatrLevel;
@property (nonatomic, weak) id<ABStarLevelViewDelegate>delegate;
/**
初始化StarLevel
@param style 允许传nil(传nil,内部默认初始化一个ABStarLevelStyle)
@return ABStarLevelView
*/
- (instancetype)initWithStyle:(ABStarLevelStyle *)style;
/**
初始化StarLevel
@param frame 设置大小
@param style 允许传nil(传nil,内部默认初始化一个ABStarLevelStyle)
@return ABStarLevelView
*/
- (instancetype)initWithFrame:(CGRect)frame style:(ABStarLevelStyle *)style;
@end
再来看看使用例子
//默认样式
ABStarLevelStyle *style = [[ABStarLevelStyle alloc]init];
ABStarLevelView *starLevelView = [[ABStarLevelView alloc]initWithFrame:CGRectMake(30, 250, 210, 30) style:style];
starLevelView.delegate = self;
starLevelView.backgroundColor = [UIColor greenColor];
starLevelView.touchEnabled = YES;
[self.view addSubview:starLevelView];
self.starLevelView = starLevelView;
//设置星星大小,间距
ABStarLevelStyle *style2 = [[ABStarLevelStyle alloc]init];
style2.starType = ABStarLevelTypeFull;//ABStarLevelTypeHalf(半星)
style2.starSize = CGSizeMake(30, 30);
style2.starInterval = 15;
ABStarLevelView *starLevelView2 = [[ABStarLevelView alloc]initWithFrame:CGRectMake(30, 350, 210, 30) style:style2];
starLevelView2.delegate = self;
starLevelView2.backgroundColor = [UIColor greenColor];
starLevelView2.touchEnabled = YES;
[self.view addSubview:starLevelView2];
-(void)starLevelView:(ABStarLevelView *)starLevelView currentStarLevel:(CGFloat)currentStarLevel
{
NSLog(@"FFFFF === %f",currentStarLevel);
}
-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
NSLog(@"currentSatrLevel == %f",self.starLevelView.currentSatrLevel);
}
最后贴上.m文件
#import "ABStarLevelView.h"
#define STAR_NUM 5
@implementation ABStarLevelStyle
- (instancetype)init
{
self = [super init];
if (self) {
self.starType = ABStarLevelTypeFull;
self.starInterval = 0;
self.starSize = CGSizeZero;
self.normalStarImageName = @"start_normal";
self.highlightStarImageName = @"start_highlight";
}
return self;
}
@end
@interface ABStarLevelView ()
@property (nonatomic, strong) ABStarLevelStyle *style;
@property (nonatomic, strong) NSMutableArray *frontStars;
@property (nonatomic, strong) NSMutableArray *backStars;
@property (nonatomic, strong) UIView *frontView;
@property (nonatomic, strong) UIView *backView;
@property (nonatomic, assign) CGFloat starWidth;
@property (nonatomic, assign) CGFloat starHeight;
@end
@implementation ABStarLevelView
-(NSMutableArray *)frontStars
{
if (_frontStars == nil) {
_frontStars = [NSMutableArray arrayWithCapacity:STAR_NUM];
}
return _frontStars;
}
-(NSMutableArray *)backStars
{
if (_backStars == nil) {
_backStars = [NSMutableArray arrayWithCapacity:STAR_NUM];
}
return _backStars;
}
- (instancetype)initWithStyle:(ABStarLevelStyle *)style
{
self = [super init];
if (self) {
if (style == nil) {
style = [[ABStarLevelStyle alloc]init];
}
self.style = style;
[self addTheView];
}
return self;
}
- (instancetype)initWithFrame:(CGRect)frame style:(ABStarLevelStyle *)style
{
self = [super initWithFrame:frame];
if (self) {
if (style == nil) {
style = [[ABStarLevelStyle alloc]init];
}
self.style = style;
[self addTheView];
}
return self;
}
- (void)addTheView
{
self.touchEnabled = NO;
if (self.style.starType == ABStarLevelTypeFull) {
for (NSInteger i = 0; i < STAR_NUM; i ++) {
UIImageView *imageView = [[UIImageView alloc]initWithImage:[UIImage imageNamed:self.style.highlightStarImageName]];
[self addSubview:imageView];
[self.frontStars addObject:imageView];
}
}
else {
self.backView = [self creatViewWithImageName:self.style.normalStarImageName front:NO];
[self addSubview:self.backView];
self.frontView = [self creatViewWithImageName:self.style.highlightStarImageName front:YES];
[self addSubview:self.frontView];
}
}
- (UIView *)creatViewWithImageName:(NSString *)imageName front:(BOOL)front
{
UIView *view = [[UIView alloc]init];
view.layer.masksToBounds = YES;
view.backgroundColor = [UIColor clearColor];
for (NSInteger i = 0; i < STAR_NUM; i ++) {
UIImageView *imageView = [[UIImageView alloc]initWithImage:[UIImage imageNamed:imageName]];
imageView.contentMode = UIViewContentModeScaleAspectFit;
[view addSubview:imageView];
front ? [self.frontStars addObject:imageView] : [self.backStars addObject:imageView];
}
return view;
}
-(void)layoutSubviews
{
[super layoutSubviews];
CGFloat starWidth = 0;
CGFloat starHeight = 0;
CGFloat parentViewWidth = self.frame.size.width;
CGFloat parentViewHeight = self.frame.size.height;
if (self.style.starSize.width == 0 || self.style.starSize.width > parentViewWidth / 5.0) {
starWidth = parentViewWidth / 8.0;
if (starWidth > parentViewHeight) {
starWidth = parentViewHeight;
}
starHeight = starWidth;
}
else {
starWidth = self.style.starSize.width;
if (starWidth > parentViewHeight) {
starWidth = parentViewHeight;
}
starHeight = self.style.starSize.height > parentViewHeight ? starWidth : self.style.starSize.height;
}
if (self.style.starInterval <= 0) {
self.style.starInterval = (parentViewWidth - starWidth * 5.0) / 4.0;
}
CGFloat starViewY = (parentViewHeight - starHeight) / 2;
self.starWidth = starWidth;
self.starHeight = starHeight;
if (self.style.starType == ABStarLevelTypeFull) {
for (NSInteger i = 0; i < STAR_NUM; i ++) {
UIImageView *imageView = self.frontStars[i];
imageView.frame = CGRectMake(i * (starWidth + self.style.starInterval), starViewY, starWidth, starHeight);
}
}
else {
self.frontView.frame = self.bounds;
self.backView.frame = self.bounds;
for (NSInteger i = 0; i < STAR_NUM; i ++) {
CGRect frame = CGRectMake(i * (starWidth + self.style.starInterval), starViewY, starWidth, starHeight);
UIImageView *fontImageView = self.frontStars[i];
fontImageView.frame = frame;
UIImageView *backImageView = self.backStars[i];
backImageView.frame = frame;
}
}
//给个初始值
self.starLevel = self.starLevel;
}
-(void)setStarLevel:(CGFloat)starLevel
{
starLevel = MAX(0, MIN(5.0, starLevel));
_starLevel = starLevel;
if (self.style.starType == ABStarLevelTypeFull) {
[self.frontStars enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
UIImageView *imageView = obj;
if (idx + 1 <= starLevel) {
imageView.image = [UIImage imageNamed:self.style.highlightStarImageName];
}
else {
imageView.image = [UIImage imageNamed:self.style.normalStarImageName];
}
}];
}
else {
int value = starLevel;
CGFloat width = (value) * (self.starWidth + self.style.starInterval) + (starLevel - value) * self.starWidth;
self.frontView.frame = CGRectMake(0, 0, width, self.frame.size.height);
}
_currentSatrLevel = starLevel;
}
#pragma mark - touch
-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
if (!self.touchEnabled) {
return;
}
if (self.style.starType == ABStarLevelTypeFull) {
[self resetFullStar:touches];
}
else {
[self resetHalfStar:touches];
}
}
-(void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
if (!self.touchEnabled) {
return;
}
if (self.style.starType == ABStarLevelTypeFull) {
[self resetFullStar:touches];
}
else {
[self resetHalfStar:touches];
}
}
- (void)resetFullStar:(NSSet<UITouch *> *)touches
{
UITouch *touch = [touches anyObject];
CGPoint touchPoint = [touch locationInView:self];
CGFloat starLevel = 0;
for (NSInteger i = 0; i < STAR_NUM; i++) {
UIImageView *imageView = self.frontStars[i];
if (touchPoint.x >= 0 && touchPoint.x < self.frame.size.width && touchPoint.y >= 0 && touchPoint.y < self.frame.size.height) { //触摸点在星星上
if (imageView.frame.origin.x > touchPoint.x) {
imageView.image = [UIImage imageNamed:self.style.normalStarImageName];
}
else {
imageView.image = [UIImage imageNamed:self.style.highlightStarImageName];
starLevel ++;
}
}
}
_currentSatrLevel = starLevel;
if (self.delegate && [self.delegate respondsToSelector:@selector(starLevelView:currentStarLevel:)]) {
[self.delegate starLevelView:self currentStarLevel:starLevel];
}
}
- (void)resetHalfStar:(NSSet<UITouch *> *)touches
{
UITouch *touch = [touches anyObject];
CGPoint touchPoint = [touch locationInView:self];
CGPoint starPoint;
CGFloat starLevel = 0;
int flag = 0;//判断是否已经调用delegate
if (touchPoint.x >= 0 && touchPoint.x < self.frame.size.width && touchPoint.y >= 0 && touchPoint.y < self.frame.size.height) {
for (NSInteger i = 0; i < STAR_NUM; i ++) {
UIImageView *imageView = self.frontStars[i];
starPoint = [touch locationInView:imageView];
if (starPoint.x >= 0 && starPoint.x <= self.starWidth) { //触摸点在星星上
CGFloat value = starPoint.x / self.starWidth;
self.frontView.frame = CGRectMake(0, 0, imageView.frame.origin.x + value * self.starWidth, self.frame.size.height);
_currentSatrLevel = i + value;
if (flag == 0 && self.delegate && [self.delegate respondsToSelector:@selector(starLevelView:currentStarLevel:)]) {
[self.delegate starLevelView:self currentStarLevel:i + value];
}
flag ++;
}
else {
self.frontView.frame = CGRectMake(0, 0, touchPoint.x, self.frame.size.height);
if (touchPoint.x > imageView.frame.origin.x) {
starLevel = i + 1;
_currentSatrLevel = starLevel;
}
}
}
if (flag == 0 && self.delegate && [self.delegate respondsToSelector:@selector(starLevelView:currentStarLevel:)]) {
[self.delegate starLevelView:self currentStarLevel:starLevel];
}
}
}
@end
基本上就这样,感觉还有很多细节可以优化!
网友评论