SwiftUI如何实现圆角HStack按钮栏并固定在屏幕底部上方
问题描述
我想要实现如下样式的按钮栏:
为此我决定使用HStack实现(不确定该方案是否最优),具体代码如下:
HStack{ ForEach(playerMenuControllers,id: \.self ){img in let pos = playerMenuControllers.firstIndex(of: img) let likeImg = liked ? "heart.fill" : img let bookMarkImg = bookmark ? "bookmark.fill" : img Button(action: { switch pos{ case 0: break case 1: liked.toggle() break case 2: bookmark.toggle() break case 3: showingSheet.toggle() break default: break } }) { HStack { switch pos{ case 0: Image(systemName: img).foregroundColor(Color.white) case 1: Image(systemName: likeImg).foregroundColor(Color.white) case 2: Image(systemName: bookMarkImg).foregroundColor(Color.white) case 3: Image(systemName: img).foregroundColor(Color.white) default: Image(systemName: img).foregroundColor(Color.white) } } }.sheet(isPresented: $showingSheet) { SheetView(model: episode) } .padding(EdgeInsets(top: 17, leading: 33, bottom: 17, trailing: 33)) } } .cornerRadius(15) .background(Color(red: 54 / 255, green: 54 / 255, blue: 54 / 255)) .padding(EdgeInsets(top: 17, leading: 33, bottom: 17, trailing: 33))
实际运行后得到的效果如下:
我已经按照设计要求设置了所有参数,请问具体是哪里存在问题?
问题原因与修复方案
你代码里存在四个核心问题:
- 内边距设置逻辑错误
你给每个Button单独加了leading/trailing各33的内边距,同时外层HStack又加了一遍左右33的内边距,双重padding导致按钮间距远超设计值,整个按钮栏被撑宽。 - HStack没有配置均等分排布
默认HStack会按照元素内容大小自适应排列,不会自动平分可用宽度,所以按钮之间没有均匀分配空间。 - sheet修饰符位置错误
你把sheet挂在了ForEach循环内的每个Button上,相当于同时创建了4个完全一样的sheet,运行时会出现渲染异常,正确做法是把sheet移到HStack外层。 - 索引获取方式有隐患
用firstIndex(of:)获取元素位置,如果数组中存在重复元素会返回错误的索引,建议直接遍历带索引的数组。
修正后的代码如下:
HStack(spacing: 0) { // 直接遍历带索引的数组,避免firstIndex异常 ForEach(Array(playerMenuControllers.enumerated()), id: \.element) { index, img in let currentImg: String if index == 1 { currentImg = liked ? "heart.fill" : img } else if index == 2 { currentImg = bookmark ? "bookmark.fill" : img } else { currentImg = img } Button(action: { switch index{ case 1: liked.toggle() case 2: bookmark.toggle() case 3: showingSheet.toggle() default: break } }) { // 每个按钮设置maxWidth为.infinity,自动平分HStack宽度 Image(systemName: currentImg) .foregroundColor(.white) .frame(maxWidth: .infinity) .padding(.vertical, 17) } } } .background(Color(red: 54 / 255, green: 54 / 255, blue: 54 / 255)) .cornerRadius(15) // 外层padding只留全局边距即可 .padding(.horizontal, 33) .padding(.vertical, 17) // sheet移到外层,避免重复创建 .sheet(isPresented: $showingSheet) { SheetView(model: episode) }
内容的提问来源于stack exchange,提问作者Andrew
相关产品推荐
相关产品推荐

