Uiscrollview Practical Experience

Source: Internet
Author: User

reprinted from : http://tech.glowing.com/cn/practice-in-uiscrollview/

UIScrollView(including its subclasses UITableView and UICollectionView ) is the most common and interesting UI component in IOS development, and most apps ' core interfaces are based on a combination of one or three of them. UIScrollViewis one of the UIKit few that can respond to sliding gestures, compared to UIPanGestureRecognizer implementing some of the effects of sliding gestures, with UIScrollView the advantage of bounce and decelerate features such as the user experience of the APP and the IOS system user experience Remain consistent. In this paper, some examples UIScrollView are given to explain the characteristics and practical use of experience.

Uiscrollview and Auto Layout

When IPhone 5 came out, most apps that didn't support horizontal screens didn't need to do much of the work, because the screen width didn't change, and the table view multiple cells didn't have to add code. But after the release of iphone 6 and iphone 6 Plus, the multi-resolution adaptation is finally no longer a patent for Android development. As a result, Auto Layout, which existed since IOS 6, has finally come into play.

For basic usage of Auto Layout, you can refer to the tutorials on Ray Wenderlich (Part 2). But UIScrollView in Auto Layout is a very special view, for UIScrollView the Subview, its leading/trailing/top/bottom space is relative to UIScrollView the contentsize rather than Bounds to determine, so when you try to use UIScrollView and it subview leading/trailing/top/bottom to determine the size of each other, it will appear "has ambiguous scrollable content width /height"'s warning. The correct posture is to determine UIScrollView the size of the subview with an external view or UIScrollView a width/height of its own contentSize . Because UIScrollView my own leading/trailing/top/bottom became useless, I was accustomed to UIScrollView adding a content view between it and its original subviews, and the benefits were:

    • Won't leave error/warning in the storyboard.
    • Provides leading/trailing/top/bottom for Subview, convenient subview layout
    • Adjust the size of the content view (which can be constraint) by adjusting the IBOutletcontentSize
    • No hard code associated with screen size is required
    • Better support to rotation

The AutoLayout in sample demonstrates the UIScrollView example of + Auto Layout.

Uiscrollviewdelegate

UIScrollViewDelegateis UIScrollView the delegate protocol, the UIScrollView interesting function is through its delegate method to achieve. Understanding the conditions that these methods are triggered and the order of the calls UIScrollView is necessary for the use, this article mainly talk about drag related effects, so zoom related methods skip not mentioning, drag the related delegate method in the order of calls are:

- (void)scrollViewDidScroll:(UIScrollView *)scrollView

This method is invoked whenever a change is triggered in any way contentOffset (including user drag, deceleration, direct code Setup, etc.), can be used to monitor contentOffset the changes, and according to the current contentOffset other view to make a follow-up adjustment.

- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView

Called when the user starts to drag the scroll view.

- (void)scrollViewWillEndDragging:(UIScrollView *)scrollView withVelocity:(CGPoint)velocity targetContentOffset:(inout CGPoint *)targetContentOffset

This method was introduced from IOS 5 and was called before Didenddragging, when the Willenddragging method velocity was CGPointZero (no speed in two directions at the end of the drag), the didenddragging in the decelerate NO Without the deceleration process, willbegindecelerating and didenddecelerating will not be called. Conversely, when velocity not CGPointZero , the scroll view slows down until it is at its velocity initial speed targetContentOffset . It is worth noting that here targetContentOffset is a pointer, yes, you can change the deceleration movement of the destination, which is useful when some effect is realized, the Example section will refer to its usage, and compared with other implementation methods.

- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate

is called when the user ends the drag, and decelerate YES there is a deceleration process when the end is dragged. Note that after didenddragging, if there is a deceleration process, the dragging of scroll view is not immediately set NO , but until the deceleration is over, so the actual semantics of this dragging attribute are closer to scrolling< /c13>.

