A deep understanding of UIScrollView in iOS development

Source: Internet
Author: User

I'm Mike Ash's Let's Build... Fans of the series of articles, in which he designed Cocoa controls from the ground up to explain how they work. Here I want to do something similar and use a few lines of code to implement my own rolling attempt. First, let's take a look at how the coordinate system in UIKit works. If you are only interested in the Code Implementation of the rolling attempt, you can skip the next section with confidence. Each View in the UIKit coordinate system defines its own coordinate system. As shown in, the X axis points to the right, and the Y axis points to the bottom:

Note that this logical coordinate system does not focus on the width and height of the View contained in it. The entire coordinate system has no boundaries extending infinitely around. We place four sub-views in the coordinate system. Each color block represents a View:

The code for adding a View is as follows:

 
 
  1. UIView *redView = [[UIView alloc] initWithFrame:CGRectMake(20, 20, 100, 100)]; 
  2. redView.backgroundColor = [UIColor colorWithRed:0.815 green:0.007 
  3.     blue:0.105 alpha:1]; 
  4.   
  5. UIView *greenView = [[UIView alloc] initWithFrame:CGRectMake(150, 160, 150, 200)]; 
  6. greenView.backgroundColor = [UIColor colorWithRed:0.494 green:0.827 
  7.     blue:0.129 alpha:1]; 
  8.   
  9. UIView *blueView = [[UIView alloc] initWithFrame:CGRectMake(40, 400, 200, 150)]; 
  10. blueView.backgroundColor = [UIColor colorWithRed:0.29 green:0.564 
  11.     blue:0.886 alpha:1]; 
  12.   
  13. UIView *yellowView = [[UIView alloc] initWithFrame:CGRectMake(100, 600, 180, 150)]; 
  14. yellowView.backgroundColor = [UIColor colorWithRed:0.972 green:0.905 
  15.     blue:0.109 alpha:1]; 
  16.   
  17. [mainView addSubview:redView]; 
  18. [mainView addSubview:greenView]; 
  19. [mainView addSubview:blueView]; 
  20. [mainView addSubview:yellowView]; 
Bounds

Apple's document on UIView describes the attributes of bounds as follows:

Bounds rectangle... The position and size of the view in its own coordinate system.

A View can be seen as a window or a visible area of a rectangle defined on the plane of its coordinate system. The View boundary indicates the position and size of the visible area of the rectangle.

Suppose our View is 320 pixels in width, 480 pixels in height, and the origin is 0, 0 ). This View becomes the observation port of the plane of the whole coordinate system. It shows only a small part of the plane. The region located outside the View boundary still exists, but is hidden.

A View provides an observation port for its plane. The bounds rectangle of the View describes the location and size of the area.

Frame

Next, we will try to modify the coordinates of the bounds origin:

 
 
  1. CGRect bounds = mainView.bounds; 
  2. bounds.origin = CGPointMake(0, 100); 
  3. mainView.bounds = bounds; 

After we set the bound origin to 0,100), the entire screen looks like this:

Modifying the bounds origin is equivalent to moving the visible area on the plane.

It seems that this View has moved 100 pixels down, which is true in the View's own coordinate system. However, the actual position of the View on the screen is more accurate to the position on its parent View.) In fact, this is not changed because it is determined by the frame attribute of the View and has not changed:

Frame rectangle... Defines the position and size of the View in its parent View coordinate system.

Because the position of the View is relatively fixed, you can think of the entire coordinate plane as a transparent canvas that we can drag up and down, and think of this View as a window for us to observe the coordinate plane. Adjusting the Bounds attribute of a View is equivalent to dragging the canvas, so the following content can be observed in our View:

Since the view's position is fixed (from its own perspective), think of the coordinate system plane as a piece of transparent film we can drag around, and of the view as a fixed window we are looking through. adjustingbounds'S origin is equivalent to moving the transparent film such that another part of it becomes visible through the view:

Modifying the bounds origin coordinate is also equivalent to dragging the entire coordinate system up. Because the frame of the View has not changed, its position relative to the parent View has not changed.

In fact, this is what happens when UIScrollView slides. Note: from the perspective of a user, he thought that when the child View in this View was moving, their position in the coordinate system was not changed.

Create your UIScrollView

A scroll view does not need the coordinates of Its Neutron View to scroll them. The only thing you need to do is change its bounds attributes. With this in mind, it is no longer difficult to implement a simple scroll view. We use a gesture recognizer to identify the user's drag operation and change the bounds origin point based on the user's drag offset:

 
 
  1. // CustomScrollView.h 
  2. @import UIKit; 
  3.   
  4. @interface CustomScrollView : UIView 
  5.   
  6. @property (nonatomic) CGSize contentSize; 
  7.   
  8. @end 
  9.   
  10. // CustomScrollView.m 
  11. #import "CustomScrollView.h" 
  12.   
  13. @implementation CustomScrollView 
  14.   
  15. - (id)initWithFrame:(CGRect)frame 
  16.     self = [super initWithFrame:frame]; 
  17.     if (self == nil) { 
  18.         return nil; 
  19.     } 
  20.     UIPanGestureRecognizer *gestureRecognizer = [[UIPanGestureRecognizer alloc] 
  21.         initWithTarget:self action:@selector(handlePanGesture:)]; 
  22.     [self addGestureRecognizer:gestureRecognizer]; 
  23.     return self; 
  24.   
  25. - (void)handlePanGesture:(UIPanGestureRecognizer *)gestureRecognizer 
  26.     CGPoint translation = [gestureRecognizer translationInView:self]; 
  27.     CGRect bounds = self.bounds; 
  28.   
  29.     // Translate the view's bounds, but do not permit values that would violate contentSize 
  30.     CGFloat newBoundsOriginX = bounds.origin.x - translation.x; 
  31.     CGFloat minBoundsOriginX = 0.0; 
  32.     CGFloat maxBoundsOriginX = self.contentSize.width - bounds.size.width; 
  33.     bounds.origin.x = fmax(minBoundsOriginX, fmin(newBoundsOriginX, maxBoundsOriginX)); 
  34.   
  35.     CGFloat newBoundsOriginY = bounds.origin.y - translation.y; 
  36.     CGFloat minBoundsOriginY = 0.0; 
  37.     CGFloat maxBoundsOriginY = self.contentSize.height - bounds.size.height; 
  38.     bounds.origin.y = fmax(minBoundsOriginY, fmin(newBoundsOriginY, maxBoundsOriginY)); 
  39.   
  40.     self.bounds = bounds; 
  41.     [gestureRecognizer setTranslation:CGPointZero inView:self]; 
  42.   
  43. @end 

Like the real UIScrollView, our class also has a contentSize attribute. You must set this value from the outside to specify the scrolling area, when we change the bounds size, we need to ensure that the set value is valid.

Result:

Our scroll view is ready to work, but there is still a lack of momentum scrolling, the rebound effect and a scroll prompt.

Summary

Thanks to the features of the coordinate system of UIKit, it took us 30 lines of code to reproduce the essence of UIScrollView. Of course, the real UIScrollView is much more complicated than what we have done and has a rebound effect, momentum rolling, amplification attempts, and proxy methods, which are not covered here.

Update 5/2, 2014: the code in this article is at https://github.com/ole/customscrollview.

Update 5/8, 2014:

1. the coordinate system does not extend infinitely. The range of the coordinate system is determined by the length of CGFloat, which is usually a large value, depending on the 32-bit and 64-bit systems.

2. In fact, unless you set clipToBounds = YES, all the parts beyond the child View are actually visible. However, the View does not detect excessive touch events.

Http://blog.jobbole.com/70143/.

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.