前言

随着业务的发展,页面的复杂度越来越高,嵌套滚动视图的方式也越来越受设计师们的青睐,在各大电商App十分常见。如下Demo图:

但是这样的交互官方并不推荐,而且对开发来说确是不那么友好,需要处理滚动手势的冲突,页面的多层级嵌套都给开发带来了一定程度的麻烦。接下里我聊聊我们的实现思路。

思路和过程

对应这种页面结构应该毫无疑问是最底层是一个纵向滚动的scrollView,它的页面上面放一个固定高度的header,紧接着下面一个支持横向滚动切换的容器scrollView,容器上面才是各个页面具体的tableView,如下图:

思路一

最先想到的是,既然是滚动视图那么我们是否可以通过滚动视图的可滚动属性来做呢,在初始时把最上层具体业务的tableView禁止滚动,那么根据事件响应链,滚动事件事件会由底层的ScrollView接收并处理,在到达最大偏移量之后,禁用底层的ScrollView滚动,同时开启上层的tableView,使得上层可以滑动,想起来是有一定可行性的,可惜,事实现实是残酷的,效果如下:

这样会导致当偏移量到达临界值时,由于设置了scrollEnable属性和最大偏移量,此次滚动手势会被截断,需要再次拖拽才能继续滚动,显然,这样的效果是无法接受的。

思路二

这是同事提供的思路,在做这个时和同事有过讨论,他们之前有这样的交互页面,使用的是自定义手势,但由于UIScrollView是有弹性效果的,一般的滑动手势做不到这一点的,所以需要引入UIDynamic模拟力场,实现阻尼效果。想了一下,虽然有一定的可行性,但是为了一个联动滑动,要做这么多的事情,感觉比较繁琐,而且自定义手势做的模拟弹性效果可能和原生ScrollView的效果还是有一定的差距,所以选择放弃。

思路三

回到我们思路一,除了边界位置会阻断联动滚动外,其他效果还是可以的,那么能不能通过手段解决这个问题呢?既然能写到了这里,那么毫无疑问,肯定是可以的。通过手势穿透,即让一个滑动手势既作用于底层的ScrollView又能作用于上层的业务tableView,同时控制他们的滚动即可达成目的。通过让底层的scrollView实现一个手势识别的协议,同时响应滚动事件:

func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {
 return true
 }

根据官方文档描述:

Asks the delegate if two gesture recognizers should be allowed to recognize gestures simultaneously.

表达的意思是询问委托是否允许两个手势识别器同时识别手势,那么我们实现这个协议,”穿透“手势,分别在底层容器和上层业务中实现滚动视图的代理方法func scrollViewDidScroll(_ scrollView: UIScrollView),分别控制他们的可滚动状态和偏移量则能实现目的。部分实现如下:

底层容器ScrollView:

func scrollViewDidScroll(_ scrollView: UIScrollView) {
  headerView.isHidden = scrollView.contentOffset.y >= maxOffset ? true : false
  if !superCanScroll {
   scrollView.contentOffset.y = maxOffset
   currentVC.childCanScroll = true
  } else {
   if scrollView.contentOffset.y >= maxOffset {
    scrollView.contentOffset.y = maxOffset
    superCanScroll = false
    currentVC.childCanScroll = true
   }
  }
 }

上层业务tableView:

func scrollViewDidScroll(_ scrollView: UIScrollView) {
  if !childCanScroll {
   scrollView.contentOffset.y = 0
  } else {
   if scrollView.contentOffset.y <= 0 {
    childCanScroll = false
    superCanScrollBlock?(true)
   }
  }
 }

通过底层ScrollView是否达到最大偏移量控制header的显示隐藏和对应的偏移量及可滚动状态,在业务tableView使用回调将ScrollView的可滚动状态回调达到状态同步。总体来说还是比较清晰,更多细节请看QFMultipleScrollView

总结

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

