最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

iOS實(shí)現(xiàn)支持小數(shù)的星星評(píng)分組件實(shí)例代碼

 更新時(shí)間:2017年08月10日 09:41:12   作者:Nemocdz  
程序中需要打分的功能,在網(wǎng)上找了幾個(gè),都不是很滿(mǎn)意。所以自己動(dòng)手實(shí)現(xiàn)了一個(gè),下面這篇文章主要給大家介紹了關(guān)于利用iOS實(shí)現(xiàn)支持小數(shù)的星星評(píng)分組件的相關(guān)資料,需要的朋友可以參考借鑒,下面來(lái)一起看看吧。

前言

評(píng)分功能是我們大家都不陌生的一個(gè)功能,現(xiàn)在在很多電商,外賣(mài),餐飲型應(yīng)用里隨處可見(jiàn),都會(huì)在商品結(jié)束后評(píng)價(jià)中有一個(gè)星星組件。核心思路就是用UIControl并自定義實(shí)現(xiàn)其中的trackTouch的幾個(gè)方法。而顯示不到一個(gè)的星星,比如半個(gè)星星的思路是根據(jù)分?jǐn)?shù)切割星星的圖像并顯示其中一部分。

實(shí)現(xiàn)后效果如下:


單個(gè)星星的實(shí)現(xiàn)

對(duì)于單個(gè)星星的實(shí)現(xiàn),先考慮星星有三個(gè)狀態(tài),完全置灰狀態(tài),完全高亮狀態(tài),根據(jù)百分比半高亮狀態(tài)。而我這邊用的是UIButton來(lái)實(shí)現(xiàn),因?yàn)閁IButton本身已經(jīng)有普通,高亮,選擇的狀態(tài)。主要實(shí)現(xiàn)的就是百分比高亮狀態(tài)。我們可以根據(jù)百分比將圖像進(jìn)行裁剪,讓新圖像的寬度只有百分比所占的整個(gè)圖像的寬度。但是這時(shí)候調(diào)用setImage,會(huì)發(fā)現(xiàn)圖片處于整個(gè)button中間。這是因?yàn)閁IButton的imageView的contentMode默認(rèn)是AspectFit的,而AspectFit是默認(rèn)居中的。Contentmode中的UIViewContentModeLeft,是不會(huì)把長(zhǎng)邊縮放到imageView的邊長(zhǎng)的。況且,直接改變UIButton里的ImageView的ContentMode是沒(méi)有效果的。要通過(guò)UIControl的contentVerticalAlignment屬性(垂直)和contentHorizontalAlignment屬性(水平)來(lái)達(dá)到類(lèi)似ImageView的contentMode的效果。但是這兩個(gè)屬性都沒(méi)有帶Fit后綴的選項(xiàng),也就是說(shuō)并不會(huì)根據(jù)邊長(zhǎng)等比縮放。所以需要先把圖片縮放到和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設(shè)置為灰色的星星圖像,設(shè)置為Button的highlighted狀態(tài)

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

而全高亮的狀態(tài)可以設(shè)置為UIButtonde點(diǎn)擊態(tài)

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

而點(diǎn)擊事件交由給上層的UIControl去處理,因?yàn)辄c(diǎn)擊的時(shí)候,除了點(diǎn)擊的星星本身,之前的星星也應(yīng)該處于完全高亮狀態(tài)。在上層初始化按鈕的時(shí)候把其userInteractionEnabled屬性設(shè)置為NO即可,這樣觸摸事件就會(huì)忽略傳遞到Button去做事件處理,從而從響應(yīng)者鏈傳遞上去交由父視圖的UIControl處理。

如果點(diǎn)擊到星星的一半,我們應(yīng)該把點(diǎn)擊點(diǎn)轉(zhuǎn)換成小數(shù)部分給上層。C語(yǔ)言的round函數(shù)可以四舍五入,這里的10代表保留一位小數(shù),可以根據(jù)實(shí)際情況保留位數(shù),一般評(píng)分很少需要更高精度的。

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

到這里一個(gè)可以顯示分?jǐn)?shù)的星星按鈕就完成了,接下來(lái)就是在上層的UIControl去處理觸摸事件的響應(yīng)。

