尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

ScrollingStackViewController的edgeInsets秘密:容器视图自动包装机制揭秘

ScrollingStackViewController的edgeInsets秘密:容器视图自动包装机制揭秘 ScrollingStackViewController的edgeInsets秘密容器视图自动包装机制揭秘【免费下载链接】ScrollingStackViewControllerA view controller that uses root views of child view controllers as views in a UIStackView.项目地址: https://gitcode.com/gh_mirrors/sc/ScrollingStackViewControllerScrollingStackViewController是 Just Eat 开源的 iOS 滚动容器控件它用UIStackViewUIScrollView把多个子视图控制器纵向堆叠成一个可滚动的页面。它的edgeInsets内边距参数背后藏着一个巧妙的容器视图自动包装机制——今天我们就把这个秘密拆开来看。一、edgeInsets 参数是什么为什么新手容易踩坑普通的add(viewController:)会把子控制器的view直接塞进UIStackView。而带内边距的版本多了一个可选参数add(viewController: viewController, edgeInsets: insets)一句话概括它的效果让某个子控制器在页面中缩进显示比如左右留白 40pt常见于卡片式布局。示例工程里就给了 6~10 号区块加上了UIEdgeInsets(top: 20, left: 40, bottom: 20, right: 40)的内边距效果就是页面下半部分的区块整体向里收缩形成卡片感。但很多新手遇到两个奇怪的现象❓ 明明调用的是hide(viewController:)缩进的区块却没反应❓ 明明调用的是scrollTo(viewController:)滚动定位却走了别的分支。答案都藏在同一个秘密里传了edgeInsets的子控制器它的view并没有直接放进 StackView而是被自动包进了一层新的容器视图。二、自动包装机制一行参数背后的四步操作打开核心文件 ScrollingStackViewController.swiftinsert(viewController:edgeInsets:at:)的逻辑可以拆成 4 步正常挂载子控制器先执行addChild和didMove(toParent:)父子关系与不带内边距时完全一致动态创建容器视图当edgeInsets非nil时现场new一个containerView一个纯UIView并把子控制器的view作为子视图加进去同时关闭双方的自动转换布局用 4 条约束还原内边距子视图的上边距绑edgeInsets.top、左边距绑left容器的下边距、右边距反向绑bottom和right——内边距本质上就是容器比子视图大一圈的距离把容器而不是子视图放入 StackViewstackView.insertArrangedSubview(containerView, at: index)。如果edgeInsets是nil则跳过整个包装过程直接insertArrangedSubview(viewController.view, at: index)。 换句话说edgeInsets不是修改某个属性而是悄悄地多插了一层视图层级。三、为什么必须用 show/hide 来操作它这是最容易被忽略的坑README 里有一句简短提示When a child view is added to a padding container view, the show/hide functions should be used.原因很简单StackView 的 arrangedSubview 是容器show/hide最终操作的是arrangedView(for:)返回的那个视图见 arrangedView(for:) 实现。它先查子视图本身查不到就通过arrangedViewContainerIndex(for:)L339-L345向上查找哪个 arrangedSubview 包含了我。所以正确的操作姿势是✅ 插入时用add(viewController:edgeInsets:)✅ 之后对它的显隐、滚动都走show/hide/scrollTo这些按控制器的 API它们会自动穿透容器找到正确对象❌ 不要绕过这些 API 直接操作viewController.view的层级。四、remove 时的双重移除细节删除被包装的子控制器时remove(arranged:) 方法 里有一行很关键的判断if arrangedView ! viewController.view { viewController.view.removeFromSuperview() }源码注释写得很直白This happens when the view controller was added with edges.即被内边距包装过的子控制器remove需要移除两次——先把容器视图从 StackView 摘掉再把子视图从容器里摘出来最后才走标准的willMove/removeFromParent流程。这套清理工作全部由框架自动完成使用者只要调remove(_:)即可。五、三个实用小贴士 位置定位同样容器感知insert支持.start/.end/.index(1)/.after(vc)/.before(vc)五种位置Position 枚举定义。定位.after/.before时用的arrangedViewOrContainerIndex(for:)会先查直接子视图、再查包裹容器所以对包装过的区块也能精确定位背景色画在容器间隙spacingColor和borderColor/borderWidth作用在stackViewBackgroundView上viewDidLoad 布局逻辑。内边距区块周围露出的间距会显示spacingColor可以借此做出卡片悬浮的视觉层次子视图控制器必须自带高度约束README 特别强调Make sure your child view controllers have constraints to self-size vertically。被容器包装后容器的大小是由子视图固有高度 四边内边距推算出来的若子视图不能自测量高整条链路都会失效。六、总结一张图看懂机制不带 edgeInsets StackView ──┬── 子VC1.view └── 子VC2.view 带 edgeInsets StackView ──┬── 子VC1.view └── containerView(容器) └── 子VC3.view(四周留出内边距)edgeInsets的秘密并不复杂传参 → 自动 new 容器 → 4 条约束留出内边距 → 容器进 StackView而show/hide/scrollTo/remove全链路都做了容器感知的兼容只要坚持用按控制器操作的公开 API就能零成本享受卡片式布局。 想动手试试完整示例在 ViewController.swift第 6~10 号区块都用了edgeInsets插入单元测试见 ScrollingStackViewTests.swiftPod 依赖声明见 ScrollingStackViewController.podspec。【免费下载链接】ScrollingStackViewControllerA view controller that uses root views of child view controllers as views in a UIStackView.项目地址: https://gitcode.com/gh_mirrors/sc/ScrollingStackViewController创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表