在不执行弹出操作的情况下更改SwiftUI工具栏图标
我希望工具栏项在处于活动状态时能显示徽章。我认为实现起来最好看的方式是使用自定义的SF Symbol,因为这与我的应用的其他部分相匹配。
但显然 .toolbar 标签忽略了你符号的文本对齐规则?因为导出时它们看起来很完美,但当我切换符号时,它们就会上下跳动:

.toolbar {
ToolbarItem(placement: .topBarTrailing) {
Button {
isFilterSheetPresented = true
} label: {
Image(
systemName: activeFilterCount == 0 ? "tray" : "tray.badge"
)
// .contentTransition(.symbolEffect(.replace))
.symbolRenderingMode(activeFilterCount > 0 ? .palette: .none)
.foregroundStyle(
activeFilterCount > 0 ? Color.accentColor : Color.primary,
Color.primary
)
}
.accessibilityLabel("Filter")
}
}
在我的应用中,我使用自定义符号:
activeFilterCount==0 ? "custom.line.3.horizontal.decrease" : "custom.line.3.horizontal.decrease.badge"
但 tray.badge 的表现也一样,且它并非自定义——徽章会让符号变高,因此底层的符号在加上徽章时会向下弹出。
我已经禁用了 .contentTransition,因为一方面它只是让它在上下之间淡入淡出,而不是弹出;另一方面随着其他属性在随机时间间隔改变,会引发一堆乱象。
每个AI工具都建议我把它包在一个框架里,但那样只会阻止图标尺寸变化干扰工具栏的其他部分。我希望符号按其文本指南来布局,而不是按它的边界框来布局,而框架根本解决不了这个问题。
如果没有“正确”的答案,我可以用自定义让它基本可用
.offset(y: activeFilterCount > 0 ? -3.5 : 0)
并且在每个文本大小上大致估算一个偏移量,但这看起来深感愚蠢。
我真的希望有办法使用 .alignmentGuide() 和/或 .firstTextBaseline 来实际锁定它,但我认为这些在工具栏中并不工作。而且我也不认为有办法在里面放一个 HStack,可以避免同样的跳动。
我也在继续努力让它与 .badge() 一起工作,但那样也不会是理想的外观。
解决方案
这个问题类似于 SF Symbol replace animation size is off。
我的回答 对那个问题给出了解法。我认为你可以在这里使用相同的技术,但重要的一点是要用带徽章的图像版本作为隐藏图像来建立基线:
ToolbarItem(placement: .topBarTrailing) {
Button {
activeFilterCount = activeFilterCount == 0 ? 1 : 0
// isFilterSheetPresented = true
} label: {
ZStack(alignment: .centerFirstTextBaseline) {
Image(systemName: "tray.badge")
.hidden()
Image(systemName: activeFilterCount == 0 ? "tray" : "tray.badge")
.symbolRenderingMode(activeFilterCount > 0 ? .palette: .none)
.foregroundStyle(
activeFilterCount > 0 ? Color.accentColor : Color.primary,
Color.primary
)
}
}
.accessibilityLabel("Filter")
}

站内所有文章版权归属LeftHeroAI导航站,无授权禁止任何主体转载、抄袭、复制内容,亦不得私自架设镜像站点。一经侵权,本站将通过法律途径追责。