SwiftUI : Why preferenceKey is not read/called

From the code below, I can't figure out why Preference key is not read from the view put in background of HStack. Strangely, If I put that BGViewSetter to the Text Views inside ForEach loop, it works. Unless I have ommitted something too obvious, it looks like a bug. Anybody can confirm it? Thanks
  • xcode12.2

  • ios 14.2

Code Block
struct BGViewSetter: View {
var body: some View {
GeometryReader { geometry in
RoundedRectangle(cornerRadius: 25.0)
.fill(Color.init(#colorLiteral(red: 0.9372549057, green: 0.3490196168, blue: 0.1921568662, alpha: 1)))
.preference(key: TestRectPreferenceKey.self,
value: TestRectPreference(frame: geometry.frame(in: .global)))
}
}
}
struct FinalView : View
{
@State var offsetX : CGFloat = .zero
@State var info = ""
@State var size : CGFloat = .zero
var body: some View
{
VStack
{
Text("FinalView : \(info)")
HStack
{
ForEach( 1 ..< 10)
{ i in
Text("\(i)")
.frame(width: 100)
.opacity(0.8)
}
}
.background(BGViewSetter())
.animation(.easeOut)
.gesture(
DragGesture()
.onChanged
{ gesture in
self.offsetX = gesture.translation.width
}
.onEnded
{ _ in
self.offsetX = .zero
}
)
.offset(x: self.offsetX)
Text("Footer")
Divider()
Spacer()
}
.onPreferenceChange(TestRectPreferenceKey.self)
{
self.size = $0.frame.height
self.info = "Pref Chng : \(self.size)"
}
}
}
struct PreferenceKeyTest_Previews: PreviewProvider {
static var previews: some View {
FinalView()
}
}

I wanted to test, but I miss TestRectPreferenceKey definition.
Accepted Answer
I've run into the same issue. Setting preference key in background() view fails. Same code works fine on ios 13.
My Mistake for not including TestRectPreference Implementation. Below is the code :

Code Block
struct TestRectPreference : Equatable
{
var frame : CGRect
}
struct TestRectPreferenceKey : PreferenceKey
{
typealias Value = TestRectPreference
static var defaultValue: TestRectPreference = TestRectPreference(frame: CGRect.zero)
static func reduce(value: inout TestRectPreference, nextValue: () -> TestRectPreference)
{
value.frame = nextValue().frame
}
}

There is no ContentView in the code.

What is the view you call in the SceneDelegate ? Looks like it is BGViewSetter. Correct ?

Do you mean you have to change to
Code Block
ForEach( 1 ..< 10)
{ i in
Text("\(i)")
.frame(width: 100)
.opacity(0.8)
.background(BGViewSetter())
}
}


For it to work ?

I tried and did not notice any difference (when running in simulator, not in Preview)
In all cases, I get a rounded corner red view with nothing inside.
When testing,g in Preview, I get 3 buttons visible at top (4, 5, 6) in both cases.
  • What are you expecting as a result ?

  • What do you get ?

  • How do you know it is called / not called ?

@Claude31

Yes, Your code is what I meant as working (reading the frame of the background View of each Text views).
  • I am expecting Preferencekey to read the background View of HStack inside which contains

Code Block
Text("\(i)")
  • I get "0.0" frame size. It's NOT supposed to be "0.0"

  • If you look at the info above red bar "Final View : Pref Change : <has to be some number>" not 0.0. If you put preferencekeyed background as like your code, you will see some number. I want to read HStack view not individual Text views.

Since "jtmorris" mentioned that it works on ios13, seems like updated compiler issue (inconsistencies) .

It's been a year. I hope you've solved your problem. Try removing value.frame = nextValue().frame should solve your problem

SwiftUI : Why preferenceKey is not read/called
 
 
Q