美文网首页
oc 评价星星view

oc 评价星星view

作者: 那一处风景ljz | 来源:发表于2023-09-21 18:26 被阅读0次

第一种:

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
1041695378440_.pic.jpg

注意:图片换成自己的

相关文章

网友评论

      本文标题:oc 评价星星view

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