In the App store or some other apps, we can score apps by clicking or sliding stars, as follows
Now let's implement this function.
First we need to prepare two pictures as the material, one is the gray background star, the other is the yellow star to indicate the score.
(bright stars) (dark Stars)
The actual operation can be replaced with the picture you need.
Next, we create our own class inheritance view to implement this scoring view, which assumes that it is named Cyzstarrageview. Now take a look at the header file
@class Cyzstarrateview; @protocol Cyzstarrateviewdelegate <nsobject>/** * Notify the agent to change the rating to a specific value * * @param starrateview means Current Rating View * @param percentage New rating value */-(void) Starrateview: (Cyzstarrateview *) Starrateview Didchangedscorepercentageto: (cgfloat) percentage; @end @interface cyzstarrateview:uiview/** * Agent */@property (weak, nonatomic) id< Cyzstarrateviewdelegate> delegate;/** * Whether to use animation, default to No */@property (assign, nonatomic) BOOL shoulduseanimation;/** * whether Allow non-integer ratings, default to No/@property (assign, nonatomic) BOOL allowincompletestar;/** * Whether to allow user finger operation rating, default is yes */@property (Assign, no natomic) BOOL allowuserinteraction;/** * Current Rating value, range 0---1, indicates the percentage of yellow stars, default is 1 */@property (assign, nonatomic) cgfloat percentage;/** * Initialize method, need to pass in the total number of stars * * @param frame the size and position of the Starview * @param count star number of stars * * @return instance variable */-(id) INI Twithframe: (CGRect) frame starcount: (nsinteger) count;/** * Set current rating to a value, whether to use animation depends on the value of the Shoulduseanimation property * * @param Score new scoring value */-(void) SetScore: (cgfloat) score;
A protocol is written first, and the protocol method is triggered when the score changes. Second, for this class, set up some properties to control the corresponding function. Example: whether to allow non-integer scoring, whether to allow user interaction, whether to set up animations, and so on. Also requires an initialization method, where the number of stars is passed in. The application can be set by directly setting the percentage property or by calling the SetScore method, essentially the two are the same.
Key code:
First, the method of initialization.
In the initialization method, assign a value to the private variable starcount, calculating the width of each star for subsequent initialization of the child view. The default values, child views, and gestures are then initialized. To keep the method "neat," encapsulate the following sequence of operations into a private method-(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 Method:
-(void) Initstarview { //default value self.percentage = 1.0f; Self.shoulduseanimation = NO; Self.allowincompletestar = NO; Self.allowuserinteraction = YES; Star View Self.lightstarview = [self starviewwithimagename:light_star_image_name]; Self.graystarview = [self starviewwithimagename:dark_star_image_name]; [Self addSubview:self.grayStarView]; [Self addSubview:self.lightStarView]; The pan gesture is used here to achieve the effect that the user can swipe the finger to score self.pan = [[Uipangesturerecognizer alloc] initwithtarget:self action: @selector ( Handlepan:)]; [Self addGestureRecognizer:self.pan];}
Second, add a child view method
The total number of scored stars has been obtained in the initialization method before, and the corresponding number of stars is added to the view.
-(UIView *) Starviewwithimagename: (NSString *) imageName { UIView *view = [[UIView alloc] initWithFrame:self.bounds] ; View.clipstobounds = YES; View.backgroundcolor = [Uicolor clearcolor]; Add Star for (int i = 0; i < Self.starcount; i++) { Uiimageview *iv = [[Uiimageview alloc] Initwithframe:cgrectma Ke (i * self.starwidth, 0, Self.starwidth, self.bounds.size.height)]; Iv.image = [UIImage imagenamed:imagename]; Iv.contentmode = Uiviewcontentmodescaleaspectfit; [View Addsubview:iv]; } return view;}
Set the Clipstobounds property of the view to achieve the effect of writing down the score. Note that the order in which the child views are added cannot be changed after the gray and light views have been obtained in the previous initialization method. All we have to do is make light stars cover the Dark stars according to the score.
Third, the corresponding method of gesture
Here is the core of the code, in order to achieve the finger swipe scoring, we choose to add a pan gesture (if not this function, simple tap gestures can be). So here we calculate and operate according to the state of the gesture.
-(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;}
The idea is to record the starting point, record the offset, calculate how many times the offset is the width of the star, and then calculate the actual multiplier based on whether the non-shaping score is allowed, and use that value to remove the total to get a rating of 0-1. Assign a value to percentage, and you can see that we will do extra work in the setter of the percentage.
Four, setter
Paste the code directly:
-(void) Setpercentage: (cgfloat) Percentage { if (percentage >= 1) { _percentage = 1; } else if (percentage & Lt 0) { _percentage = 0; } else { _percentage = percentage; } [Self setneedslayout]; if ([Self.delegate respondstoselector: @selector (Starrateview:didchangedscorepercentageto:)]) { [self.delegate Starrateview:self didchangedscorepercentageto:_percentage];} }
This is mainly a test of the rationality of the value, the invocation of the proxy, and the notification view to re-layout. In the layout method we really achieve the effect of scoring
V. Methods of 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); }];}
Change the Lightstarview frame to show the number and range of bright stars, revealing the gray stars below. This will achieve the effect we want.
iOS development--the implementation of sliding star scoring control