iOS ScrollView嵌套tableView联动滚动的思路与最佳实践的更多相关文章

  1. iOS将UIView转换为ScrollView而不破坏布局?

    是否有可能在不破坏所有约束和放置的情况下从UIView移动到UIScrollView.问题是我构建整个UI而不在iPhone4上测试它,现在我看到一些视图应该在ScrollView中工作.我尝试了一些技巧,但没有任何作用.约束被删除.以下是示例的示例图片:现在我希望test1UIView是ScrollView,我试图将ScrollView放在test1View中,然后在滚动视图中递归复制test1

  2. ios – 放大故事板中的任何视图时,Xcode 8.2和8.1崩溃

    当我单击视图框并拖动以放大视图时,视图不会放大.但相反,鼠标等待指示器将持续一秒钟,然后整个xcode将崩溃.这是在我的代码8.2更新后发生的.所以我尝试安装xcode8.1,问题仍然存在于一个特定项目中.所有其他项目都运作良好.故事板中没有警告或冲突.我不记得改变任何设置.附加崩溃日志:CRASH_LOG解决方法修正了问题:在我将ScrollView添加到ViewController并更改了Vi

  3. ios – UIButton在uiscrollView中不起作用

    我有一个将UIView作为子视图的scrollView.这有UIView子视图UIButton.只有scrollView连接到插座,其余全部都是代码.按钮不响应触摸,触摸时不变蓝.我能做些什么才能让它发挥作用?这是代码:解决方法您必须设置视图的内容大小.它必须大于或等于scrollView的内容大小.因为您的视图的默认大小是320*480和320*568.因此,增加视野的高度–self.view.frame=CGRectMake;然后将其添加为scrollView的子视图.将帮助您解决问题.

  4. ios – Xcode只看到一些嵌套类的类似扩展,这些扩展是用不同的文件编写的

    解决方法我遇到过类似的问题,似乎编译器正在尝试处理扩展嵌套类的文件,在嵌套类定义之前.因此,您有此错误说该Space没有成员SomeClass.我发现的解决方案是转到目标设置,打开BuildPhases.在“编译源”部分中,您应该将用于定义嵌套类的文件放在扩展它的文件上.这个解决方案似乎甚至可以很好地与您的观察结果一致,当您重新创建文件时,它有时会编译,因为当您重新创建文件时,它在编译源中的位置会发生变化.

  5. ios – scrollViewDidEndDecelerating检测哪个集合视图在运行

    我使用这种方法来组织分页:当我滚动我的UICollectionView时,我在屏幕上更改了一些内容.但是我的屏幕上有很少的UICollectionView,我只需要一个.解决方法好吧,UICollectionView继承自UIScrollView,因此您可以检查哪个滚动视图最终从委托方法中减速.

  6. ios – 嵌套递归函数

    我试图做一个嵌套递归函数,但是当我编译时,编译器崩溃.这是我的代码:编译器记录arehere解决方法有趣的…它似乎也许在尝试在定义之前捕获到内部的引用时,它是bailing?以下修复它为我们:当然没有嵌套,我们根本没有任何问题,例如以下工作完全如预期:我会说:报告!

  7. ios – 在swift中将捕获列表正确放置在嵌套闭包中

    在Swift中为哪些嵌套闭包定义捕获的引用?如果[weakself]被捕获在只有内部最后面的闭包,GCD将保留ExampleDataSource,直到块完成执行,这就解释了为什么调试看起来像这样:同样的事情会发生,如果没有捕获列表被包括,我们从来没有可选地解开自己,尽管编译器,确实试图警告你!

  8. ios – 无效的软件包 – 嵌套软件包没有在CFBundleSupportedPlatforms Info.plist键中列出的正确平台

    我上传了一个应用程序到iOSAppStoretestflight.iOSAppStore收到以下电子邮件:InvalidBundle–Anestedbundledoesn’thavetherightplatformslistedinCFBundleSupportedplatformsInfo.plistkey.Oncetheseissueshavebeencorrected,youcanthenr

  9. ios – 如何在使用嵌套上下文时自动设置Core Data关系

    解决方法想到的第一个想法是,虽然姓名的人际关系是不可选的,但你并没有说Person的姓名关系也是不可选的.创建一个没有名字的人,可以用您的代码处理,然后在实际需要时创建名称吗?当然不用打扰自定义awakeFromInsert…

  10. ios – 使用autolayout将子视图的宽度与其超级视图相匹配

    >我做错了什么?

