Greetings, traveler!
Have you ever tried to apply rotationEffect to a SwiftUI view that already has glassEffect?
The code looks innocent:
Text("Hello world")
.padding()
.glassEffect()
.rotationEffect(.degrees(20))
At first glance, this is exactly how SwiftUI code should look. Create a text view, add padding, apply Liquid Glass, then rotate the result.
But the visual result can be disappointing. The glass may shift in a strange way, lose its symmetry, or change its shape so that the whole component looks slightly broken. It is not the kind of rotation you expect when you think, “Just rotate this pill-shaped glass view by 20 degrees.”
This happens because Liquid Glass is more geometry-sensitive than a simple background. It is not just a color or a blur behind the text. SwiftUI anchors the Liquid Glass effect to the bounds of the view. Once transforms enter the picture, the relationship between the rendered content, the glass shape, and layout geometry becomes more visible.
The problem with a regular rotationEffect
Apple documents rotationEffect(_:anchor:) as a modifier that rotates the view’s content around the axis that points out of the xy-plane. It also says that this modifier has no effect on the view’s frame.
In many SwiftUI layouts, this behavior is exactly what you want. You can rotate a view visually without asking the parent layout to reserve a different amount of space. The original frame stays where it was.
With Liquid Glass, though, the result may still look wrong. The glass effect is tied to the view’s bounds and rendered shape. When the content is rotated after the glass effect, the visual transform can make the glass feel like it is no longer aligned with the component you wanted to rotate.
In other words, the frame may remain stable, but the glass does not necessarily look stable.
The text rotates. The glass rotates too. But the shape can appear offset, asymmetric, or visually distorted.
A workaround with ignoredByLayout
One workaround is to apply the rotation as a GeometryEffect and then call ignoredByLayout() on that effect:
Text("Hello world")
.padding()
.glassEffect()
.modifier(
_RotationEffect(angle: .degrees(20))
.ignoredByLayout()
)_RotationEffect is the internal SwiftUI geometry effect that powers rotationEffect. It represents rotation as a GeometryEffect, which means it can be passed to .modifier(...) and then combined with ignoredByLayout().
In SwiftUI/Swift, attributes or types with _ are usually implementation details, not the API surface Apple expects you to use directly. So, the contract may change at any moment.
Anyway, the important part is not _RotationEffect by itself. The important part is ignoredByLayout().
Apple describes ignoredByLayout() as a method on GeometryEffect. It returns an effect that produces the same geometry transform as the original effect, but applies that transform only while rendering the view.
During layout calculations, SwiftUI ignores the transform returned by the effect.
That gives us a useful split:
- Rendering sees the rotation
- Layout calculations ignore the rotation.
For a Liquid Glass view, this can help because the rotation becomes a visual transform rather than something that participates in layout geometry. The glass keeps behaving as if it belongs to the original unrotated bounds, while the final rendered result is rotated.
This is why the workaround often looks much better than plain rotationEffect.
Why this helps
SwiftUI layout and SwiftUI rendering are related, but they are not the same thing.
Layout answers questions like:
How much space does this view need?
Where should it be placed?
What bounds should other layout-dependent systems use?
Rendering answers a different question:
What should be drawn on the screen?
A GeometryEffect can transform the rendered geometry of a view. Rotation, scaling, translation, and custom matrix transforms all fit into this idea.
ignoredByLayout() tells SwiftUI to keep the transform out of layout calculations. The view is still rendered with the transform, but layout behaves as if the transform was not there.
For Liquid Glass, that distinction is useful because the effect depends on the shape and bounds of the view. If the transform affects the geometry used around the glass effect, the result can feel unstable. If the transform is only applied at render time, the glass keeps a cleaner relationship with its original shape.
Where else ignoredByLayout can help
Liquid Glass is not the only place where ignoredByLayout() can be useful.
The same idea applies whenever you want a geometry transform to be visual only.
A common example is a shake animation for validation errors. You want the field to shake left and right, but you do not want the parent layout, anchors, or geometry readers to react as if the field is changing its position.
struct ShakeEffect: GeometryEffect {
var amount: CGFloat = 8
var shakesPerUnit: CGFloat = 3
var progress: CGFloat
var animatableData: CGFloat {
get { progress }
set { progress = newValue }
}
func effectValue(size: CGSize) -> ProjectionTransform {
ProjectionTransform(
CGAffineTransform(
translationX: amount * sin(progress * .pi * shakesPerUnit),
y: 0
)
)
}
}Usage:
TextField("Email", text: $email)
.modifier(
ShakeEffect(progress: trigger)
.ignoredByLayout()
)The field moves visually, but layout can continue to treat it as stable.
This can also help around custom transitions. Apple explicitly mentions using ignoredByLayout() to disable layout changes during transitions. That makes sense. During a transition, you often want a view to move, rotate, or scale as part of the animation, but you may not want that temporary transform to affect layout.
It can also be useful when you work with layout-sensitive APIs such as:
- GeometryReader
- anchorPreference
- matched geometry style effects
- custom Layout implementations
- custom GeometryEffect animations
Any time you read geometry and then use that geometry to position something else, transforms can become tricky. ignoredByLayout() gives you a way to say, “This effect is only for drawing. Do not let it pollute the geometry model.”
When not to use it
I would not reach for ignoredByLayout() by default. Most of the time, regular SwiftUI modifiers are enough:
.offset(x: 20)
.scaleEffect(1.1)
.rotationEffect(.degrees(10))If the result looks correct and your layout is stable, there is nothing to fix.
ignoredByLayout() is useful when you can see that a visual transform is leaking into layout-dependent behavior. Use it when the transform should be visual only.
Final thoughts
ignoredByLayout() is a small API, but it explains an important part of SwiftUI. A view can have layout geometry and rendered geometry. Most of the time, you do not need to think about the difference. SwiftUI hides it well.
