UPGRADE YOUR SKILLS: Learn advanced Swift and SwiftUI on Hacking with Swift+! >>

Animate rotation3DEffect in a circular way

Forums > SwiftUI

Hello there,

I'm trying to get an animation similar to what we have in the iOS Widget picker where a view 3D rotates in X and Y in circle, without reverse:

GIF

I've tried to play a little bit with rotation3DEffect without success to get a coutinuous rotation.

Anyone sees what I'm missing?

P.S. Kudos if you have any input to do the 3D shadow behind it!

@State private var rotate = false

View()
.rotation3DEffect(.degrees(rotate ? 12 : -12), axis: (x: rotate ? 90 : -45, y: rotate ? -45 : -90, z: 0))
.animation(.linear(duration: 8).repeatForever(autoreverses: true), value: rotate)
.onAppear {
        rotate.toggle()
}

1      

I agree. But by setting it to false, I couldn't find any setting where I could achieve a continuous rotation without any snap at the end of the animation loop. My example above is somehow what I could do at best but without getting the excepted result…

1      

I think you want TWO animations.

The first will twist your clock face left and right like an old school radio dial.
The second will tilt your clock face forward and backwards, like nodding your head yes and no.

The trick is you want the twisting and the nodding to both take the same amount of time, for example two seconds. However you want them out of phase with each other by one second. This is where I use the delay(1) modifier.

In this manner, as the clock face is fully twisted left, it has zero tilt forward or backwards.
When the clock face is half way twisted left, it is half way tilted forward.
When the clock facs is has neither left nor right twist, it is fully tilted forward.
When the clock face is half way twisted right, it is half way tilted forward.
When the clock face is fully twisted right, it has neutral tilt.

This pattern reverses giving you a smooth left to right twist, combined with a smooth back and forth tilt.

At least this is what I think you're after.

Please report back! Let us know how you solved this!

//  RotateClockView.swift
//  Created by Obelix on 3/20/22.
//
import SwiftUI
struct ClockFaceView: View {
    var body: some View {
        // Clock Face
        Circle()
            .foregroundColor(.cyan).opacity(0.8)
            .frame(width: 200, height: 200, alignment: .center)
        // Ticks
        ForEach(0..<60) {
            Circle()
                .foregroundColor($0.isMultiple(of: 5) ? .blue : .white)
                .frame(width: $0.isMultiple(of: 5) ? 8 : 3, height: 8)
                .offset(y: -90)
                .rotationEffect(.degrees(Double($0) * 6)) // rotate the tick marks
        }
    }
}

struct RotateClockView: View {
    @State private var isRotating = false
    private var xAxis: CGFloat = 1.0 // nod face back and forth
    private var zAxis: CGFloat = 1.0 // rotate face left and right like a dial

    var body: some View {
        ZStack {
            Rectangle()  // x Axis Guide. Guides help me visualize the tilt motions.
                .foregroundColor( xAxis > 0 ? .black : .clear )
                .frame(width: 300, height: 3)
            Rectangle()  // z Axis Guide
                .foregroundColor( zAxis > 0 ? .blue : .clear )
                .frame(width: 3, height: 300)
            ClockFaceView()
        }
        // Rotate clock back and forth over x axis
        .rotation3DEffect(.degrees(isRotating ? 20 : -20), axis: (x: xAxis, y: 0, z:  0))
        .animation(.easeInOut(duration: 2).repeatForever(autoreverses: true), value: isRotating)
        // Spin clock face left and right over z axis
        .rotation3DEffect(.degrees(isRotating ? 20 : -20), axis: (x: 0, y: 0, z:  zAxis))
        .animation(.easeInOut(duration: 2).repeatForever(autoreverses: true).delay(1.0), value: isRotating)
        .onAppear { isRotating.toggle() }
    }
}

1      

Also, check the documentation.

The values for x, y, and z axis should be values from zero to one.

You've inserted degrees, and some are negative. Not sure why the compiler is not complaining. (Maybe it's me who needs to check the documentation!)

1      

Wow, this is exactly what I was looking for... and didn't execept a whole precise solution like this!

The funny thing is that using two rotation3DEffect and two animations was my very first idea... but using X and Y axis. And for whatever reason when you chain two rotation3DEffect, one on X and the other on Y, you get a blurry view. Not sure if this is a SwiftUI rendering bug or if there is a reason for this... anyway then I was sure there was a way of doing it using only one rotation3DEffect...

Concerning the limits between 0 and 1 for axis values, I noticed the doc but found multiple examples using higher values... but same feeling, not sure why the compiler allows this (and that it actually works).

Many thanks for your help @Obelix !

1      

You noted:

The funny thing is that using two rotation3DEffect and two animations was my very first idea... but using X and Y axis.

Look at your monitor in front of you.

The X Axis would be tilting your monitor backwards to face the ceiling, or forwards to face the keyboard.

The Y Axis would be moving the monitor to show someone sitting to your left, or the other way to show someone sitting on your right.

The Z Axis would be twisting your monitor from a landscape orientation to a portrait orientation.

You could get nice effects from adjusting all three parameters in a 3D Rotation effect.

Homework

Here's a homework assignment!

Add three vars to your RotateClockView, one each for X, Y and Z axis. Then add three sliders to your user interface. Allow the user to slide the values from zero to one and update the 3D rotation in real time. Find the three values that like you best!

Post your updated code here, please!

1      

Feel free to pick an answer here and mark it as "Solved"

This way we don't keep revisiting your question and others might find the answer to a similar question.

1      

Hacking with Swift is sponsored by Essential Developer

SPONSORED Join a FREE crash course for mid/senior iOS devs who want to achieve an expert level of technical and practical skills – it’s the fast track to being a complete senior developer! Hurry up because it'll be available only until April 28th.

Click to save your free spot now

Sponsor Hacking with Swift and reach the world's largest Swift community!

Archived topic

This topic has been closed due to inactivity, so you can't reply. Please create a new topic if you need to.

All interactions here are governed by our code of conduct.

 
Unknown user

You are not logged in

Log in or create account
 

Link copied to your pasteboard.