When developing using SwiftUI, there are situations where we need to get the frame of a subview in its ancestor view. For instance, I am currently working on a feature where upon long-pressing a button, the user can move their finger to a specific view in order to cancel a certain process, similar to voice input in WeChat.
At this moment, it is essential to obtain the precise frame of a particular view to verify if the user’s finger is positioned on it.
GeometryReader
To obtain the frame of a view, we can utilize the GeometryReader
in SwiftUI. By wrapping a view with a GeometryReader, we can access its precise position and frame infomation.
By incorporating a GeometryReader, we gain the ability to accurately determine the dimensions and location of a specific view.
Look at the following code
1 | struct SomeView: View { |
There are three ractangles. If we need to know the x, y, width, height of the middle one. We can put this rectangle inside a GeometryReader, like this:
1 | struct SomeView: View { |
Then we can display the size on the rectangle using overlay
.
1 | struct SomeView: View { |
Also the x, y position:
1 | struct SomeView: View { |
We have got the exact postion and frame of the middle rectangle.
But the data can only be used in the rectangle view. What if we want to use them in parent view?
We need use the PreferenceKey to pass the infomation from inner to outside.
PreferenceKey
To use a preference key, we need to define a struct first.
1 | struct GeometryPreferenceKey: PreferenceKey { |
PreferenceKey
is a protocol. To confirm this protocol, we need a defaultValue
static property. We can designate the type of defaultValue by our demand. Here, I let it be CGRect and give it a default value .zero
.
Then, we must implement another method called reduce
.
1 | struct GeometryPreferenceKey: PreferenceKey { |
This reduce method looks like the common reduce method in Swift standard library. It can be used to handle a initial value and a new value. Combine them by some means. Here, we just replace the old value with the new one. The first parameter value is an inout parameter.
Then we can put the value into the preference by the custom key.
1 | struct SomeView: View { |
Give the rectangle a view modifier called preference
, specify the key to GeometryPreferenceKey.self
we just defined. Put the value we need into the value parameter.
Then use .onPreferenceChange
on the outside VStack
, we can get the value here.
We can print the value, or store it in a @State
property.
So we have got the data we need, we can use it to implement a lot of features.
Conclusion
GeometryReader and PreferenceKey are incredibly useful features in SwiftUI. They provide powerful tools to address a wide range of challenges. It is essential to have a good understanding of these concepts as they can greatly enhance your SwiftUI development skills.