UIControl部分的實(shí)現(xiàn)

主要分兩塊,星星按鈕的布局,觸摸事件響應(yīng)。

布局

首先根據(jù)星星的數(shù)量一個(gè)個(gè)添加上視圖,用UIView的tag來(lái)表示對(duì)應(yīng)第幾個(gè)星星按鈕。

- (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;//關(guān)閉事件響應(yīng),交由UIControl本身處理
  [self addSubview:starButton];
 }
}

然后是計(jì)算每個(gè)星星的位置,計(jì)算間隔和上下邊距并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);
 }
}

這時(shí),我們可以加上兩個(gè)方法去找到對(duì)應(yīng)的星星button,根據(jù)tag和根據(jù)點(diǎn)擊的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;
}

處理觸摸事件

我們先加上兩個(gè)方法。一個(gè)是從第一個(gè)到某個(gè)星星開(kāi)始從左到右依次點(diǎn)亮,一個(gè)是從最后一個(gè)星星到某個(gè)星星從右到左依次熄滅。

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

然后設(shè)置一個(gè)評(píng)分的屬性,重寫(xiě)其setter方法。allowFraction,用來(lái)判斷組件是否需要分?jǐn)?shù)表示,floor函數(shù)是取最大整數(shù),相當(dāng)于直接去除小數(shù)點(diǎn)后面的數(shù)字。判斷評(píng)分的整數(shù)部分是否已經(jīng)亮著,亮著那么說(shuō)明從左到右最后一個(gè)亮著的右邊,反之在左邊,分別調(diào)用從右到左依次熄滅,或從左到右依次點(diǎn)亮的方法,最后再設(shè)置分?jǐn)?shù)部分。

- (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的四個(gè)方法


第一個(gè)是開(kāi)始點(diǎn)擊的時(shí)候的事件處理,第二個(gè)是手指未抬起在屏幕上繼續(xù)移動(dòng)的事件處理,第三個(gè)是離開(kāi)屏幕,第四個(gè)是因?yàn)閯e的特殊情況事件被結(jié)束的處理。

點(diǎn)擊時(shí)候只要確定點(diǎn)擊的星星,確定其小數(shù)部分,然后調(diào)用評(píng)分屬性的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;
}

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

- (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{
   //移到了當(dāng)前星星的左邊
  if (point.x < self.currentStar.frame.origin.x) {
   self.score = self.currentStar.tag;
  }
   //移到了當(dāng)前星星的右邊
  else if (point.x > (self.currentStar.frame.origin.x + self.currentStar.frame.size.width)){
   self.score = self.currentStar.tag + 1;
  }
 }
 return YES;
}

而完成觸摸操作時(shí),我們就可以用一個(gè)回調(diào)將當(dāng)前的評(píng)分傳給外界。

@protocol CDZStarsControlDelegate<NSObject>
@optional

/**
 回調(diào)星星改變后的分?jǐn)?shù)

 @param starsControl 星星組件
 @param score 分?jǐn)?shù)
 */
- (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;
}

開(kāi)放score屬性和allowFraction屬性即可。使用起來(lái)也很簡(jiǎn)單。

 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里處理分?jǐn)?shù)改變后的操作即可。

源碼下載

所有源碼和Demo本地下載

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

總結(jié)

以上就是這篇文章的全部?jī)?nèi)容了,希望本文的內(nèi)容對(duì)大家的學(xué)習(xí)或者工作能帶來(lái)一定的幫助,如果有疑問(wèn)大家可以留言交流,謝謝大家對(duì)腳本之家的支持。

