I just made a function for modifying views, the code builds itself, but when I am using it it complaints about Type issue related to protocol, it must be an easy fix, but I could not solve it.
struct CGSizePreferenceKey: PreferenceKey {
static var defaultValue: CGSize { get { return CGSize() } }
static func reduce(value: inout CGSize, nextValue: () -> CGSize) { value = nextValue() }
}
extension View {
func onPreference<K: PreferenceKey>(key: K, value: K.Value, action: ((K.Value) -> Void)?) -> some View where K.Value: Equatable {
return self
.preference(key: K.self, value: value)
.onPreferenceChange(K.self, perform: { newValue in action?(newValue)})
}
}
Use case:
struct ContentTestView: View {
@State private var size: CGSize = .zero
var body: some View {
Button("update") { size = CGSize(width: 100, height: 100) }
.onPreference(key: CGSizePreferenceKey, value: size, action: { newValue in print(newValue) })
}
}
Errors:
Instance method 'onPreference(key:value:action:)' requires that 'CGSizePreferenceKey.Type.Value' conform to 'Equatable'
Cannot convert value of type 'CGSize' to expected argument type 'CGSizePreferenceKey.Type.Value'
CodePudding user response:
First things first, you should change the definition of onPreference
to accept a meta-type instead of an instance of K
, the simple reason being that you never use that instance of K
, SwiftUI doesn't ask for an instance of PreferenceKey
in that context.
extension View {
func onPreference<K: PreferenceKey>(key: K.Type, value: K.Value, action: @escaping (K.Value) -> Void) -> some View where K.Value: Equatable {
I also took the liberty of removing the optionality of the action
parameter, since it makes little sense to call onPreference
without a callback.
Now, with the new definition in place, what's left is to update the call site to pass the meta-type:
.onPreference(key: CGSizePreferenceKey.self, ...
Note that a shorter solution would've been to just instantiate the preference at the call site:
.onPreference(key: CGSizePreferenceKey(), ...
, that would've make the compiler happy, however it wouldn't have been the right solution.