在近期的開發計劃中,咱們的開發計劃有關於商品打分的功能需求列了進來,我就提早看了下,網上的這種demo實在太多了,可是都不是很符合咱們的需求,索性本身寫一個得了,那就開始動手。先看一下最終效果(最後有demo哦): git
先理一下實現思路,個人實現思路是利用CALayer的maskLayer來實現,就跟通常的進度條實現思路差很少,不過此次要用帶星的view來作mask。具體實現看下面。github
首先寫maskLayer的view 也就是帶星星的view:bash
#import <UIKit/UIKit.h>
typedef NS_ENUM(NSInteger, CYXRatingStarStyle) {
RatingStarStyleFull = 0, //滿星打分
RatingStarStyleHalf = 1, //可半星打分
};
NS_ASSUME_NONNULL_BEGIN
@interface CYXRatingStarMaskView : UIView
/*星星個數*/
-(instancetype)initWithStarNum:(NSInteger)starNum;
/**
初始化方法
@param starNum 星星個數
@param space 星星直接的間距 默認15
@return self
*/
-(instancetype)initWithStarNum:(NSInteger)starNum andSpace:(CGFloat)space;
/*更新佈局 在設置frame以後調用*/
-(void)updateViewConstrains;
/*觸摸*/
-(void)touchesWithPoint:(CGPoint)touchPoint;
/*打分風格*/
@property (nonatomic,assign) CYXRatingStarStyle ratingStarStyle;
/*總分*/
@property (nonatomic,assign) NSInteger fullScore;
/*點擊 調用block transformPoint轉換過的點 score得分*/
@property (nonatomic,strong) void(^touchBlock)(CGPoint transformPoint,NSInteger score);
@end
複製代碼
相關實現(多的我就再也不囉嗦了註釋裏面都有):佈局
#import "CYXRatingStarMaskView.h"
@interface CYXRatingStarMaskView ()
/*星星個數 最少兩個*/
@property (nonatomic,assign) NSInteger starNum;
/*星星間距 默認15*/
@property (nonatomic,assign) CGFloat space;
@property (nonatomic,strong) NSMutableArray *itemList;
@end
@implementation CYXRatingStarMaskView
-(instancetype)initWithStarNum:(NSInteger)starNum{
return [self initWithStarNum:starNum andSpace:15];
}
-(instancetype)initWithStarNum:(NSInteger)starNum andSpace:(CGFloat)space{
if (self = [super init]) {
self.starNum = starNum;
self.space = space;
[self createItems];
}
return self;
}
-(void)createItems{
self.itemList = [NSMutableArray new];
for (int i =0; i<self.starNum; i++) {
UIImageView * item = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"starUnselected"]];
[self.itemList addObject:item];
[self addSubview:item];
}
}
-(void)updateViewConstrains{
if (self.starNum>1) {
CGFloat itemWidth = (self.frame.size.width-(self.starNum -1)*self.space)/self.starNum;
if (itemWidth>0) {
CGFloat x = 0;
for (UIImageView * item in self.itemList) {
item.frame = CGRectMake(x, 0, itemWidth, self.frame.size.height);
x+=itemWidth;
x+=self.space;
}
}
}
}
-(void)touchesWithPoint:(CGPoint)touchPoint{
[self transformPointWithTouchPoint:touchPoint];
}
/*將觸點轉化成填充星星的點*/
-(CGPoint)transformPointWithTouchPoint:(CGPoint)touchPoint{
/*滿星平均分*/
NSInteger average = self.fullScore/[self.itemList count];
/*觸摸點x*/
CGFloat x = touchPoint.x;
/*得分*/
CGFloat score = 0;
/*倒序遍歷*/
for (NSInteger i = [self.itemList count]-1; i>=0; i--) {
UIImageView * item = self.itemList[i];
if (x>item.frame.origin.x) {
switch (self.ratingStarStyle) {
case RatingStarStyleFull:{//滿星
score = (i+1)*average;
x = item.frame.origin.x+item.frame.size.width;
}
break;
case RatingStarStyleHalf:{//支持半星
if (x>(item.frame.origin.x+item.frame.size.width/2)) {//超過半星
score = (i+1)*average;
x = item.frame.origin.x+item.frame.size.width;
}else{
score = (i+1)*average - (average/2);
x = item.frame.origin.x+item.frame.size.width/2;
}
}
break;
default:
break;
}
break;
}
}
CGPoint transformPoint = CGPointMake(x, touchPoint.y);
if (self.touchBlock) {
self.touchBlock(transformPoint, score);
}
return CGPointZero;
}
複製代碼
而後建立用於打分的View來利用這個maskview實現:ui
#import <UIKit/UIKit.h>
#import "CYXRatingStarMaskView.h"
NS_ASSUME_NONNULL_BEGIN
@interface CYXRatingStarView : UIView
/**
初始化方法
@param frame frame
@param ratingStarStyle 打分風格
@param fullScore 滿分
@return self
*/
-(instancetype)initWithFrame:(CGRect)frame
andRatingStarStyle:(CYXRatingStarStyle)ratingStarStyle
andFullScore:(NSInteger)fullScore;
/**
初始化layer 在完成frame賦值後調用一下
*/
-(void)initLayers;
/*選擇分數*/
@property (nonatomic,strong) void (^selectScore)(NSInteger score);
@end
複製代碼
相關實現(沒啥難點都有註釋本身看吧):atom
#import "CYXRatingStarView.h"
@interface CYXRatingStarView()
/*背景紅色*/
@property (nonatomic,strong) CAShapeLayer *backColorLayer;
@property (nonatomic,strong) CYXRatingStarMaskView *maskView;
@end
@implementation CYXRatingStarView
-(instancetype)initWithFrame:(CGRect)frame
andRatingStarStyle:(CYXRatingStarStyle)ratingStarStyle
andFullScore:(NSInteger)fullScore{
if (self = [super initWithFrame:frame]) {
self.backgroundColor = [UIColor whiteColor];
self.maskView.fullScore = fullScore;
self.maskView.ratingStarStyle = ratingStarStyle;
[self.layer addSublayer:self.backColorLayer];
}
return self;
}
-(void)initLayers{
self.maskView.frame = self.bounds;
[self.maskView updateViewConstrains];
self.backColorLayer.frame = self.bounds;
UIBezierPath *path = [UIBezierPath bezierPath];
[path moveToPoint:CGPointMake(0, self.frame.size.height/2)];
[path addLineToPoint:CGPointMake(self.frame.size.width, self.frame.size.height/2)];
self.backColorLayer.path = path.CGPath;
self.backColorLayer.lineWidth = self.frame.size.height;
self.backColorLayer.mask = self.maskView.layer;
self.backColorLayer.strokeEnd = 0;
}
/*設置選擇的星星*/
-(void)setStrokeWithTransformPoint:(CGPoint)transformPoint{
CGPoint newPoint = [self convertPoint:transformPoint fromView:self.maskView];
NSLog(@"%f",newPoint.x);
self.backColorLayer.strokeEnd = newPoint.x/self.frame.size.width;
}
/*一根或者多根手指開始觸摸view,系統會自動調用view的下面方法*/
-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
//獲取touch
UITouch * touch = [touches anyObject];
//獲取當前點
CGPoint touchPoint = [touch locationInView:self];
CGPoint newPoint = [self convertPoint:touchPoint toView:self.maskView];
[self.maskView touchesWithPoint:newPoint];
}
#pragma mark ---G
-(CAShapeLayer*)backColorLayer{
if(!_backColorLayer){
_backColorLayer = [[CAShapeLayer alloc] init];
_backColorLayer.backgroundColor = [UIColor grayColor].CGColor;//在這裏是未填充的顏色
_backColorLayer.fillColor = [UIColor clearColor].CGColor; // 填充色爲透明(不設置爲黑色)
//_backColorLayer.lineCap = kCALineCapSquare; // 設置線爲圓角
_backColorLayer.strokeColor = [UIColor redColor].CGColor; // 路徑顏色顏色(填充顏色)
}
return _backColorLayer;
}
-(CYXRatingStarMaskView*)maskView{
if(!_maskView){
__weak __typeof(&*self)weakSelf = self;
_maskView = [[CYXRatingStarMaskView alloc] initWithStarNum:5];
_maskView.touchBlock = ^(CGPoint transformPoint, NSInteger score) {
NSLog(@"%@",NSStringFromCGPoint(transformPoint));
NSLog(@"%ld",(long)score);
[weakSelf setStrokeWithTransformPoint:transformPoint];
if (weakSelf.selectScore) {
weakSelf.selectScore(score);
}
};
}
return _maskView;
}
複製代碼
整體寫下來思路仍是很明確的,並且實現過程中並無什麼疑難雜症,有什麼問題歡迎討論。spa
demo地址:github.com/SionChen/CY…code