Demand
The project needs to use a marquee to display only one message, the appropriate length does not scroll, too long the cycle of scrolling.
Although I did not write, but looked at the code, is in a uiview inside put two Uilabel,
At the end of the previous one, the other shows. However, click Processing is indeed a UIView click event.
However, see, such as Subway, bus inside the marquee is divided into a lot of paragraph display. Although it is said that multiple segments can be merged into a section to display,
But what if the individual needs to click on the event and how to deal with it? So I came to realize a clickable multi-segment marquee.
So this essay I'm going to implement the marquee contains the following effect: (There are 5 paragraphs in the picture can be clicked to trigger the corresponding event)
Detour
Remember the last essay "IOS" to align the bottom of text with different font sizes?
Although it is not possible to achieve the bottom alignment of multiple uilabel, we can change the position of the vertical direction of the text by inheriting the Uilabel.
So, my initial idea is to inherit Uilabel, can maintain its inheritance, through the nstimer to move directly uilable inside the text.
Here are two questions: (at @ " This is the text to be moved in the custom marquee " for example)
1. Movement is movable, but when the text moves left to the point where it is almost invisible (only "moving text"), how do you make @ "This is ..." Begin to appear on the right?
2. When the text is too long, the invisible part will be truncated, so there is only part of the text when moving.
The first seems to have no way, uilabel there is only one text of the bounds, it is impossible to let him part on the left, part on the right.
The second is because there is a default property nslinebreakmode:nslinebreakbywordwrapping, and even if you do not truncate the text, it will only become an ellipsis.
So this method is abandoned ....
Realize
The first thing to be clear is that this marquee inherits the UIView and needs two Uilabel, timer Nstimer.
When initializing, pass in an array of strings and calculate the adaptive size of each string
CGRect textrect = [((NSString *) _textarray[i]) boundingrectwithsize:maxsize options: Nsstringdrawinguseslinefragmentorigin attributes:@{nsfontattributename:kfont} Context:nil]; [_textrectarray Addobject:[nsvalue valuewithcgrect:textrect];
If the number of string arrays passed in is 1 and the adaptive width <uiview width, it does not scroll. Re-write a uilabel for the display.
In other cases, it is possible to scroll, instantiate two Uilabel, and turn on the timer:
Timer Related:
_timer = [Nstimer scheduledtimerwithtimeinterval:0.02 target:self selector: @selector (timeraction:) Userinfo:nil Repeats:yes]; [[Nsrunloop Mainrunloop] Addtimer:_timer formode:nsrunloopcommonmodes];
Why put the timer in the loop?
If this runloop is performing a continuous operation, the timer will be delayed.
In other words, if you put a marquee on the ScrollView, the timer won't move when you slide the ScrollView.
Related methods:
[_timer setfiredate:[nsdate Date]]; Start//[_timer setfiredate:[nsdate Distantfuture]]; Time out
Cancel Timer
[_timer invalidate]; _timer = nil; Prevent Wild Hands
Timer Execution Events:
-(void) Timeraction: (Nstimer *) timer{}
Now all we have to do is set two Uilabel each time we enter the method.
OK, now assume that 4 strings are passed @[@ "This is the No. 0 string", @ "This is the 1th string", @ "This is the 2nd string", @ "This is the 3rd string"];
Only two labels, whether scrolling to the right or to the left, we will initially show as Labels[0], and then show the positioning labels[1]
Defines a variable that stores the origin.x value of the previous Uilabel in real time, starting with 0
1. Each time the previous uilabel is not completely hidden, the latter Uilabel is already present (there is a fixed distance between the two internalwidth)
You also need to control the position of labels[0] (change the offsetx value) by changing the size of the labels[0] by the value of the speed.
This distance and the previous position can be used to calculate the position of a Uilabel (origin.x value) in real time.
2. Each time the previous uilabel is completely hidden, a value needs to be reset, which is only entered once each time the previous uilabel is completely invisible
At the same time, the left and right two Uilabel transform position. Scroll left: After the a<--b,a disappears, a runs to the right of B; After becoming a b<--a,b disappears, go to the right of A again.
So only need to set offsetx = _labels[1].frame.origin.x; after the//a disappears, the next B position is the location of the label that will disappear, a changes to a later one,
Its position is calculated in real time based on the position of B. Each time the previous one disappears, the replacement is so circular.
But this only changes the position, the text and the size are not transformed, see 3.
3. the content of AB is the same for only one text. However, for the four strings passed in, the AB content needs to be changed each time the value is reset.
At the same time, for strings of unequal length, the corresponding AB frame needs to be set according to different text sizes.
so it takes four string literal sizes, and the text content is previously saved as an array. Defines a location that always records the (previous) Uilabel that is currently being prepared to disappear : _currentindex
In step 1: Get an array of text from two arrays for display in A.B: Labeltextarray frame array: Labelarray (from which to get wide and high)
For each AB position exchange, the currentindex+1 is required: _currentindex = (_currentindex + 1)% _textarray.count, for use after exchange.
The current and next text and frame are then saved to an array of length 2, respectively, for use
It's too much, too messy ... I don't want to see I don't want to see I don't want to see ...
Here is a picture: Read the above still do not understand, please see this bar.
Explain again
<=============== left Shift ==================
================ Right Shift =================>
now only look at the color to see can be to either roll right or left to roll Green is always labels[0] (will disappear label) red is always label[1]
under normal scrolling conditions:
The green OffsetX value changes with speed: self.offsetx = self.offsetx-sign * self.speed;
The red X value will change with the green OffsetX and fixed spacing: cgfloat nextoffx = self.offsetx + sign * ((self.orientation = Rollingorientationleft )? FirstRect.size.width:lastRect.size.width) + self.internalwidth);
Assign values from the saved data to the contents and size of the red, green, and _currentindex values:
When the green disappears for a moment:
should be on the right side of the red suddenly frighten green: self.offsetx = _labels[1].frame.origin.x;
The disappearing green will change to red in the normal scrolling condition.
_currentindex refers to the index of the green content always: _currentindex = (_currentindex + 1)% _textarray.count;
This value will then get the red, green size, and text content in the normal scrolling condition
(Two processes that will be performed will be operated in the blue section of the "normal scrolling scenario")
}
Well, explain to this end look good tired .... Wait, there's a click on the event, not finished.
Click events: Processing after adding tap gestures to Uilabel
-(void) Labeltap: (UITapGestureRecognizer *) gesture{Nsinteger tag= ((UILabel *) [gesture view]). Tag- -; Nsinteger index; if(Tag = =0){//If Yes (Labels[0]) GreenIndex=_currentindex; }Else if(Tag = =1){//if it is (labels[1]) Red is the last one that is currently clickedIndex= (_currentindex +1) %_textarray.count; }Else{Index=_currentindex; }
if(Self.labelclickblock) {self.labelclickblock (index); }}
End
Code See GitHub: ====> yfrollinglabel PS: Source and GitHub documents are written in crappy English, do not know if anyone will see.
Also indicate the problem with the recording:
The length of the text array to put is not too short because there are only two Uilabel if the length is too short and the spacing is small
After the green has just disappeared, it will turn red immediately, appearing on the current green right instead of moving slowly.
Text too long (hundreds of Chinese, normally not set so many bar), will result in the text width is too long, the uilabel width is too long, the text is not displayed directly, but the click event or some note that there is still ... This doesn't make sense ...
Well, finally finished, long live Windows Mobile!!!
"IOS" Custom clickable multi-text marquee Yfrollinglabel