SwiftUI能否绑定多份同类型ViewModel以合并重复的视图修饰符
解决方案
完全可以合并两次showView修饰符调用,核心思路是将两个ViewModel的show属性的Binding<Bool>实例,合成一个**任意源为true就返回true**的绑定即可,以下是两种常用实现方案:
方案1:不修改现有扩展,调用侧直接合成绑定
无需调整你已经写好的View扩展和ViewModel定义,仅修改ContentView的body部分,构造合成绑定传入即可:
struct ContentView: View { @StateObject var viewModel1 = ViewModel() @StateObject var viewModel2 = ViewModel() var body: some View { // 合成绑定:只要任意一个show为true,返回true let combinedShow = Binding<Bool>( get: { viewModel1.show || viewModel2.show }, // 如果不需要反向修改两个show的值,set闭包可以留空;需要的话可按业务逻辑调整 set: { newValue in viewModel1.show = newValue viewModel2.show = newValue } ) Text("Home") .showView(show: combinedShow) } }
原理说明
SwiftUI的@Published属性变更时会触发所属ObservableObject对应的视图刷新,合成绑定的get闭包会在每次视图刷新时读取两个ViewModel的show值,无论哪个ViewModel的show发生变更,都能正确拿到最新的组合状态,触发showView的重绘逻辑。
方案2:扩展修饰符支持多绑定传入
如果后续经常需要绑定多个控制条件,可以重载showView修饰符,支持可变参数传入多个Binding<Bool>,更方便复用:
第一步:修改View扩展
extension View { // 原有单绑定方法保留,新增多绑定重载 func showView(shows: Binding<Bool>...) -> some View { let combinedShow = Binding<Bool>( get: { shows.contains { $0.wrappedValue } }, set: { newValue in shows.forEach { $0.wrappedValue = newValue } } ) return ZStack(alignment: .top) { self if combinedShow.wrappedValue { Text("Hello, world.") } } } }
第二步:调用侧直接传入多个绑定
struct ContentView: View { @StateObject var viewModel1 = ViewModel() @StateObject var viewModel2 = ViewModel() var body: some View { Text("Home") // 直接传入任意数量的show绑定即可 .showView(shows: $viewModel1.show, $viewModel2.show) } }
内容的提问来源于stack exchange,提问作者Alexico
相关产品推荐
相关产品推荐

