airbnb / lottie-android

Render After Effects animations natively on Android and iOS, Web, and React Native
http://airbnb.io/lottie/
Apache License 2.0
34.96k stars 5.4k forks source link

[not bug]The bounds obtained through BaseLayer.getBounds() are not accurate. #2526

Closed UI-Animation-Chen closed 1 month ago

UI-Animation-Chen commented 1 month ago

Firstly, this is NOT a bug.

Hello, Lottie team, thanks a lot for your great lottie library. I now want to add the click event capability to the animation elements in Lottie. The implementation principle is to obtain the bounds of the BaseLayer, then convert it back to the bounds in the coordinate system of the screen, and judge whether the layer is clicked through the x and y in the MotionEvent.

  1. The conversion of the obtained bounds to the bounds in the screen coordinates is implemented as follows:

    RectF layerTransformedRect = new RectF();
    layer.getBounds(layerTransformedRect, null, false); // get the transformed bounds
    
    RectF layerOriginRect = new RectF();
    
    float viewW = getWidth(); // LottieAnimationView's width
    float viewH = getHeight(); // LottieAnimationView's height
    
    float lottieW = lottieDrawable.getBounds().width();
    float lottieH = lottieDrawable.getBounds().height();
    
    if (viewW == 0 || viewH == 0 || lottieW == 0 || lottieH == 0) {
        return;
    }
    
    // just for ScaleType.CenterCrop
    Matrix m = new Matrix();
    float scale;
    if ((lottieW / lottieH) >= (viewW / viewH)) {
        // height fill up,width crop
        scale = viewH / lottieH;
        m.preScale(scale, scale);
        m.postTranslate(-((lottieW * scale - viewW) / 2), 0);
    } else {
        // width fill up,height crop
        scale = viewW / lottieW;
        m.preScale(scale, scale);
        m.postTranslate(0, -((lottieH * scale - viewH) / 2));
    }
    m.mapRect(layerOriginRect, layerTransformedRect);
  2. Then it was found that the bounds of some Layers were accurate, but there were some offsets for the layers under the CompositionLayer, like image below. I would like to ask, why are there offsets for the layers under the CompositionLayer? Do different layers need special handling when obtaining the bounds? Looking forward to your reply. Thank you :)

image
gpeal commented 1 month ago

Could you attach a repro?

UI-Animation-Chen commented 1 month ago

Could you attach a repro?

Hello, this is not an occasional occurrence, but a definite one. I have provided a demo here. The method for finding the layer bounds is in lines 225 to 337 of LottieAnimationView. I'm really looking forward to you checking the logic inside and giving some suggestions. The link of the demo is here: https://github.com/UI-Animation-Chen/LottieDemo.git

After opening the demo, the Lottie animation will be executed and then stop at frame 200. At this point, you can click on each element in the Lottie animation. The bounds obtained in the middle red envelope area are a bit lower than the displayed one.

UI-Animation-Chen commented 1 month ago

The solution has been found. When obtaining the bounds through layer.getBounds(outRect, parentMatrix, true), the second and third parameters need to pass in parentMatrix and true, instead of null and false. Thanks to the excellent lottie library.