iOS 16 List Section头Modifier在NavigationView多栏布局下表现不一致
问题背景
自从iOS将List的底层实现从UITableView替换为UICollectionView后,应用中所有Section的头视图都会自动继承列表单元格的背景色。
为了统一全应用列表配色,我实现了自定义组件ThemedList:
struct ThemedList<Content>: View where Content: View { @ViewBuilder var content: () -> Content var body: some View { List { content() .listRowBackground(Color.red) } } }
iOS 15系统下,全局用ThemedList替换原生List运行完全正常,测试代码如下:
struct SidebarView: View { var body: some View { ThemedList { Section("Header") { Text("Row") Text("Row") Text("Row") } } } }

升级到iOS 16后出现异常:Section头视图被染上了列表行配置的红色背景:
临时修复方案及存在的问题
最初判断该问题修复成本较低,因此自定义了ThemedSection组件,专门将Section头、尾视图的背景设置为透明色.clear:
struct ThemedSection<Header, Content, Footer> { @ViewBuilder var header: () -> Header @ViewBuilder var footer: () -> Footer @ViewBuilder var content: () -> Content } extension ThemedSection : View where Header : View, Content : View, Footer : View { var body: some View { Section { content() } header: { header() .listRowBackground(Color.clear) } footer: { footer() .listRowBackground(Color.clear) } } }
同时补齐了和原生Section一致的初始化方法,保证调用方式无感知:
extension ThemedSection where Header == Text, Content : View, Footer == EmptyView { init<S>(_ title: S, @ViewBuilder content: @escaping () -> Content) where S : StringProtocol { self.content = content self.header = { Text(title) } self.footer = { EmptyView() } } }
将全局Section替换为ThemedSection后,单独展示侧边栏视图时头视图背景恢复正常:
struct SidebarView: View { var body: some View { ThemedList { ThemedSection("Header") { Text("Row") Text("Row") Text("Row") } } } }

但后续测试发现该方案存在严重兼容性问题:透明背景设置并非在所有场景下生效:
- 侧边栏视图单独放在
NavigationView中时,头视图透明效果正常 - iPad端为NavigationView添加第二个视图作为初始详情栏时,主栏列表的Section头视图透明设置直接失效
复现代码如下:
struct ContentView: View { var body: some View { NavigationView { SidebarView() Text("iPad selected initial view") // 移除该行后头视图可恢复透明 } } } struct SidebarView: View { var body: some View { ThemedList { ThemedSection("Header") { Text("Row") Text("Row") Text("Row") } } } }

极端场景下,将完全相同的SidebarView同时作为NavigationView的主栏和详情栏时,详情栏的Section头视图表现正常,主栏的透明设置依然失效:
struct ContentView: View { var body: some View { NavigationView { SidebarView() SidebarView() } } }

待解决问题
- 该兼容性问题的根本产生原因
- 适配所有场景的通用修复方案
内容的提问来源于stack exchange,提问作者Darren
相关产品推荐
相关产品推荐

