iOS用AutoLayout实现分页滚动功能

滚动视图分页

UIScrollView的pagingEnabled属性用于控制是否按分页进行滚动。在一些应用中会应用到这一个特性,最典型的就是手机桌面的应用图标列表。这些界面中往往每一页功能都比较独立,系统也提供了UIPageViewController来实现这种分页滚动的功能。

实现分页滚动的UI实现一般是最外层一个UIScrollView。然后UIScrollView里面是一个总体的容器视图containerView。容器视图添加N个页视图,对于水平分页滚动来说容器视图的高度和滚动视图一样,而宽度则是滚动视图的宽度乘以页视图的数量,页视图的尺寸则和滚动视图保持一致,对于垂直分页滚动来说容器视图的宽度和滚动视图一样,而高度则是滚动视图的高度乘以页视图的数量,页视图的尺寸则和滚动视图保持一致。每个页视图中在添加各自的条目视图。

整体效果图如下:

AutoLayout实现分页滚动的方法

根据上面的UI结构这里用AutoLayout的代码来实现水平分页的滚动。这里的约束设置代码是iOS9以后提供的相关API。

- (void)loadView {

 UIScrollView *scrollView = [[UIScrollView alloc] init];
 if (@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];

 //设置容器的四个边界和滚动视图保持一致的约束。
 [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;
 //容器视图的高度和滚动视图保持一致。
 [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++)
 {
 //建立页视图
 UIView *pageView = [UIView new];
 pageView.backgroundColor = colors[i];
 pageView.translatesAutoresizingMaskIntoConstraints = NO;
 [containerView addSubview:pageView];

 //页视图分别从左往右排列,第1页的左边约束是容器视图的左边,其他页的左边约束则是前面兄弟视图的右边。
 [pageView.leftAnchor constraintEqualToAnchor:prevLeftAnchor].active = YES;
 //每页的顶部约束是容器视图。
 [pageView.topAnchor constraintEqualToAnchor:containerView.topAnchor].active = YES;
 //每页的宽度约束是滚动视图
 [pageView.widthAnchor constraintEqualToAnchor:scrollView.widthAnchor].active = YES;
 //每页的高度约束是滚动视图
 [pageView.heightAnchor constraintEqualToAnchor:scrollView.heightAnchor].active = YES;

 prevLeftAnchor = pageView.rightAnchor;

 [pageViews addObject:pageView];

 }

 //关键的一步,如果需要左右滚动则将容器视图中的最右部子视图这里是B的右边边界依赖于容器视图的右边边界。
 [pageViews.lastObject.rightAnchor constraintEqualToAnchor:containerView.rightAnchor].active = YES;

 //这里可以为每个页视图添加不同的条目视图,具体实现大家自行添加代码吧。

}

下面是运行时的效果图:

MyLayout实现分页滚动的方法

你也可以用MyLayout布局库来实现分页滚动的能力。MyLayout布局库是笔者开源的一套功能强大的UI布局库。

您可以从github地址: github.com/youngsoft/M… 下载或者从podfile中导入:

pod 'MyLayout'

来使用MyLayout。下面是具体用MyLayout来实现分页滚动的代码。

//
#import <MyLayout.h>

- (void)loadView {

 UIScrollView *scrollView = [[UIScrollView alloc] init];
 if (@available(iOS 11.0, *)) {
 scrollView.contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever;
 } else {
 // Fallback on earlier versions
 }
 scrollView.pagingEnabled = YES;
 scrollView.backgroundColor = [UIColor whiteColor];
 self.view = scrollView;

 //建立一个水平线性布局容器视图
 MyLinearLayout *containerView = [MyLinearLayout linearLayoutWithOrientation:MyOrientation_Horz];
 containerView.myVertMargin = 0; //水平线性布局的上下边界和滚动视图保持一致,这里也会确定线性布局的高度。
 containerView.gravity = MyGravity_Vert_Fill | MyGravity_Horz_Fill; //设置线性布局中的所有子视图均分和填充线性布局的高度和宽度。
 [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++)
 {
 //建立页视图
 UIView *pageView = [UIView new];
 pageView.backgroundColor = colors[i];
 [containerView addSubview:pageView];

 //因为线性布局通过属性gravity的设置就可以确定子页视图的高度和宽度,再加上线性布局的特性,所以页视图不需要设置任何附加的约束。

 [pageViews addObject:pageView];

 }

 //关键的一步, 设置线性布局的宽度是滚动视图的倍数
 containerView.widthSize.equalTo(scrollView.widthSize).multiply(colors.count);

 //这里可以为每个页视图添加不同的条目视图,具体实现大家自行添加代码吧。

}

MyLayout实现桌面的图标列表分页功能

MyLayout中的流式布局MyFlowLayout所具备的能力和flex-box相似,甚至有些特性要强于后者。流式布局用于一些子视图有规律排列的场景,就比如本例子中的滚动分页的图标列表的能力。下面就是具体的实现代码。

- (void)loadView {

 UIScrollView *scrollView = [[UIScrollView alloc] init];
 if (@available(iOS 11.0, *)) {
  scrollView.contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever;
 } else {
  // Fallback on earlier versions
 }
 scrollView.pagingEnabled = YES;
 scrollView.backgroundColor = [UIColor whiteColor];
 self.view = scrollView;

 //建立一个垂直数量约束流式布局:每列展示3个子视图,每页展示9个子视图,整体从左往右滚动。
 MyFlowLayout *containerView = [MyFlowLayout flowLayoutWithOrientation:MyOrientation_Vert arrangedCount:3];
 containerView.pagedCount = 9; //pagedCount设置为非0时表示开始分页展示的功能,这里表示每页展示9个子视图,这个数量必须是arrangedCount的倍数。
 containerView.wrapContentWidth = YES; //设置布局视图的宽度由子视图包裹,当垂直流式布局的这个属性设置为YES,并和pagedCount搭配使用会产生分页从左到右滚动的效果。
 containerView.myVertMargin = 0; //容器视图的高度和滚动视图保持一致。

 containerView.subviewHSpace = 10;
 containerView.subviewVSpace = 10; //设置子视图的水平和垂直间距。
 containerView.padding = UIEdgeInsetsMake(5, 5, 5, 5); //布局视图的内边距设置。
 [scrollView addSubview:containerView];

 //建立条目视图
 for (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];
 }

 //获取流式布局的横屏size classes,并且设置设备处于横屏时,每排数量由3个变为6个,每页的数量由9个变为18个。
 MyFlowLayout *containerViewSC = [containerView fetchLayoutSizeClass:MySizeClass_Landscape copyFrom:MySizeClass_wAny | MySizeClass_hAny];
 containerViewSC.arrangedCount = 6;
 containerViewSC.pagedCount = 18;

从上面的代码可以看出要实现分页滚动的图标列表的能力,主要是对充当容器视图的流式布局设置一些属性即可,不需要为条目设置任何约束,而且还支持横竖屏下每页的不同数量的展示能力。整个功能代码量少,对比用UICollectionView来实现相同的功能要简洁和容易得多。下面是程序运行的效果:

横竖屏切换

对于带有分页功能的滚动视图来说,当需要支持横竖屏时就有可能会出现横竖屏切换时界面停留在两个页面中间而不是按页进行滚动的效果。其原因是无论是分页滚动还是不分页滚动,在滚动时都是通过调整滚动视图的contentOffset来实现的。而当滚动视图进行横竖屏切换时不会调整对应的contentOffset值,这样就导致了在屏幕方向切换时的滚动位置出现异常。解决的办法就是在屏幕滚动时的相应回调处理方法中修正这个contentOffset的值来解决这个问题。比如我们可以在屏幕切换的sizeclass变化的视图控制器的协议方法中添加如下代码:

- (void)traitCollectionDidChange:(nullable UITraitCollection *)previousTraitCollection
{
 [super traitCollectionDidChange:previousTraitCollection];

 UIScrollView *scrollView = (UIScrollView*)self.view;

 //根据当前的contentOffset调整到正确的contentOffset
 int pageIndex = scrollView.contentOffset.x / scrollView.frame.size.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);

}

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,谢谢大家对我们的支持。