相關(guān)文章

  • iOS利用NSAttributedString實(shí)現(xiàn)圖文混排效果示例

    iOS利用NSAttributedString實(shí)現(xiàn)圖文混排效果示例

    iOS7以后,因?yàn)門(mén)extKit的強(qiáng)大,可以用NSAttributedString很方便的實(shí)現(xiàn)圖文混排(主要是利用了NSTextAttachment),所以下面這篇文章主要給大家介紹了關(guān)于iOS利用NSAttributedString實(shí)現(xiàn)圖文混排效果的相關(guān)資料,需要的朋友可以參考借鑒,下面來(lái)一起看看吧。
    2017-10-10
  • iOS給border設(shè)置漸變色的方法實(shí)例

    iOS給border設(shè)置漸變色的方法實(shí)例

    這篇文章主要給大家介紹了關(guān)于iOS給border設(shè)置漸變色的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2021-03-03
  • IOS給圖片添加水印(兩種方式)

    IOS給圖片添加水?。▋煞N方式)

    為了防止自己辛苦做的項(xiàng)目被別人盜走,采取把圖片添加水印,在此表示圖片的獨(dú)一無(wú)二。加水印不是要在上面添加上幾個(gè)Label,而是我們要把字畫(huà)到圖片上成為一個(gè)整體,下面這篇文章主要介紹IOS給圖片添加水印,有需要的小伙伴可以來(lái)參考下
    2015-08-08
  • 解析iOS開(kāi)發(fā)中的FirstResponder第一響應(yīng)對(duì)象

    解析iOS開(kāi)發(fā)中的FirstResponder第一響應(yīng)對(duì)象

    這篇文章主要介紹了解析iOS開(kāi)發(fā)中的FirstResponder第一響應(yīng)對(duì)象,包括View的FirstResponder的釋放問(wèn)題,需要的朋友可以參考下
    2015-10-10
  • 一步一步實(shí)現(xiàn)iOS主題皮膚切換效果

    一步一步實(shí)現(xiàn)iOS主題皮膚切換效果

    這篇文章主要為大家詳細(xì)介紹了一步一步實(shí)現(xiàn)iOS主題皮膚切換效果的相關(guān)資料,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2016-09-09
  • 如何去掉Xcode工程中某種類(lèi)型的警告

    如何去掉Xcode工程中某種類(lèi)型的警告

    這篇文章主要給大家介紹了關(guān)于如何去掉Xcode工程中某種類(lèi)型的警告,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者使用Xcode具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2019-04-04
  • iOS中Cell的Section展開(kāi)和收起的示例代碼

    iOS中Cell的Section展開(kāi)和收起的示例代碼

    本篇文章主要介紹了iOS中Cell的Section展開(kāi)和收起的示例代碼,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2017-08-08
  • iOS 縮小打包項(xiàng)目ipa大小的實(shí)現(xiàn)方法

    iOS 縮小打包項(xiàng)目ipa大小的實(shí)現(xiàn)方法

    下面小編就為大家分享一篇iOS 縮小打包項(xiàng)目ipa大小的實(shí)現(xiàn)方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2017-12-12
  • IOS 下獲取 rootviewcontroller 的版本不同的問(wèn)題解決辦法

    IOS 下獲取 rootviewcontroller 的版本不同的問(wèn)題解決辦法

    這篇文章主要介紹了IOS 下獲取 rootviewcontroller 的版本不同的問(wèn)題解決辦法的相關(guān)資料,希望通過(guò)本文能幫助到大家,讓大家遇到這種問(wèn)題可以解決,需要的朋友可以參考下
    2017-10-10
  • IOS開(kāi)發(fā)實(shí)現(xiàn)手機(jī)震動(dòng)的提示實(shí)例代碼

    IOS開(kāi)發(fā)實(shí)現(xiàn)手機(jī)震動(dòng)的提示實(shí)例代碼

    這篇文章主要介紹了IOS開(kāi)發(fā)實(shí)現(xiàn)手機(jī)震動(dòng)的提示實(shí)例代碼的相關(guān)資料,需要的朋友可以參考下
    2017-04-04

最新評(píng)論

招远市| 舞钢市| 垫江县| 澜沧| 理塘县| 镇远县| 长葛市| 江油市| 冀州市| 镇平县| 南华县| 丹棱县| 乐清市| 义马市| 玉环县| 彰武县| 宁河县| 天峻县| 中宁县| 平南县| 余姚市| 西藏| 伽师县| 宣恩县| 安丘市| 城市| 清水县| 郓城县| 塔河县| 仁布县| 新郑市| 碌曲县| 富裕县| 德阳市| 卓尼县| 济源市| 蒙自县| 彰化市| 建昌县| 漯河市| 喜德县|