V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
iOS 开发实用技术导航
NSHipster 中文版
http://nshipster.cn/
cocos2d 开源 2D 游戏引擎
http://www.cocos2d-iphone.org/
CocoaPods
http://cocoapods.org/
Google Analytics for Mobile 统计解决方案
http://code.google.com/mobile/analytics/
WWDC
https://developer.apple.com/wwdc/
Design Guides and Resources
https://developer.apple.com/design/
Transcripts of WWDC sessions
http://asciiwwdc.com
Cocoa with Love
http://cocoawithlove.com/
Cocoa Dev Central
http://cocoadevcentral.com/
NSHipster
http://nshipster.com/
Style Guides
Google Objective-C Style Guide
NYTimes Objective-C Style Guide
Useful Tools and Services
Charles Web Debugging Proxy
Smore
hustlzp
V2EX  ›  iDev

[iOS 开发] 请教大家这种页面如何实现比较优雅?

  •  
  •   hustlzp ·
    hustlzp · 2015-12-03 11:17:22 +08:00 · 9608 次点击
    这是一个创建于 3283 天前的主题,其中的信息可能已经有所发展或是发生改变。



    类似上图的页面,上面有个 tab ,点击可以切换下面的视图,下面的视图可能是 tableview 或 collection view 或普通的 uiview 。

    如果 tab 是固定在上方的,实现起来比较简单,可以把下面的页面拆分到一个个独立的 view controller 中,然后作为 child view controller 加进来。切换上面的 tab 时,只需显示 /隐藏 child view controller 的 view 就行。

    但这个 tab 需要跟着页面上下滚动。目前想到的方式是在当前 view controller 中实现一个 tableview ,把 tab 作为 tableview 的 header view 。然后如果点击 tab 切换到 tableview 类型的视图,那么就在 tableview 协议中根据不同的 tab 返回对应类型的 cell 。如果是其他类型的,那么 tableview 的 rows 返回 1 ,然后把整个 view 塞到这个 cell 中(比如把整个 collection view 塞到这个 cell 中)。

    但这样做的问题是维护性差,单个 view controller 塞进了太多的逻辑。如果能拆开就好了。

    不知道大家有没有遇到这样的问题,或者有更好的想法。
    27 条回复    2015-12-04 10:25:39 +08:00
    hustlzp
        1
    hustlzp  
    OP
       2015-12-03 11:49:28 +08:00
    想到了一种减负的方法:

    将 datasource 和 delegate 拆分到独立的 class 中,切换 tab 时,同时切换 tableview 的 datasource 和 delegate :

    if (didPressedATab) {
    self.tableView.delegate = instanceOfMyClassA;
    self.tableView.datasource = instanceOfMyClassA;
    } else {
    self.tableView.delegate = instanceOfMyClassB;
    self.tableView.datasource = instanceOfMyClassB;
    }

    然后再 reloadData 一下。不知道这样可以不可以,去试试~
    loveuqian
        2
    loveuqian  
       2015-12-03 11:55:02 +08:00 via iPhone
    header 是 tag
    footer 是或者 cell 是 scrollView
    切换 tag 就滚动
    这样可以嘛
    blacknight
        3
    blacknight  
       2015-12-03 11:59:46 +08:00
    view controller 的本质还是 view ,这几个 tab 对应的页面你可以单独写在每一个 view controller 中,添加的时候只使用 view controller 的 view 即可。这样整个页面处理的实际上就是一个如图的 header 和一个 tab 。
    mornlight
        4
    mornlight  
       2015-12-03 12:00:34 +08:00
    @hustlzp 每次切换一个 tab 就 reload 一次,这个方式好像太野蛮了。
    「这个 tab 需要跟着页面上下滚动」 这个滚不滚动对实现方式有很大影响吗?
    hustlzp
        5
    hustlzp  
    OP
       2015-12-03 12:11:41 +08:00
    @mornlight

    「这个方式好像太野蛮了。」
    看起来确实有点野蛮...不过 tableview 的 reloadData 只会 reload 当前可见的 rows ,而且 cell 是可以 dequeue 复用的, cell height 也可以做 cache ,所以 reload 的代价个人觉得其实还好。

    主要还是可维护性方面的考虑,因为太多逻辑堆到一个 controller 里面看起来太虐心了...

    「这个滚不滚动对实现方式有很大影响吗?」 不滚动,我就可以把下面的视图拆分到 view controllers 中,如 @blacknight 所说, tab 和 child view controller 的 view 是兄弟关系。

    但如果需要 tab 跟着 tableview 滚动,需要把它作为 tableview 的 header view 才行(目前我只想到这样做), tab 和 child view controller 的 view 是从属关系。
    hustlzp
        6
    hustlzp  
    OP
       2015-12-03 12:12:19 +08:00
    @blacknight 恩,我明白你的意思。这个我在帖子中提到了。
    blacknight
        7
    blacknight  
       2015-12-03 12:27:32 +08:00
    @hustlzp 我再说详细一点吧,这个界面可以分成三部分,最上面的 header , 中间的 tab ,最下面的一个混合视图。其实三个部分都可以用 view 来实现,最上面的是 uiview ,中间是 uiview ,下面可以用 scrollview ,暂称为 sub scrollview 。然后再用一个 scrollview 来容纳这三个 view 。上下滑动的时候,根据 scrollview 的位移来让 tab 随页面滚动,点击 tab 的时候,设置 tab 在 scrollview 中的位置和切换 sub scrollview 中的 view controller 。

    这样做, scrollview 里的逻辑仅处理 tab 的跟随和 sub scrollview 的切换,具体的页面都划分到了各个 view controller 中去
    hustlzp
        8
    hustlzp  
    OP
       2015-12-03 12:38:36 +08:00
    @blacknight 感谢回复,你的思路可行。我没有想到把 tableview 放到 scrollview 中...就是不知 iOS 会不会正确处理嵌套的滚动关系。我去试试,感谢回复!
    hustlzp
        9
    hustlzp  
    OP
       2015-12-03 12:44:40 +08:00
    @blacknight SO 上找到了相关的一个问题:

    http://stackoverflow.com/questions/17334478/uitableview-within-uiscrollview-using-autolayout

    就是类似你提到的解决方法。
    xi_lin
        10
    xi_lin  
       2015-12-03 12:49:54 +08:00   ❤️ 1
    @blacknight 说的做法还是上方固定的来法吧
    这样的话其实直接就是 https://github.com/wangmchn/WMPageController
    blacknight
        11
    blacknight  
       2015-12-03 12:53:32 +08:00   ❤️ 1
    @hustlzp 方案是可行的,我试过
    送佛送到西,帮人帮到底,刚去翻了一下 github ,给你一个现成的吧
    https://github.com/AugustRush/ARSegmentPager
    hustlzp
        12
    hustlzp  
    OP
       2015-12-03 12:55:22 +08:00
    @xi_lin
    @blacknight

    感谢分享!
    mornlight
        13
    mornlight  
       2015-12-03 12:58:25 +08:00   ❤️ 1
    @hustlzp 和 7 楼的想法类似,我觉得中间的自滚动 tab 独立出来会让耦合度低一些。
    hustlzp
        14
    hustlzp  
    OP
       2015-12-03 13:02:07 +08:00
    nellace
        15
    nellace  
       2015-12-03 14:02:17 +08:00
    @xi_lin 做的挺精致的这个
    racechao
        16
    racechao  
       2015-12-03 14:02:39 +08:00
    @hustlzp
    和上面的思路基本差不多,这样并不需要用 tableVIew :
    1.只需要有一个主要的 ViewController ,这个 ViewController 有她的 Header View (普通的 View )还有一个 scrollView ;
    2.假设这里每个 tab 对应一个 ViewControll 的 view ,将这些 view 放到 scrollView 中就可以了。这就将 tab 分到了多个 ViewController 当中, 当切换 tab 时改变 scrollView 的 content offset (将 scrollView 的 pagingEnabledtab 设为 true 会很方便);
    我之前用 Swift 写了一个类似的控件 --> https://github.com/alfredcc/ZYScrollTabBar
    使用方法和 tableView 差不多,拆分了 dataSource 和 delegate 有兴趣可以参考下
    pheyer
        17
    pheyer  
       2015-12-03 14:36:06 +08:00
    可能有一个问题没考虑到,你的 Tab 要不要悬浮呢
    借用上面 @blacknight 的描述: 这个界面可以分成三部分,最上面的 header , 中间的 tab ,最下面的一个混合视图。其实三个部分都可以用 view 来实现,最上面的是 uiview ,中间是 uiview ,下面可以用 scrollview ,暂称为 sub scrollview 。然后再用一个 scrollview 来容纳这三个 view 。

    如果容纳这三个 view 的是 scrollview 的话,我们知道展示 scrollview 时是要提前知道它的 contentsize 的,你准备给它多少 height ?

    如果 Tab 要有悬浮效果的话,容纳这三个 view 的用 TableView 可能更好一些,把 Tab 放在 Section 里面,悬浮就是自然而然的事情。设这个 TableView 名为 TableView0
    上面说的 sub scrollview 可能具体起来就是 TableView 或者 CollectionView 了,就假设都为 sub TableView

    如果想要比较好的滑动体验的话,然后 TableView 嵌套的滑动问题就来了,当 TableView0 还未滑动到底部,而手指落在 subTableView 的内容上面,如何确保手指向上滑动时是滑动 TableView0 ?或者你不管任由它滑动 subTableView ?
    另一个问题,手指向下滑动使 subTableView 滑动到顶部,手指落在 subTableView 的内容上面,这时候怎么确保手指再往下滑动后滑动的是 TableView0 而非 subTableView ?
    hustlzp
        18
    hustlzp  
    OP
       2015-12-03 15:37:04 +08:00
    @pheyer 你这个思路挺新颖的,我目前没有悬浮的要求,不过以后应该会有的。

    嵌套 scroll 目前还没有用过。
    hustlzp
        19
    hustlzp  
    OP
       2015-12-03 15:39:30 +08:00
    @racechao 好思路,这样写代码起来方便,不用手动去 show/hide child view 了,根据当前 index 设置 contentOffset 就行了。谢谢分享。
    jackisnotspirate
        20
    jackisnotspirate  
       2015-12-03 15:52:27 +08:00
    scrollview 里面包着 tab, header , scrollview 滑动的时候, tab 跟着滑动,然后在达到某个时刻, scrollview 滑动, tab 设置成 相对 顶部 静止。
    blacknight
        21
    blacknight  
       2015-12-03 15:57:03 +08:00
    @pheyer 下面用 scrollview 主要是为了便于左右滑动可以切换上面的 tab , contentsize 设为 屏幕宽,高度为屏幕高减去 tab 高度,其实这里使用 pageviewcontroller 也是可以。在初始化的时候,你可以禁用下面 sub scrollview 子视图的手势,当 sub scrollview 显示在 scrollview 某个位置的时候,开启 sub scrollview 子视图的手势,此时保留 tab 在屏幕最上方,就有了悬浮的效果。当检测到 sub scrollview 子视图( tableview or collectionview )到了顶的时候,就把手势还给 sub scrollview 。这样处理就可以达到 LZ 要求的效果。

    我在后面有帖一个达到类似效果的示例,你可以去看看它是怎么实现的,可能跟我的实现方案不一样。
    blacknight
        22
    blacknight  
       2015-12-03 16:16:49 +08:00
    仔细想了一下,上面的处理方法不正确,这样滑动效果没办法衔接。之前做的时候没有 tab 悬浮的问题,是固定了 tab 。
    看看这篇文章的解决办法可行么
    http://blog.csdn.net/lizhongfu2013/article/details/12063413
    wezzard
        23
    wezzard  
       2015-12-03 16:23:09 +08:00   ❤️ 1
    WWDC 2014 session 232
    fhefh
        24
    fhefh  
       2015-12-03 16:50:25 +08:00
    mark 目前也遇到类似问题 收藏一下
    nathanw
        25
    nathanw  
       2015-12-03 17:37:27 +08:00   ❤️ 1
    别把 tableview 放在 scrollView 上,
    也别把 view 放在 scrollView 用于左右切换,用 transition 的 api ,自己查查。

    至于实现,我觉得直接让 header + tab 悬浮,多个 child controller 的 view 全屏加在底部,设置 contentInset 让内容下移,最后 header 和 tab 监听 child table view 的 contenoffset 来移动
    free9fw
        26
    free9fw  
       2015-12-03 20:31:28 +08:00   ❤️ 1
    https://github.com/wangmchn/WMPageController 这个挺好用的,最近修复了几个 bug ,可以设置子 view 的 frame 和 origin
    tigerZhang
        27
    tigerZhang  
       2015-12-04 10:25:39 +08:00
    @nathanw 遵守苹果的建议,实现方案也可行。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   3741 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 21ms · UTC 10:35 · PVG 18:35 · LAX 02:35 · JFK 05:35
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.