(0)

相关推荐

  • iOS中关于Swift UICollectionView横向分页的问题

    下面通过图文并茂的形式给大家介绍UICollectionView横向分页的问题,具体内容详情如下所示: 情况 直接看图 滚前 滚后 已经设置collectionView的isPagingEnabled为true了,可是出现了这种情况,原因就是collectionView的contentSize不够. <UICollectionView: 0x7fc565076000; frame = (0 0; 375 197); clipsToBounds = YES; gestureRecognizers

  • iOS 高效的分页加载实现示例

    今天在review代码的时候发现之前的tableview 和 collectview 的分页加载逻辑还有优化的余地,于是进行了优化. 一.tableview的分页加载的代码对比 没有优化之前的代码如下: [strongSelf.tableView.mj_footer endRefreshing]: [strongSelf.articleArr addObjectsFromArray:feedList]; [strongSelf.tableView reloadData]; 优化之后的代码如下:

  • iOS App开发中的UIPageControl分页控件使用小结

    分页控件是一种用来取代导航栏的可见指示器,方便手势直接翻页,最典型的应用便是iPhone的主屏幕,当图标过多会自动增加页面,在屏幕底部你会看到原点,用来只是当前页面,并且会随着翻页自动更新. 一.创建 复制代码 代码如下: UIPageControl* myPageControl = [[UIPageControl alloc]initWithFrame:CGRectMake(0.0, 400.0, 320.0, 0.0)]; 二.设置属性 页面数目 复制代码 代码如下: myPageContr

  • iOS Swift UICollectionView横向分页滚动,cell左右排版问题详解

    情况 Swift对于一门新的iOS编程语言,他的崛起是必然的,我们这群老程序员们学习新的技能也是必然的,不接受新技能将被这大群体无情的淘汰. 最近因为工作的需求,在做表情键盘时遇到一个问题,我用UICollectionView来布局表情,使用横向分页滚动,但在最后一页出现了如图所示的情况 情况分析图 是的,现在的item分布就是这个鬼样子 现在想要做的,就是将现在这个鬼样子变成另外一种样子,如图 那怎么办?只好重新布局item了 解决方案 我是自定了一个Layout(LXFChatEmotion

  • iOS中的AutoLayout使用实践总结

    前言 AutoLayout非常强大也非常易用,可读性也很强,加上各种第三方AutoLayout库,让你布起局来犹如绷掉链子的狗!但在使用中也有各种各样的问题,下面就来给大家详细介绍下. AutoLayout 问题 布局冲突 固有尺寸冲突 布局和固有尺寸冲突 主要概念 固有尺寸 intrinsicContentSize(意思就是说我知道自己的大小,如果你没有为我指定大小,我就按照这个大小来.) hugging,compress priority constraint:equal,unequal 一

  • iOS如何跳转到App Store下载评分页面示例代码

    前言 目前很多应用是要求点击事件直接跳转到App Store,最近工作中就遇到了一个跳转 App Store 评分或者下载更新的功能,网上查到很多跳转方法,这里记录一下,下面话不多说了,来一起看看详细的介绍吧. 主要跳转方法有两种 使用官方 StoreKit.framework 框架 应用间跳转直接跳到 App Store 应用,并携带自己 App 的 AppID. 使用官方框架 苹果提供了StoreKit.framework框架,工程中可以导入这个框架的主头文件 #import <StoreK

  • iOS用AutoLayout实现分页滚动功能

    滚动视图分页 UIScrollView的pagingEnabled属性用于控制是否按分页进行滚动.在一些应用中会应用到这一个特性,最典型的就是手机桌面的应用图标列表.这些界面中往往每一页功能都比较独立,系统也提供了UIPageViewController来实现这种分页滚动的功能. 实现分页滚动的UI实现一般是最外层一个UIScrollView.然后UIScrollView里面是一个总体的容器视图containerView.容器视图添加N个页视图,对于水平分页滚动来说容器视图的高度和滚动视图一样,

  • 利用iOS实现系统相册大图浏览功能详解

    前言 本文主要给大家介绍了关于iOS实现系统相册大图浏览功能的相关资料,分享出来供大家参考学习,下面话不多说了,来一起看看详细的介绍吧. 最终效果图 大图浏览 实现过程 创建两个UICollectionView分别放置大图和缩略图 实现大图和缩略图的联动 实现当前展示的大图对应的缩略图放大效果 实现原理 创建collectionView非常简单,只要正常创建就好,值得注意的是:由于需要当前展示的图片的缩略图始终保持在屏幕中间位置,所以在创建缩略图的collectionView的时候需要对coll

  • iOS实现简单的头部缩放功能

    本文通过实例代码给大家介绍了iOS实现简单的头部缩放功能.实现思路有头部视图,滚动视图,控制头部动画等多个示例代码块,大家可以参考下本文. 简单实现并集成一个头部缩放的功能,适用于UIScrollView以及其子类. 头部伴随模糊效果放大缩小,并在一定位置时悬停充当导航栏.这里提供实现思路,如有符合可直接使用. 效果如下图. 实现: 首先分解为两部分,一部分为头部视图,一部分为滚动视图.头部视图负责展示,滚动视图负责控制头部视图如何展示,比如放大和缩小. 一:头部视图 头部视图拆解为负责展示图片

  • iOS使用UICollectionView实现横向滚动照片效果

    本文实例为大家分享了iOS使用UICollectionView实现横向滚动展示照片的具体代码,供大家参考,具体内容如下 这是Demo链接 效果图 思路 1. 界面搭建 界面的搭建十分简单,采用UICollectionView和自定义cell进行搭建即可. // ViewController.m // 下面使用到的宏和全局变量 #define ScreenW [UIScreen mainScreen].bounds.size.width #define ScreenH [UIScreen main

  • kkpager 实现ajax分页查询功能

    前台分页数据,适合数据少量的时候,因为分页的数据是从后台获取的,大数据的话不建议使用 先看下前台代码: @{ Layout = null; } <!DOCTYPE html> <html> <head> <meta name="viewport" content="width=device-width" /> <script src="~/kkpager/lib/jquery-1.10.2.min.js

  • 原生javascript实现的全屏滚动功能示例

    本文实例讲述了原生javascript实现的全屏滚动功能.分享给大家供大家参考,具体如下: 原理: 1. 计算当前浏览器屏幕高度,每次翻页显示的内容高度即为屏幕高度 2. 对鼠标滚轮事件进行监听,注意滚轮事件的浏览器兼容问题. 废话不多说,直接上代码 html代码: <div id="wrap"> <div id="main" style="top: 0;"> <div class="content num

  • iOS高仿微信表情输入功能代码分享

    最近项目需求,要实现一个类似微信的的表情输入,于是把微信的表情扒拉出来,实现了一把.可以从这里下载源码.看起来表情输入没有多少东西,不外乎就是用NSTextAttachment来实现图文混排,结果在实现的过程中遇到了很多小问题,接下来会一一介绍遇到过的坑.先上一张效果图: 一.实现表情选择View(WKExpressionView) 具体的实现就不细说了,主要功能就是点击表情时,将对应表情的图片名称通知给delegate. 二.实现表情textView(WKExpressionTextView)

  • iOS开发之自定义图片拉伸功能

    需求 为了减小app体积,同时为了适配不同尺寸屏幕或不同应用场景,很多图片素材都是标准通用的,比如IM消息气泡.按钮阴影效果等,但直接使用这些素材会产生一些问题,假如我们需要实现以下效果,即使用图片为账号密码输入框添加阴影效果: 图片素材: 直接使用图片实现的效果与需求效果对比: 经过自定义拉伸调整过后,最终效果: 实现 将storyboard中的控件关联到代码文件中,accountTextBgImageView 为textFiled 下的背景图片视图,实现代码如下: UIImage *text

  • iOS中仿QQ侧滑菜单功能

    UITabBarController做QQ侧滑菜单效果: 首先要了解UITabBarController的层级结构: UITabBarController加载的其它UIViewController的View都是被添加在UITransitionView上(这是一个私有API),UITransitionView在self.view的0层,UITabBar在的第一层. 所以我的思路是这样的: UITransitionView与UITabBar转移到一个新的View1上去,作为滑动的部分: 在View1

随机推荐