It should animate both the indicator's width and position:
We'll solve the challenge in two parts. First, we use anchors and preferences to collect the frames of each tab item. Second, we draw the selection indicator by resolving the anchor inside a geometry reader.
An anchor is an opaque layout value (for example, a CGPoint or CGRect) combined with a particular view. You cannot access the underlying values directly: to get access to the underlying value (e.g. a CGRect) you resolve the anchor using a geometry proxy. This makes for safer layout code. You can safely pass around these anchor values without having to manually convert between coordinate spaces.
We'll wrap each item in the tab bar using a Button, and set the selected index when the user taps the button. We'll also set a preference value to communicate the button's frame up the view hierarchy, but only if the item is currently selected. We set the item's color to be blue if selected, and the primary color otherwise. We'll add all of this code as a method on TabBar:
To create the indicator, we'll create a method that takes an optional CGRect anchor: if the anchor is not nil, it'll resolve it via a geometry proxy and draw a rectangle. To position the rectangle at the bottom of the proposed frame, we'll use a flexible frame with a maximum width and height set to .infinity. The actual size of that frame will be exactly the proposed size, and we can use the frame's alignment parameter to align the indicator with the bottom-leading corner.
From there, we use offset and frame to set the position and size of the indicator:
To tie everything together, we'll implement the view's body property: we loop over all the indices, draw the item, and use an overlayPreference to pass the anchor preference to the indicator. Unfortunately, the overlayPreferenceValue modifier does not have an alignment property; if it did, we could dispose the flexible frame in the snippet above:
Our new book, Thinking in SwiftUI, discusses the layout system in more detail in chapter four and five. At the time of writing, the first four chapters are already available for early access readers, with a new chapter and Q&A video released every week until the book is complete.