iOS实现支持小数的星星评分组件实例代码

2020-01-21 00:06:24王冬梅

而全高亮的状态可以设置为UIButtonde点击态


- (void)setHighlightedImage:(UIImage *)highlightedImage{
 _highlightedImage = [CDZStarButton reSizeImage:highlightedImage toSize:self.frame.size];
 [self setImage:_highlightedImage forState:UIControlStateSelected];
}

而点击事件交由给上层的UIControl去处理,因为点击的时候,除了点击的星星本身,之前的星星也应该处于完全高亮状态。在上层初始化按钮的时候把其userInteractionEnabled属性设置为NO即可,这样触摸事件就会忽略传递到Button去做事件处理,从而从响应者链传递上去交由父视图的UIControl处理。

如果点击到星星的一半,我们应该把点击点转换成小数部分给上层。C语言的round函数可以四舍五入,这里的10代表保留一位小数,可以根据实际情况保留位数,一般评分很少需要更高精度的。


- (CGFloat)fractionPartOfPoint:(CGPoint)point{
 CGFloat fractionPart = (point.x - self.frame.origin.x) / self.frame.size.width;
 return round(fractionPart * 10) / 10;
}

到这里一个可以显示分数的星星按钮就完成了,接下来就是在上层的UIControl去处理触摸事件的响应。

UIControl部分的实现

主要分两块,星星按钮的布局,触摸事件响应。

布局

首先根据星星的数量一个个添加上视图,用UIView的tag来表示对应第几个星星按钮。


- (void)setupView {
 for (NSInteger index = 0; index < self.numberOfStars; index++) {
  CDZStarButton *starButton = [CDZStarButton.alloc initWithSize:self.starSize];
  starButton.tag = index;
  starButton.normalImage = self.normalStarImage;
  starButton.highlightedImage = self.highlightedStarImage;
  starButton.userInteractionEnabled = NO;//关闭事件响应,交由UIControl本身处理
  [self addSubview:starButton];
 }
}

然后是计算每个星星的位置,计算间隔和上下边距并layout


- (void)layoutSubviews {
 [super layoutSubviews];
 for (NSInteger index = 0; index < self.numberOfStars; index ++) {
  CDZStarButton *starButton = [self starForTag:index];
  CGFloat newY = (self.frame.size.height - self.starSize.height) / 2;
  CGFloat margin = 0;
  if (self.numberOfStars > 1) {
   margin = (self.frame.size.width - self.starSize.width * self.numberOfStars) / (self.numberOfStars - 1);
  }
  starButton.frame = CGRectMake((self.starSize.width + margin) * index, newY, self.starSize.width, self.starSize.height);
 }
}

这时,我们可以加上两个方法去找到对应的星星button,根据tag和根据点击的CGPoint


- (CDZStarButton *)starForPoint:(CGPoint)point {
 for (NSInteger i = 0; i < self.numberOfStars; i++) {
  CDZStarButton *starButton = [self starForTag:i];
  if (CGRectContainsPoint(starButton.frame, point)) {
   return starButton;
  }
 }
 return nil;
}

- (CDZStarButton *)starForTag:(NSInteger)tag {
 __block UIView *target;
 [self.subviews enumerateObjectsUsingBlock:^(__kindof UIView * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
  if (obj.tag == tag) {
   target = obj;
   *stop = YES;
  }
 }];
 return (CDZStarButton *)target;
}