代码之家  ›  专栏  ›  技术社区  ›  Z S

SwiftUI:使用@FocusState。与视图初始化器绑定

  •  0
  • Z S  · 技术社区  · 昨天

    我有一个观点 @FocusState 我想传递到子视图中。对于子视图,我使用 @FocusState.Binding 。如果我不使用自定义初始化器,这可以很好地工作。。。但我无法弄清楚它如何与自定义视图初始化器一起工作的语法,出于其他原因,我需要它。

    以下是有效的代码:

    struct TestListButtonsAndListFocusView: View {
        
        @FocusState var buttonFocusState: ButtonState?
        @ObservedObject var viewModel: ViewModel = ViewModel()
        
        var body: some View {
            TestListView(viewModel: viewModel, bindedFocusButtonState: $buttonFocusState) // for custom init, replace with following line
            //TestListView(viewModel: viewModel, focusButtonState: $buttonFocusState) // 1. Uncomment this for custom initializer
        }
    }
    
    struct TestListView: View {
        @State private var items1: [TimedItem] = [
            TimedItem(number: 1, timestamp: "2024-11-20 10:00"),
            TimedItem(number: 2, timestamp: "2024-11-20 11:00"),
            TimedItem(number: 3, timestamp: "2024-11-20 12:00")
        ]
        
        @ObservedObject var viewModel: ViewModel
        @FocusState.Binding var bindedFocusButtonState: ButtonState?
        
        @State var selectedItem: TimedItem.ID?
        
        var body: some View {
            List(items1, selection: $selectedItem) { item in
                ContentListItemView(item: item)
            }
            .onChange(of: bindedFocusButtonState) {
                if let bindedFocusButtonState {
                    print("TestListView - bindedListFocusState has changed to \(bindedFocusButtonState)")
                    if bindedFocusButtonState == .one && selectedItem == nil {
                        selectedItem = items1.first?.id
                    }
                } else {
                    print("ListOneView - bindedListFocusState has changed to nil")
                }
            }
        }
        
        // 2. Uncomment this
        /*init(viewModel: ViewModel, focusButtonState: FocusState<ButtonState?>.Binding) {
            // how to pass in @FocusState.Binding?
            self.viewModel = viewModel
            self.bindedFocusButtonState = focusButtonState
            // Error: Cannot assign value of type 'FocusState<ButtonState?>.Binding' to type 'ButtonState?'
        }*/
    }
    
    public class ViewModel: NSObject, ObservableObject {
        
        @Published public var selectedButton: ButtonState? = ButtonState.one
    }
    
    public enum ButtonState: Int, CaseIterable, Hashable, Identifiable {
        
        public var id: Self {
            return self
        }
        case one, two, three
    }
    
        
    #Preview {
        TestListButtonsAndListFocusView()
    }
    

    但是,如果我取消注释自定义初始化器的行,然后取消注释 TestListButtonsAndListFocusView 要使用自定义初始化器,语法错误,我得到错误:

    错误:无法分配“FocusState<”类型的值;按钮状态>。绑定' 键入“ButtonState?”

    我不确定如何初始化 @焦点状态。结合 这种方式。我知道如果我使用它,它就会起作用 var bindedFocusButtonState: FocusState<ContactTabStyle?>.Binding 相反,然后在初始化器中也使用它。但我真的很想弄清楚如何使用新的 @焦点状态。结合 使用自定义初始化器,因为它避免了访问 wrappedValue 并且更容易观察 onChange

    1 回复  |  直到 昨天
        1
  •  0
  •   Sweeper    昨天

    您应该为下划线前缀属性赋值 _bindedFocusButtonState .

    self._bindedFocusButtonState = focusButtonState
    

    这是实际包含 FocusState.Binding . bindedFocusButtonState 另一方面,它实际上是一个返回的计算属性 _bindedFocusButtonState.wrappedValue .

    特别是,线

    @FocusState.Binding var bindedFocusButtonState: ButtonState?
    

    声明 属性:

    private var _bindedFocusButtonState: FocusState<ButtonState?>.Binding
    
    var bindedFocusButtonState: ButtonState? {
        get { _bindedFocusButtonState.wrappedValue }
        set { _bindedFocusButtonState.wrappedValue = newValue }
    }
    
    var $bindedFocusButtonState: FocusState<ButtonState?>.Binding {
        get { _bindedFocusButtonState.projectedValue }
    }