Scroll view paging
The pagingEnabled property of UIScrollView is used to control whether to scroll by page. This feature is used in a number of applications, the most typical being the app icon list on the mobile desktop. In these interfaces, each page function is often independent, and the system also provides a UIPageViewController to achieve this paging scrolling function. The UI implementation for paging scrolling is typically the outermost UIScrollView. And then inside UIScrollView is an overall containerView, containerView. Container view adds N page views, and for horizontal paging scrolling the container view is the same height as the scroll view, and the width is the width of the scroll view times the number of page views, and the page view is the same size as the scroll view, and for vertical paging scrolling the container view is the same width as the scroll view, The height is the height of the scroll view multiplied by the number of page views, and the page views are the same size as the scroll view. Each page view adds its own entry view. The overall effect is as follows:
AutoLayout implements paging scrolling methods
Based on the UI structure above, here we use AutoLayout code to achieve horizontal paging scrolling. The constraint setting code here is the API that comes with iOS9.
- (void)loadView {
UIScrollView *scrollView = [[UIScrollView alloc] init];
if(@ the available (iOS 11.0. *)) {scrollView. ContentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever; }else{ // Fallback on earlier versions } scrollView.pagingEnabled = YES; scrollView.backgroundColor = [UIColor whiteColor]; self.view = scrollView; UIView *containerView = [UIView new]; containerView.translatesAutoresizingMaskIntoConstraints = NO; [scrollView addSubview:containerView]; // Set the container's four boundaries to be consistent with the scroll view constraints. [containerView.leftAnchor constraintEqualToAnchor:scrollView.leftAnchor].active = YES; [containerView.topAnchor constraintEqualToAnchor:scrollView.topAnchor].active = YES; [containerView.rightAnchor constraintEqualToAnchor:scrollView.rightAnchor].active = YES; [containerView.bottomAnchor constraintEqualToAnchor:scrollView.bottomAnchor].active = YES; // The height of the container view is the same as that of the scroll view. [containerView.heightAnchor constraintEqualToAnchor:scrollView.heightAnchor].active = YES; NSArray<UIColor*> *colors = @[[UIColor redColor],[UIColor greenColor], [UIColor blueColor]]; NSMutableArray<UIView*> *pageViews = [NSMutableArray arrayWithCapacity:colors.count]; NSLayoutXAxisAnchor *prevLeftAnchor = containerView.leftAnchor;for(int i = 0; i < colors.count; I++) {// create pageView UIView *pageView = [UIView new]; pageView.backgroundColor = colors[i]; pageView.translatesAutoresizingMaskIntoConstraints = NO; [containerView addSubview:pageView]; // Page views are arranged from left to right, with the left constraint on page 1 being the left of the container view and the left constraint on other pages being the right of the previous sibling view. [pageView.leftAnchor constraintEqualToAnchor:prevLeftAnchor].active = YES; // The top constraint on each page is the container view. [pageView.topAnchor constraintEqualToAnchor:containerView.topAnchor].active = YES; / / constraint is the width of each page scroll view [pageView. WidthAnchor constraintEqualToAnchor: scrollView. WidthAnchor]. Active = YES; / / constraint is the height of each page scroll view [pageView. HeightAnchor constraintEqualToAnchor: scrollView. HeightAnchor]. Active = YES; prevLeftAnchor = pageView.rightAnchor; [pageViews addObject:pageView]; } // The key step, if you need to scroll left or right, is to move the rightmost subview of the container view, where the right edge of B depends on the right edge of the container view. [pageViews.lastObject.rightAnchor constraintEqualToAnchor:containerView.rightAnchor].active = YES; // You can add a different entry view for each page view. }Copy the code
Here is a run-time rendering:
MyLayout implements paging scrolling methods
You can also use the MyLayout library to implement paging scrolling capabilities. MyLayout library is an open source UI layout library with powerful functions. You can download it from github address: github.com/youngsoft/M… Download or import from podfile:
pod 'MyLayout'
Copy the code
To use MyLayout. Here is the code for paging scrolling using MyLayout.
//
#import <MyLayout.h>
- (void)loadView {
UIScrollView *scrollView = [[UIScrollView alloc] init];
if(@ the available (iOS 11.0. *)) {scrollView. ContentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever; }else{ // Fallback on earlier versions } scrollView.pagingEnabled = YES; scrollView.backgroundColor = [UIColor whiteColor]; self.view = scrollView; / / create a horizontal linear layout container view MyLinearLayout * containerView = [MyLinearLayout linearLayoutWithOrientation: MyOrientation_Horz]; containerView.myVertMargin = 0; // The upper and lower boundaries of the horizontal linear layout are consistent with the scrolling view, where the height of the linear layout is also determined. containerView.gravity = MyGravity_Vert_Fill | MyGravity_Horz_Fill; // Sets the height and width of all subviews in the linear layout to evenly divide and fill the linear layout. [scrollView addSubview:containerView]; NSArray<UIColor*> *colors = @[[UIColor redColor],[UIColor greenColor], [UIColor blueColor]]; NSMutableArray<UIView*> *pageViews = [NSMutableArray arrayWithCapacity:colors.count];for(int i = 0; i < colors.count; I++) {// create pageView UIView *pageView = [UIView new]; pageView.backgroundColor = colors[i]; [containerView addSubview:pageView]; // Because linear layouts determine the height and width of the subpage view by setting the gravity property, plus linear layouts do not require any additional constraints on the page view. [pageViews addObject:pageView]; } / / crucial step, set the width of the linear layout is in multiples of the scroll view containerView widthSize. EqualTo (scrollView. WidthSize), multiply (colors. Count); // You can add a different entry view for each page view. }Copy the code
MyLayout implements the pagination function of the icon list on the desktop
MyLayout has similar capabilities to flex-Box, if not more. Streaming layout is used in some scenarios where subviews are arranged regularly, such as the ability to scroll through a paged list of ICONS in this example. The following is the concrete implementation code.
- (void)loadView {
UIScrollView *scrollView = [[UIScrollView alloc] init];
if(@ the available (iOS 11.0. *)) {scrollView. ContentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever; }else{ // Fallback on earlier versions } scrollView.pagingEnabled = YES; scrollView.backgroundColor = [UIColor whiteColor]; self.view = scrollView; // Create a vertical quantity-constrained streaming layout: 3 sub-views per column, 9 sub-views per page, scrolling from left to right. MyFlowLayout *containerView = [MyFlowLayout flowLayoutWithOrientation:MyOrientation_Vert arrangedCount:3]; containerView.pagedCount = 9; // When pagedCount is set to non-0, page display function begins. Here, 9 sub-views are displayed per page. This number must be a multiple of arrangedCount. containerView.wrapContentWidth = YES; // Sets the width of the layout view to be wrapped by subviews. When this property is set to YES for vertical streaming layouts and used in conjunction with pagedCount, pages scroll left to right. containerView.myVertMargin = 0; // The height of the container view is the same as that of the scroll view. containerView.subviewHSpace = 10; containerView.subviewVSpace = 10; // Sets the horizontal and vertical spacing of the subviews. containerView.padding = UIEdgeInsetsMake(5, 5, 5, 5); // Layout view inside margin Settings. [scrollView addSubview:containerView]; // Create an entry viewfor (int i = 0; i < 40; i++)
{
UILabel *label = [UILabel new];
label.textAlignment = NSTextAlignmentCenter;
label.backgroundColor = [UIColor greenColor];
label.text = [NSString stringWithFormat:@"%d",i]; [containerView addSubview:label]; } // Get horizontal size classes for the streaming layout, and set the number of devices per row to 6 from 3, and the number of devices per page to 18 from 9 when the device is in landscape. MyFlowLayout *containerViewSC = [containerView fetchLayoutSizeClass:MySizeClass_Landscape copyFrom:MySizeClass_wAny | MySizeClass_hAny]; containerViewSC.arrangedCount = 6; containerViewSC.pagedCount = 18;Copy the code
The above code shows the ability to implement a page-scrolling list of ICONS by setting some properties on the streaming layout that acts as a container view, without any constraints on the entries, and by supporting a different number of displays per page under vertical and horizontal screens. The whole function is less code, compared with UICollectionView to achieve the same function to be concise and much easier. Here’s what it looks like:
Switching between horizontal and vertical screens
For a scrolling view with pagination, when you need to support vertical or horizontal scrolling, you might end up with the interface stuck between two pages instead of scrolling by page. The reason for this is that both paging and non-paging scrolling is achieved by adjusting the contentOffset of the scrolling view when scrolling. The corresponding contentOffset value is not adjusted when the scrolling view switches between vertical and horizontal, which results in an abnormal scrolling position when the screen orientation changes. The solution is to fix this problem by modifying the value of contentOffset in the corresponding callback handler as the screen scrolls. For example, we could add the following code to the protocol methods of the screen switching Sizeclass view controller:
- (void)traitCollectionDidChange:(nullable UITraitCollection *)previousTraitCollection { [super traitCollectionDidChange:previousTraitCollection]; UIScrollView *scrollView = (UIScrollView*)self.view; / / adjust to the correct according to the current contentOffset contentOffset int pageIndex = scrollView. ContentOffset. X/scrollView. Frame. The size. The width; int pages = scrollView.contentSize.width / scrollView.frame.size.width;if (pageIndex >= pages)
pageIndex = pages - 1;
if (pageIndex < 0)
pageIndex = 0;
scrollView.contentOffset = CGPointMake(pageIndex * scrollView.frame.size.width, scrollView.contentOffset.y);
}
Copy the code