- (void)scrollViewWillBeginDecelerating:(UIScrollView *)scrollView

The deceleration animation is called before it starts.

- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView

Deceleration animation is called at the end, there is a special case: when the deceleration animation is not yet finished again drag scroll view,didenddecelerating will not be called, and at this time scroll view dragging and decelerating properties are YES . The new dragging if there is acceleration, then willbegindecelerating will be called again, and then didenddecelerating, if there are no accelerations, although willbegindecelerating will not be called, However, the previous didenddecelerating will be called, so the order in which the delegate method is called (without didscroll) is likely to be the same if the scroll view is continuously scrolled quickly:

 scrollviewwillbegindragging: ScrollViewWillEndDragging:withVelocity:targetContentOffset:scrollViewDidEndDragging:willDecelerate: scrollviewwillbegindecelerating: scrollviewwillbegindragging: ScrollViewWillEndDragging:withVelocity:targetContentOffset:scrollViewDidEndDragging:willDecelerate: scrollviewwillbegindecelerating: ... scrollviewwillbegindragging:scrollviewwillenddragging:withvelocity: TargetContentOffset:scrollViewDidEndDragging:willDecelerate:  Scrollviewwillbegindecelerating: scrollviewdidenddecelerating:    

Although there are few bugs due to this, you need to know the intermediate state that this very common user action will cause. For example, the method you are trying to UITableViewDataSource tableView:cellForRowAtIndexPath: determine based on TableView's dragging and decelerating attributes can be misjudged when the user drags or decelerates (see Example 1).

The Delegate in Sample simply outputs a few logs, and you can quickly see the order in which these methods are called.

Instance

The use of the above delegate methods is demonstrated and described in more detail below through some examples.

1. Optimization of picture loading logic in Table View

Although this optimization method may seem less necessary in the current function and network environment, but in the first time I saw this method is 09 years (the impression is Tweetie author wrote in 08 blog, may be wrong), thinking back the function of the IPhone 3g/3gs, this method for multi-graph Table VI EW's performance has been a big boost, and it's been my secret weapon. And now, in a mobile network environment, you're still worth it to save users traffic.

Let's talk about the original idea:

    • When the user manually drag the table view, the image in the cell will be loaded;
    • During the slow-down process of the user's rapid sliding, the picture in the cell is not loaded (but the text information is still loaded, which reduces the network overhead and the cost of image loading during deceleration);
    • At the end of the deceleration, load all the visible cell images (if necessary);

Question 1:

Mentioned earlier, at the beginning of the drag, for dragging YES , decelerating for NO ; decelerate process, dragging and decelerating all for YES ; decelerate start the next drag when not finished, dragging and decelerating still YES. So it is impossible to simply pass the table view dragging and decelerating judge whether the user is dragging or slowing down the process.

To solve this problem it is simple to add a variable such as userDragging , in Willbegindragging, set to YES didenddragging NO . tableView: cellForRowAtIndexPath:in the method, the logic of whether the load picture is:

if (!self.userDragging && tableView.decelerating) {      cell.imageView.image = nil;} else { // code for loading image from network or disk}

Question 2:

In doing so, after the decelerate, the cell on the screen is not a picture, it is not difficult to solve the problem, you need a loadImageForVisibleCells way to load the image of the visible cell:

- (void)loadImageForVisibleCells{    NSArray *cells = [self.tableView visibleCells];    for (GLImageCell *cell in cells) { NSIndexPath *indexPath = [self.tableView indexPathForCell:cell]; [self setupCell:cell withIndexPath:indexPath]; }}

Question 3:

This problem may not be easy to find, in the slowdown process if the user starts a new drag, the current screen cell is not loaded (the call order problem mentioned above), and the problem 1 scenario does not solve the problem 3, because these cells are already on the screen, will not be Cellforrowatindexpath method. Although it is not easy to find, but the solution is very simple, just need to be called in the scrollViewWillBeginDragging: method once loadImageForVisibleCells .

Re-optimization

The above method did raise the table view's performance in that era, but you will find that the last slowest fraction second time in the deceleration process will actually make people wait a bit impatient, especially if your App only has pictures with no text. After the introduction of the method in IOS 5, scrollViewWillEndDragging: withVelocity: targetContentOffset: SDWebImage I tried to optimize this method to improve the user experience:

    • If there is a cache of pictures in memory, the picture is also loaded during deceleration
    • If the picture belongs to the targetContentOffset cell that can be seen, the normal load, so that the last screen of the rapid scrolling out of the process, the user can see the target area of the picture gradually loaded
    • You can try to ease the abrupt appearance of harshness with a similar fade in or flip effect (especially if you have a picture-only App like this example)

Core code:

- (void) Scrollviewwillbegindragging: (Uiscrollview *) scrollview{Self. Targetrect =Nil [Self loadimageforvisiblecells];} - (void) Scrollviewwillenddragging: (Uiscrollview *) ScrollView withvelocity: (cgpoint) Velocity Targetcontentoffset: (inout cgpoint *) targetcontentoffset{ cgrect targetrect = CGRectMake (Targetcontentoffset->x, Targetcontentoffset->y, ScrollView. Frame. Size. width, ScrollView. Frame. Size. height); self. targetrect = [Nsvalue valuewithcgrect:targetrect];} -(void) scrollviewdidenddecelerating: (uiscrollview *) scrollview{ self. targetrect = Nil; [Selfloadimageforvisiblecells];}               

Whether you need to load the logic of the picture:

BOOL shouldLoadImage = YES;  if (self.targetRect && !CGRectIntersectsRect([self.targetRect CGRectValue], cellFrame)) { SDImageCache *cache = [manager imageCache]; NSString *key = [manager cacheKeyForURL:targetURL]; if (![cache imageFromMemoryCacheForKey:key]) { shouldLoadImage = NO; }}if (shouldLoadImage) { // load image}

It is even more gratifying to judge whether or not nil , targetRect at the same time played the original userDragging role. The complete code for this example is shown in sample Lazyload

2. Several ways to implement pagination

The use of Uiscrollview there are many ways to achieve paging, but their effects and purposes are not the same, and the difference between method 2 and Method 3 is exactly the same kind of App in imitation of Glow's homepage Bubble flip effect with the Glow experience on the gap (hopefully they won't see this article and and adjust how they are implemented). This example implements a similar scenario in three ways, and you can feel the different user experiences of three implementations by installing to your phone. In order to differentiate the focus of each example, this example does not have a reuse mechanism, and the reuse of the relevant content is shown in Example 3.

2.1 pagingenabled

This is the system-provided paging method, the simplest, but with some limitations:

    • You can only flip the page in frame size, slow down the animation damping, slow down the process of not more than one
    • Need some hacking implement bleeding and padding (that is, there is a padding between page and page, you can see part of the front and back page on the current page)

Sample pagination has a simple implementation of bleeding and padding effect of the code, the main idea is:

    • Make scroll view width of page width + padding, and set clipsToBounds toNO
    • This allows you to see the contents of the front and back pages, but not the touch, so you need another view that covers the desired touch area to achieve the same touch bridging functionality

Application Scenario: The above limitations are also the advantages of this approach, such as the General App Guide page (tutorial), Calendar Month view, can be implemented in this way.

2.2 Snap

This is done in didenddragging and without deceleration animation, or Snap to an integer page when the deceleration animation is complete. The core algorithm uses the current contentoffset to calculate the nearest integer page and its corresponding contentoffset, which is animated snap to the page. The effect of this method is a common problem, that is, the final snap will occur after the end of the decelerate, always feel very abrupt.

2.3 Modifying Targetcontentoffset

Modify the scrollViewWillEndDragging: withVelocity: targetContentOffset: targetContentOffset target offset to an integer page position by modifying the method directly. Where the core code:

- (Cgpoint) Nearesttargetoffsetforoffset: (Cgpoint) offset{CGFloat pageSize = Bubble_diameter + bubble_padding;nsinteger page = roundf (Offset.x/pagesize); cgfloat targetx = pageSize * page; return cgpointmake (targetx, Offset.y);} -(void) scrollviewwillenddragging: (UIScrollView *) ScrollView withvelocity: (cgpoint) velocity Targetcontentoffset: ( inout cgpoint *) targetcontentoffset{ cgpoint targetoffset = [self nearesttargetoffsetforoffset:* Targetcontentoffset]; Targetcontentoffset->x = Targetoffset.x; targetcontentoffset->y = targetOffset< Span class= "hljs-variable" >.Y;}             

Application Scenario: Method 2 and Method 3 principle approximation, the effect is similar, the applicable scene is basically the same, but the experience of Method 3 is much better, the process of Snap to integer page is very natural, or the user is completely unaware of the existence of the snap process. The deceleration process of the two methods is smooth, apply to a screen with multiple pages, but need to slide the whole page of the scene, also applies to the table in the automatic snap to integer days of the scene, but also for each page size is different in the case of Snap to the whole page of the scene (do not make an example, to play, in fact, only need method).

Complete code See pagination

3. Reuse

Most IOS developers should be aware UITableView of the cell reuse mechanism, which reduces the memory overhead and increases the performance, UIScrollView as UITableView the parent class, which in many scenarios is also well suited for application reuse mechanisms (in fact, not just UIScrollView , in any scenario, repeated The elements that appear should be appropriately introduced to the reuse mechanism.

You can refer to UITableView the cell reuse mechanism and summarize the reuse mechanism as follows:

    • Maintain a reuse queue
    • When the element leaves the visible range removeFromSuperview and joins the Reuse queue (enqueue)
    • When new elements need to be added, first try to get reusable elements (dequeue) from the reuse queue and remove from the reuse queue
    • If the queue is empty, create a new element
    • These are generally done in the scrollViewDidScroll: method

In practical use, the points to note are:

    • When reusing objects as view controllers, rememberaddChildeViewController
    • When a view or view controller is reused but its corresponding model changes, it needs to clean up what is left before reuse.
    • Data can be properly cached, attempts to read data from the cache when reused, or even previous states (such as the contentoffset of Table view) for a better user experience
    • When the number of elements on the screen can be determined, it is sometimes possible to init these elements in advance, without encountering the lag in the scroll process due to the init overhead (especially when using the view controller as the Reuse object)

The scenario in Example 2 is well suited to view as a reusable unit, and this example adds an example of using view controller as a reusable object, which demonstrates the linkage effect, as shown in the next example.

Complete code See reuse

4. Linkage/parallax Scrolling

In the previous example, the scroll view in main scroll view and title view is a linkage example, the so-called linkage, is when a scroll, in scrollViewDidScroll: accordance with a contentOffset dynamic calculation of B contentOffset and set to B. Also for non-scroll view c, you can dynamically calculate the C frame or transform (Glow bubble as an example) to achieve parallax scrolling or other advanced animation, which is now used in many applications of the guide page.

Linkage/parallax Scrolling part of the principle is actually relatively simple, no longer repeat, wrote a simple example Parallax.

Written in the last

Unconsciously wrote a lot about UIScrollView the content, in fact, there are many can be written, because the time relationship had to stop the pen. In my opinion, it UIScrollView 's like providing a way to jump off a two-dimensional space, and if you have enough imagination, it can help you achieve a richer user experience beyond the bounds of the plane. It was also intended to write a comprehensive example, but since the time relationship has not been completed, there will be time to update later.

In addition, there may be errors or improvements in the example, and you are welcome to mention Issue or PR directly on GitHub.

Uiscrollview Practical Experience

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.