随机推荐

  1. iOS实现拖拽View跟随手指浮动效果

    这篇文章主要为大家详细介绍了iOS实现拖拽View跟随手指浮动,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

  2. iOS – genstrings:无法连接到输出目录en.lproj

    使用我桌面上的项目文件夹,我启动终端输入:cd然后将我的项目文件夹拖到终端,它给了我路径.然后我将这行代码粘贴到终端中找.-name*.m|xargsgenstrings-oen.lproj我在终端中收到此错误消息:genstrings:无法连接到输出目录en.lproj它多次打印这行,然后说我的项目是一个目录的路径?没有.strings文件.对我做错了什么的想法?

  3. iOS 7 UIButtonBarItem图像没有色调

    如何确保按钮图标采用全局色调?解决方法只是想将其转换为根注释,以便为“回答”复选标记提供更好的上下文,并提供更好的格式.我能想出这个!

  4. ios – 在自定义相机层的AVFoundation中自动对焦和自动曝光

    为AVFoundation定制图层相机创建精确的自动对焦和曝光的最佳方法是什么?

  5. ios – Xcode找不到Alamofire,错误:没有这样的模块’Alamofire’

    我正在尝试按照github(https://github.com/Alamofire/Alamofire#cocoapods)指令将Alamofire包含在我的Swift项目中.我创建了一个新项目,导航到项目目录并运行此命令sudogeminstallcocoapods.然后我面临以下错误:搜索后我设法通过运行此命令安装cocoapodssudogeminstall-n/usr/local/bin

  6. ios – 在没有iPhone6s或更新的情况下测试ARKit

    我在决定下载Xcode9之前.我想玩新的框架–ARKit.我知道要用ARKit运行app我需要一个带有A9芯片或更新版本的设备.不幸的是我有一个较旧的.我的问题是已经下载了新Xcode的人.在我的情况下有可能运行ARKit应用程序吗?那个或其他任何模拟器?任何想法或我将不得不购买新设备?解决方法任何iOS11设备都可以使用ARKit,但是具有高质量AR体验的全球跟踪功能需要使用A9或更高版本处理器的设备.使用iOS11测试版更新您的设备是必要的.

  7. 将iOS应用移植到Android

    我们制作了一个具有2000个目标c类的退出大型iOS应用程序.我想知道有一个最佳实践指南将其移植到Android?此外,由于我们的应用程序大量使用UINavigation和UIView控制器,我想知道在Android上有类似的模型和实现.谢谢到目前为止,guenter解决方法老实说,我认为你正在计划的只是制作难以维护的糟糕代码.我意识到这听起来像很多工作,但从长远来看它会更容易,我只是将应用程序的概念“移植”到android并从头开始编写.

  8. ios – 在Swift中覆盖Objective C类方法

    我是Swift的初学者,我正在尝试在Swift项目中使用JSONModel.我想从JSONModel覆盖方法keyMapper,但我没有找到如何覆盖模型类中的Objective-C类方法.该方法的签名是:我怎样才能做到这一点?解决方法您可以像覆盖实例方法一样执行此操作,但使用class关键字除外:

  9. ios – 在WKWebView中获取链接URL

    我想在WKWebView中获取tapped链接的url.链接采用自定义格式,可触发应用中的某些操作.例如HTTP://我的网站/帮助#深层链接对讲.我这样使用KVO:这在第一次点击链接时效果很好.但是,如果我连续两次点击相同的链接,它将不报告链接点击.是否有解决方法来解决这个问题,以便我可以检测每个点击并获取链接?任何关于这个的指针都会很棒!解决方法像这样更改addobserver在observeValue函数中,您可以获得两个值

  10. ios – 在Swift的UIView中找到UILabel

    我正在尝试在我的UIViewControllers的超级视图中找到我的UILabels.这是我的代码:这是在Objective-C中推荐的方式,但是在Swift中我只得到UIViews和CALayer.我肯定在提供给这个方法的视图中有UILabel.我错过了什么?我的UIViewController中的调用:解决方法使用函数式编程概念可以更轻松地实现这一目标.

返回
顶部