亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 系統 > iOS > 正文

iOS實現支持小數的星星評分組件實例代碼

2020-07-26 02:44:15
字體:
來源:轉載
供稿:網友

前言

評分功能是我們大家都不陌生的一個功能,現在在很多電商,外賣,餐飲型應用里隨處可見,都會在商品結束后評價中有一個星星組件。核心思路就是用UIControl并自定義實現其中的trackTouch的幾個方法。而顯示不到一個的星星,比如半個星星的思路是根據分數切割星星的圖像并顯示其中一部分。

實現后效果如下:


單個星星的實現

對于單個星星的實現,先考慮星星有三個狀態,完全置灰狀態,完全高亮狀態,根據百分比半高亮狀態。而我這邊用的是UIButton來實現,因為UIButton本身已經有普通,高亮,選擇的狀態。主要實現的就是百分比高亮狀態。我們可以根據百分比將圖像進行裁剪,讓新圖像的寬度只有百分比所占的整個圖像的寬度。但是這時候調用setImage,會發現圖片處于整個button中間。這是因為UIButton的imageView的contentMode默認是AspectFit的,而AspectFit是默認居中的。Contentmode中的UIViewContentModeLeft,是不會把長邊縮放到imageView的邊長的。況且,直接改變UIButton里的ImageView的ContentMode是沒有效果的。要通過UIControl的contentVerticalAlignment屬性(垂直)和contentHorizontalAlignment屬性(水平)來達到類似ImageView的contentMode的效果。但是這兩個屬性都沒有帶Fit后綴的選項,也就是說并不會根據邊長等比縮放。所以需要先把圖片縮放到和Button大小一致。


之后,我們就可以按百分比裁剪圖片

+ (UIImage *)croppedImage:(UIImage *)image fraction:(CGFloat)fractonPart{ CGFloat width = image.size.width * fractonPart * image.scale; CGRect newFrame = CGRectMake(0, 0, width , image.size.height * image.scale); CGImageRef resultImage = CGImageCreateWithImageInRect(image.CGImage, newFrame); UIImage *result = [UIImage imageWithCGImage:resultImage scale:image.scale orientation:image.imageOrientation]; CGImageRelease(resultImage); return result;}

并在BackgroundImage設置為灰色的星星圖像,設置為Button的highlighted狀態

- (void)setFractionPart:(CGFloat)fractionPart{ if (fractionPart == 0) { return; } UIImage *image = [CDZStarButton croppedImage:self.highlightedImage fraction:fractionPart]; self.imageView.contentMode = UIViewContentModeScaleAspectFit; self.contentHorizontalAlignment = UIControlContentHorizontalAlignmentLeft; self.contentVerticalAlignment = UIControlContentVerticalAlignmentFill; [self setImage:image forState:UIControlStateHighlighted]; [self setBackgroundImage:self.normalImage forState:UIControlStateHighlighted]; self.selected = NO; self.highlighted = YES;}

而全高亮的狀態可以設置為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;}

處理觸摸事件

我們先加上兩個方法。一個是從第一個到某個星星開始從左到右依次點亮,一個是從最后一個星星到某個星星從右到左依次熄滅。

- (void)starsDownToIndex:(NSInteger)index { for (NSInteger i = self.numberOfStars; i > index; --i) {  CDZStarButton *starButton = [self starForTag:i];  starButton.selected = NO;  starButton.highlighted = NO; }}- (void)starsUpToIndex:(NSInteger)index { for (NSInteger i = 0; i <= index; i++) {  CDZStarButton *starButton = [self starForTag:i];  starButton.selected = YES;  starButton.highlighted = NO; }}

然后設置一個評分的屬性,重寫其setter方法。allowFraction,用來判斷組件是否需要分數表示,floor函數是取最大整數,相當于直接去除小數點后面的數字。判斷評分的整數部分是否已經亮著,亮著那么說明從左到右最后一個亮著的右邊,反之在左邊,分別調用從右到左依次熄滅,或從左到右依次點亮的方法,最后再設置分數部分。

- (void)setScore:(CGFloat)score{ if (_score == score) {  return; } _score = score; NSInteger index = floor(score); CGFloat fractionPart = score - index;; if (!self.isAllowFraction || fractionPart == 0) {  index -= 1; } CDZStarButton *starButton = [self starForTag:index]; if (starButton.selected) {  [self starsDownToIndex:index]; } else{  [self starsUpToIndex:index]; } starButton.fractionPart = fractionPart;}

主要用到UIControl的四個方法


第一個是開始點擊的時候的事件處理,第二個是手指未抬起在屏幕上繼續移動的事件處理,第三個是離開屏幕,第四個是因為別的特殊情況事件被結束的處理。

點擊時候只要確定點擊的星星,確定其小數部分,然后調用評分屬性的setter方法就好了。

