ios开发——滑动星型评分控件的实现
在App Store或者其他一些应用中我们可以通过点击或滑动星星来给应用评分,效果图如下
现在我们来实现这一功能。
首先我们需要准备两张图片作为素材,一个是灰色背景星星,另一个是黄色星星表示评分。
(亮色星星) (暗色星星)
实际操作中可以用自己需要的图片替代。
接着,我们建立自己的类继承View,来实现这个评分视图,这里假设起名为CYZStarRageView。现在来看一下头文件
@class CYZStarRateView; @protocol CYZStarRateViewDelegate <NSObject> /** * 通知代理改变评分到某一特定的值 * * @param starRateView 指当前评分view * @param percentage 新的评分值 */ - (void)starRateView:(CYZStarRateView *)starRateView didChangedScorePercentageTo:(CGFloat)percentage; @end @interface CYZStarRateView : UIView /** * 代理 */ @property (weak, nonatomic) id<CYZStarRateViewDelegate> delegate; /** * 是否使用动画,默认为NO */ @property (assign, nonatomic) BOOL shouldUseAnimation; /** * 是否允许非整型评分,默认为NO */ @property (assign, nonatomic) BOOL allowIncompleteStar; /** * 是否允许用户手指操作评分,默认为YES */ @property (assign, nonatomic) BOOL allowUserInteraction; /** * 当前评分值,范围0---1,表示的是黄色星星占的百分比,默认为1 */ @property (assign, nonatomic) CGFloat percentage; /** * 初始化方法,需传入评分星星的总数 * * @param frame 该starView的大小与位置 * @param count 评分星星的数量 * * @return 实例变量 */ - (id)initWithFrame:(CGRect)frame starCount:(NSInteger)count; /** * 设置当前评分为某一值,是否使用动画取决于shouldUseAnimation属性的取值 * * @param score 新的评分值 */ - (void)setScore:(CGFloat)score;
首先写一个协议,当评分更改后会触发该协议方法。其次,对于这个类,设立一些属性来控制相应的功能。例如:是否允许非整型评分,是否允许用户交互,是否设立动画等等。同时需要一个初始化方法,在这里传入星星的数量。应用时可以通过直接设置percentage属性或者通过调用setScore方法来设置,实质上这两个是一样的。
关键代码:
一、初始化方法。
在初始化方法中,为私有变量starCount赋值,计算出每个星星的宽度以便之后初始化子视图用。接着对默认值、子视图、手势进行初始化。为了让该方法保持“整洁”,将后面的一系列操作封装到一个私有方法- (void)initStarView 中。
- (id)initWithFrame:(CGRect)frame starCount:(NSInteger)count { self = [super initWithFrame:frame]; if (self) { self.starCount = count; self.starWidth = (CGFloat)self.frame.size.width / self.starCount; [self initStarView]; } return self; }
initStarView方法:
- (void)initStarView { //默认值 self.percentage = 1.0f; self.shouldUseAnimation = NO; self.allowIncompleteStar = NO; self.allowUserInteraction = YES; //星星视图 self.lightStarView = [self starViewWithImageName:LIGHT_STAR_IMAGE_NAME]; self.grayStarView = [self starViewWithImageName:DARK_STAR_IMAGE_NAME]; [self addSubview:self.grayStarView]; [self addSubview:self.lightStarView]; //此处用pan手势,达到用户可以滑动手指评分的效果 self.pan = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(handlePan:)]; [self addGestureRecognizer:self.pan]; }
二、添加子视图方法
之前在初始化方法中已经获得了评分星星的总数量,接着将相应数量的星星添加到该视图中即可。
- (UIView *)starViewWithImageName:(NSString *)imageName { UIView *view = [[UIView alloc] initWithFrame:self.bounds]; view.clipsToBounds = YES; view.backgroundColor = [UIColor clearColor]; //添加星星 for (int i = 0; i < self.starCount; i++) { UIImageView *iv = [[UIImageView alloc] initWithFrame:CGRectMake(i * self.starWidth, 0, self.starWidth, self.bounds.size.height)]; iv.image = [UIImage imageNamed:imageName]; iv.contentMode = UIViewContentModeScaleAspectFit; [view addSubview:iv]; } return view; }
设置view的clipsToBounds属性来达到记下来评分的效果。注意到之前的初始化方法中得到了gray视图和light视图后,添加子视图的顺序不能变。我们要做的就是根据评分让亮星星覆盖暗星星.
三、手势的相应方法
这里算是比较核心的代码了,为了实现手指滑动评分,我们选择的方法是添加pan手势(如果不要这个功能,简单的tap手势即可)。所以在这里我们根据手势的状态进行相应的计算和操作
- (void)handlePan:(UIPanGestureRecognizer *)recognizer { static CGFloat startX = 0; CGFloat starScorePercentage = 0; if (recognizer.state == UIGestureRecognizerStateBegan) { startX = [recognizer locationInView:self].x; starScorePercentage = startX / self.starWidth; } else if (recognizer.state == UIGestureRecognizerStateChanged) { CGFloat location = [recognizer translationInView:self].x + startX; starScorePercentage = location / self.starWidth; } else { return; } CGFloat realScore = self.allowIncompleteStar ? starScorePercentage : ceilf(starScorePercentage); self.percentage = realScore / self.starCount; }
思路是,记录起点,记录偏移量,计算偏移量是单位星星宽度的多少倍,然后根据是否允许非整形评分来计算实际倍数,用该值去除以总数即可得到范围为0-1的评分。给percentage赋值即可,接下来可以看到,我们在percentage的setter中将进行额外的操作。
四、setter
直接贴上代码:
- (void)setPercentage:(CGFloat)percentage { if (percentage >= 1) { _percentage = 1; } else if (percentage < 0) { _percentage = 0; } else { _percentage = percentage; } [self setNeedsLayout]; if ([self.delegate respondsToSelector:@selector(starRateView:didChangedScorePercentageTo:)]) { [self.delegate starRateView:self didChangedScorePercentageTo:_percentage]; } }这里主要是对数值的合理性检验,调用代理,以及通知view进行重新布局。在布局方法中我们真正实现评分的效果
五、layoutSubview方法
- (void)layoutSubviews { [super layoutSubviews]; __weak CYZStarRateView *weakSelf = self; CGFloat duration = self.shouldUseAnimation ? DEFAULT_DURATION : 0.0f; [UIView animateWithDuration:duration animations:^{ weakSelf.lightStarView.frame = CGRectMake(0, 0, weakSelf.percentage * weakSelf.bounds.size.width, weakSelf.bounds.size.height); }]; }
通过改变lightStarView的frame来改变亮星星的显示个数和范围,露出下面的灰色星星。这样就达到我们想要的效果了。
郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。