Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Anchor point in SwiftUI

I'm playing with SwiftUI animations. I wanted to make a square bigger modifying its frame with an animation this way:

struct ContentView: View {
    let squareWidth = CGFloat(100)
    let squareHeight = CGFloat(100)

    @State private var bigger = false

    var body: some View {
        VStack {
            Color.green
                .frame(width: bigger ? self.squareWidth * 2 : self.squareWidth, height: self.squareHeight)
                .animation(.default)
            Button(action: {
                    self.bigger.toggle()
            }) {
                Text("Click me!")
            }
        }
    }
}

The animation happens from the centre of the View, that is the anchor point (0.5, 0.5). Is there a way to change this anchor point? I found out that I can use scaleEffect on the view specifying an anchor:

struct ContentView: View {
    let squareWidth = CGFloat(100)
    let squareHeight = CGFloat(100)

    @State private var bigger = false

    var body: some View {
        VStack {
            Color.green
                .frame(width: self.squareWidth, height: self.squareHeight)
                .scaleEffect(x: bigger ? 2 : 1, y: 1, anchor: .leading)
                .animation(.default)
            Button(action: {
                    self.bigger.toggle()
            }) {
                Text("Click me!")
            }
        }
    }
}

But it doesn't seem exactly the same. If I needed to apply several effects I should specify the anchor point for each of them, instead of specifying the anchor point on the view just one time. On UIKit I could write:

var myView = UIView(frame: CGRect(x: 0, y: 0, width: 100, height: 100))
myView.layer.anchorPoint = CGPoint(x: 0, y: 0.5) //that is, the .leading of SwiftUI
like image 429
matteopuc Avatar asked Aug 10 '19 14:08

matteopuc


People also ask

What is scaleEffect in SwiftUI?

scaleEffect(_:anchor:)Scales this view's rendered output by the given vertical and horizontal size amounts, relative to an anchor point.

What is offset in SwiftUI?

All views have a natural position inside your hierarchy, but the offset() modifier lets you move them relative to that natural position. This is particularly useful inside ZStack , where it lets you control how views should overlap.

Is SwiftUI faster?

App development speed In general, most of the developers are of the view that SwiftUI is the fastest way to create in-app functionalities. It requires very less code and can help you achieve almost the same results in a much lesser time when compared to UIKit.


1 Answers

It is possible, but your approach must change.

There is an implied, built-in centring of views in SwiftUI, which can be confusing.

The parent view is the one placing the content in the centre, recalculating the position of its subviews each time their frames change.

Embedding the VStack in a HStack and adding borders to both clearly shows this behaviour.

Also, note the Spacer(), which pushes the view to the left.

        HStack {
            VStack {
                Color.green
                    .frame(width: bigger ? self.squareWidth * 2 : self.squareWidth)
                    .frame(height: self.squareHeight)
                    .animation(.default)

                Button("Click me!") { self.bigger.toggle() }
            }.border(Color.black)

            Spacer()

        }.border(Color.red)

Using the .layer.anchorPoint in UIKit should have the same effect as using scaleEffect/offset/rotationEffect in SwiftUI, as it should affect the origin of the underlying geometry/texture which is being rendered by the GPU.

If you have a complex view (composed of multiple subviews) that needs the same scale effect, you can group them using a Group { } and use .scaleEffect on it.

like image 196
Vlad Lego Avatar answered Oct 31 '22 23:10

Vlad Lego