- (BOOL)beginTrackingWithTouch:(UITouch *)touch withEvent:(UIEvent *)event { CGPoint point = [touch locationInView:self]; CDZStarButton *pressedStar = [self starForPoint:point]; if (pressedStar) {  self.currentStar = pressedStar;  NSInteger index = pressedStar.tag;  CGFloat fractionPart = 1;  if (self.isAllowFraction) {   fractionPart = [pressedStar fractionPartOfPoint:point];  }  self.score = index + fractionPart; } return YES;}

移動處理除了和點擊一樣的判斷邏輯,還要注意手指移開了星星之外的地方,分為所在星星的左邊(當前星星熄滅),右邊(當前星星完全點亮)兩種。

- (BOOL)continueTrackingWithTouch:(UITouch *)touch withEvent:(UIEvent *)event { CGPoint point = [touch locationInView:self]; CDZStarButton *pressedStar = [self starForPoint:point]; if (pressedStar) {  self.currentStar = pressedStar;  NSInteger index = pressedStar.tag;  CGFloat fractionPart = 1;  if (self.isAllowFraction) {   fractionPart = [pressedStar fractionPartOfPoint:point];  }  self.score = index + fractionPart; } else{   //移到了當前星星的左邊  if (point.x < self.currentStar.frame.origin.x) {   self.score = self.currentStar.tag;  }   //移到了當前星星的右邊  else if (point.x > (self.currentStar.frame.origin.x + self.currentStar.frame.size.width)){   self.score = self.currentStar.tag + 1;  } } return YES;}

而完成觸摸操作時,我們就可以用一個回調將當前的評分傳給外界。

@protocol CDZStarsControlDelegate<NSObject>@optional/** 回調星星改變后的分數 @param starsControl 星星組件 @param score 分數 */- (void)starsControl:(CDZStarsControl *)starsControl didChangeScore:(CGFloat)score;@end
- (void)endTrackingWithTouch:(UITouch *)touch withEvent:(UIEvent *)event { [super endTrackingWithTouch:touch withEvent:event]; if ([self.delegate respondsToSelector:@selector(starsControl:didChangeScore:)]) {  [self.delegate starsControl:self didChangeScore:self.score]; }} - (void)cancelTrackingWithEvent:(UIEvent *)event { [super cancelTrackingWithEvent:event]; if ([self.delegate respondsToSelector:@selector(starsControl:didChangeScore:)]) {  [self.delegate starsControl:self didChangeScore:self.score]; }}

封裝

- (instancetype)initWithFrame:(CGRect)frame      stars:(NSInteger)number      starSize:(CGSize)size    noramlStarImage:(UIImage *)normalImage   highlightedStarImage:(UIImage *)highlightedImage{ if (self = [super initWithFrame:frame]) {  _numberOfStars = number;  _normalStarImage = normalImage;  _highlightedStarImage = highlightedImage;  _starSize = size;  _allowFraction = NO;  self.clipsToBounds = YES;  self.backgroundColor = [UIColor clearColor];  [self setupView]; } return self;}

開放score屬性和allowFraction屬性即可。使用起來也很簡單。

 CDZStarsControl *starsControl = [CDZStarsControl.alloc initWithFrame:CGRectMake(0, 100, self.view.frame.size.width, 50) stars:5 starSize:CGSizeMake(50, 50) noramlStarImage:[UIImage imageNamed:@"star_normal"] highlightedStarImage:[UIImage imageNamed:@"star_highlighted"]]; starsControl.delegate = self; starsControl.allowFraction = YES; starsControl.score = 2.6f; [self.view addSubview:starsControl];

然后在delegate里處理分數改變后的操作即可。

源碼下載

所有源碼和Demo(本地下載)

可以直接拿文件去使用或修改,也支持Cocoapods.

總結

以上就是這篇文章的全部內容了,希望本文的內容對大家的學習或者工作能帶來一定的幫助,如果有疑問大家可以留言交流,謝謝大家對武林網的支持。

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
米奇精品一区二区三区在线观看| 久久精品最新地址| 国产精品欧美久久久| 2019中文字幕在线免费观看| 日韩成人av在线| 亚洲天堂av在线免费| 日韩av中文字幕在线| 45www国产精品网站| 久久国产加勒比精品无码| 中文字幕亚洲无线码a| 狠狠操狠狠色综合网| 欧美多人乱p欧美4p久久| 国产精品极品尤物在线观看| 一区二区在线视频播放| 日本三级韩国三级久久| 欧美日本国产在线| 日韩av手机在线| 欧美天堂在线观看| xxxx性欧美| 日韩在线视频线视频免费网站| 国产精品一区二区三区免费视频| 日本精品久久久久久久| 亚洲人成电影网站色| 亚洲精品电影在线| 欧美精品videos| 久久影视电视剧凤归四时歌| 国产日韩欧美视频在线| 欧美精品www| 成人免费在线视频网站| 亚洲已满18点击进入在线看片| 久久中文字幕国产| 亚洲人成77777在线观看网| 日韩视频永久免费观看| 69av在线视频| 色婷婷**av毛片一区| 91精品国产91久久久| 91丨九色丨国产在线| 日韩欧美成人精品| 欧美成人在线影院| 色青青草原桃花久久综合| 亚洲人成网站免费播放| 欧美另类在线观看| 欧美日韩中文字幕在线视频| 亚洲欧美精品中文字幕在线| 91精品国产乱码久久久久久蜜臀| 精品国偷自产在线视频99| 97在线免费观看视频| 欧美日韩国产色| 热久久免费视频精品| 欧美色播在线播放| 久久久久久中文| 国产视频精品在线| 国产精品av免费在线观看| 国产精品爱啪在线线免费观看| 亚洲精品国精品久久99热一| 国产一区二区三区久久精品| 国产精品久久久一区| 日韩欧美在线第一页| 亚洲国产高清福利视频| 九九精品在线观看| 亚洲第一国产精品| 国产一级揄自揄精品视频| 日韩精品高清在线| 秋霞av国产精品一区| 高清亚洲成在人网站天堂| 91久久夜色精品国产网站| 欧美自拍大量在线观看| 欧美一区第一页| 亚洲精品国产精品国自产在线| 91av视频在线播放| 国产成人精品视频在线观看| 亚洲一区二区三区四区在线播放| 久久久久久亚洲| 亚洲夜晚福利在线观看| 一本色道久久88亚洲综合88| 91精品美女在线| 精品二区三区线观看| 日韩av一卡二卡| 国产精品一区二区久久| 久久伊人精品天天| 日韩视频免费在线观看| 欧美一乱一性一交一视频| 日韩欧美国产黄色| 亚洲精品国精品久久99热| 性欧美暴力猛交69hd| 欧美电影免费观看高清完整| 亚洲精品按摩视频| 亚洲免费一级电影| 亚洲色图欧美制服丝袜另类第一页| 韩曰欧美视频免费观看| 日韩免费观看视频| 欧美激情欧美激情| 日韩在线视频免费观看高清中文| 亚洲少妇中文在线| 欧美午夜影院在线视频| 久久精品亚洲精品| 国产精品第二页| 日本欧美精品在线| 欧美精品在线第一页| 在线观看国产精品91| 国产精品va在线播放我和闺蜜| 亚洲欧美在线看| 黄色一区二区三区| 成人亚洲激情网| 91国自产精品中文字幕亚洲| 国产91精品久久久久久| 欧美老少配视频| 中文字幕日韩精品在线观看| 亚洲a在线播放| 欧美xxxx做受欧美.88| 日韩欧美在线国产| 欧美性xxxxhd| 精品国产31久久久久久| 国产一区二区三区视频| 欧美精品九九久久| 伊人精品在线观看| 91tv亚洲精品香蕉国产一区7ujn| 亚洲色图日韩av| 全色精品综合影院| 久久久极品av| 日韩风俗一区 二区| 一区二区av在线| 亚洲欧美中文日韩在线| 国产亚洲福利一区| 亚洲国产成人久久综合一区| 97在线视频免费观看| 国产精品美女主播| 国产99久久精品一区二区| 欧美黑人一级爽快片淫片高清| 高清欧美一区二区三区| 亚洲欧美国产va在线影院| 日韩欧美在线国产| 一本色道久久88综合亚洲精品ⅰ| 国产精品自产拍在线观看| 日韩在线中文字幕| 亚洲精品视频中文字幕| 欧美视频免费在线| 亚洲国产精品久久久久秋霞蜜臀| 国产成人精品日本亚洲专区61| 国模私拍一区二区三区| 亚洲精品成人av| **欧美日韩vr在线| 日韩精品免费观看| 日韩国产高清污视频在线观看| 久久久久久国产精品三级玉女聊斋| 国产精品视频免费观看www| 精品露脸国产偷人在视频| 国产剧情日韩欧美| 亚洲免费视频观看| 国产综合久久久久久| 国产精品丝袜久久久久久不卡| 98视频在线噜噜噜国产| 欧美专区福利在线| 4k岛国日韩精品**专区| 国产精品久久久久久搜索| 久久影院模特热| 欧美中文字幕第一页| 日韩一级黄色av| 国产日韩在线一区| 欧美激情视频在线免费观看 欧美视频免费一| 国模精品视频一区二区三区| 热久久这里只有精品| 2020欧美日韩在线视频| 亚洲精品国产精品国自产在线|