美文网首页UI
iOS 一个可高度自定义化的评分控件、打分、打星

iOS 一个可高度自定义化的评分控件、打分、打星

作者: Hedgehog___ | 来源:发表于2018-11-15 17:59 被阅读68次

      在近期的开发计划中,我们的开发计划有关于商品打分的功能需求列了进来,我就提前看了下,网上的这种demo实在太多了,但是都不是很符合我们的需求,索性自己写一个得了,那就开始动手。先看一下最终效果(最后有demo哦):


    QQ20181115-174009-HD.gif

      那有兴趣的同学继续往下看。
      先理一下实现思路,我的实现思路是利用CALayer的maskLayer来实现,就跟一般的进度条实现思路差不多,不过这次要用带星的view来做mask。具体实现看下面。
      首先写maskLayer的view 也就是带星星的view:

    #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实现:

    #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
    
    

    相关实现(没啥难点都有注释自己看吧):

    #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;
    }
    

      总体写下来思路还是很明确的,而且实现过程当中并没有什么疑难杂症,有什么问题欢迎讨论。
    demo地址:https://github.com/SionChen/CYXRatingStarViewDemo

    相关文章

      网友评论

        本文标题:iOS 一个可高度自定义化的评分控件、打分、打星

        本文链接:https://www.haomeiwen.com/subject/fxxufqtx.html