Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Not possible to get a natural animation size #323

Open
neon8bit opened this issue May 24, 2024 · 2 comments
Open

Not possible to get a natural animation size #323

neon8bit opened this issue May 24, 2024 · 2 comments

Comments

@neon8bit
Copy link

Description

In our app we would like to know a natural size of the rive animation that we download from an URL.
This is needed to layout a RiveView a certain way and also constrain other views to it.
More precisely, we need to know the width/height ratio of the initial animation so that we can resize a RiveView to fit exactly its content (e.g. set fixed width to a RiveView and let the height be dynamically calculated based on width/height ratio of the animation).
Unfortunately, we didn't find a way to implement it with rive.

Could you please give us an idea of how we could possibly get the animation's size data? Or if there's no such way yet, could you please implement this in Rive SDK in future releases?

Provide a Repro

import RiveRuntime
import UIKit

class ViewController: UIViewController, RiveFileDelegate {
    
    var riveViewModel: RiveViewModel?
    var riveView: RiveView?
    
    override func viewDidLoad() {
        super.viewDidLoad()
        let animationURL = "https://cdn.rive.app/animations/truck.riv"
        let riveFile = RiveFile(httpUrl: animationURL, loadCdn: true, with: self)
    }
    
    func riveFileDidLoad(_ riveFile: RiveFile) throws {
        let riveModel = RiveModel(riveFile: riveFile)
        self.riveViewModel = RiveViewModel(riveModel)
        self.riveView = self.riveViewModel?.createRiveView()
        
        // here we'd like to have some way to get a natural animation size:
        let animationSize: CGSize = riveViewModel.size 
        let ratio = animationSize.width / animationSize.height
        
        guard let riveView = self.riveView else { return }
        
        riveView.translatesAutoresizingMaskIntoConstraints = false
        view.addSubview(riveView)
        NSLayoutConstraint.activate([
            riveView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
            riveView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
            riveView.centerYAnchor.constraint(equalTo: view.centerYAnchor),

            // so here we would be able to use the ratio for constraining the riveView
            riveView.heightAnchor.constraint(equalTo: riveView.widthAnchor, multiplier: ratio)
        ])
    }
}

Source .riv/.rev file

In the repro a sample animation URL is used: https://cdn.rive.app/animations/truck.riv

Expected behavior

We would like to have the ability to get a natural size of the rive animation that we download from an URL.

Screenshots

We also noticed, that a RiveView is not being displayed if not all the constraints are externally provided for it. So, it's not being drawn based on intrinsic size. Intrinsic size always remains CGSize(width: -1.0, height: -1.0).

image

Device & Versions (please complete the following information)

  • Device: iOS Simulator, iPhone 14
  • iOS version: iOS 17.2

Additional context

We already used simple images (UIImage) and Lottie animations in the same context, and haven't had any similar problems. For example, Lottie provides a property LottieAnimation.size that returns a natural animation size. And for UIImage the following snippet also works fine with UIImage.size property:

import UIKit

class ViewController: UIViewController {
    
    override func viewDidLoad() {
        super.viewDidLoad()

        let imageView = UIImageView()
        imageView.translatesAutoresizingMaskIntoConstraints = false
        view.addSubview(imageView)
        NSLayoutConstraint.activate([
            imageView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
            imageView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
            imageView.centerYAnchor.constraint(equalTo: view.centerYAnchor),
        ])

        DispatchQueue.global().async {
            let sampleURL = URL(string: "https://fastly.picsum.photos/id/392/200/300.jpg?hmac=tcnub3WKREnSOdoCn7rQtfZkHXNWn5fXwNpHrv0o-5k")!
            let data = try! Data(contentsOf: sampleURL)
            DispatchQueue.main.async {
                let image = UIImage(data: data)!
                let ratio = image.size.height / image.size.width
                imageView.heightAnchor.constraint(equalTo: imageView.widthAnchor, multiplier: ratio).isActive = true
                imageView.image = image
            }
        }
    }
}
@chbeer
Copy link

chbeer commented Sep 17, 2024

I was able to create a hack to get aspectRatio from the RiveModel by subclassing RiveViewModel:

class MyRiveViewModel: RiveViewModel {
    
    @Published var aspectRatio: CGFloat = 1
    
    override func riveFileDidLoad(_ riveFile: RiveFile) throws {
        try super.riveFileDidLoad(riveFile)

        if let bounds = riveModel?.artboard.bounds() {
            aspectRatio = bounds.width / bounds.height
        }
    }
    
}

Then I was able to use that aspect ratio on the view:

    @StateObject var riveViewModel: MyRiveViewModel
    
    var body: some View {
        riveViewModel.view()
            .aspectRatio(riveViewModel.aspectRatio, contentMode: .fit)
            .frame(width: geoSize.width)
    }

@e-hartig
Copy link

The above didn't work for me, maybe because I was using a local asset, but using the same logic in a getAspectRatio function worked fine to pull the aspect ratio on demand. Also, the artboard is a public property, so the override is not necessary, just cleaner.

class CustomRiveViewModel: RiveViewModel {
    func getAspectRatio() -> CGFloat {
        if let bounds = riveModel?.artboard.bounds() {
            return bounds.width / bounds.height
        }
        return 1.0
    }
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants