为HexagonLoadingView添加淡入淡出动画

6

我使用了一个六边形加载器,基于库https://github.com/Agraphie/hexagonloadingview

但是我需要稍微不同的动画效果,类似于https://codepen.io/wuser/pen/BgPMqE

六边形视图动画的代码:

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.LinearGradient;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Shader;
import android.util.AttributeSet;
import android.view.View;

public class HexagonLoadingView extends View {

public static final int NUMBER_OF_HEXAGONS = 7;
/**
 * Constants for changing the number of appearance/disappearance of the hexagons. {@link
 * HexagonLoadingView#HEXAGON_UPPER_LEFT_APPEARANCE_POSITION} = 0 means the hexagon will start
 * appearing in the upper left corner. {@link HexagonLoadingView#HEXAGON_MIDDLE_MIDDLE_APPEARANCE_POSITION}
 * = 6 means this hexagon will appear last and disappear first.
 */
public static final int HEXAGON_UPPER_LEFT_APPEARANCE_POSITION = 0;
public static final int HEXAGON_UPPER_RIGHT_APPEARANCE_POSITION = 1;
public static final int HEXAGON_MIDDLE_LEFT_APPEARANCE_POSITION = 5;
public static final int HEXAGON_MIDDLE_MIDDLE_APPEARANCE_POSITION = 6;
public static final int HEXAGON_MIDDLE_RIGHT_APPEARANCE_POSITION = 2;
public static final int HEXAGON_LOWER_RIGHT_APPEARANCE_POSITION = 3;
public static final int HEXAGON_LOWER_LEFT_APPEARANCE_POSITION = 4;
/**
 * Increase this for a slower animation i.e. decrease this for a faster animation.
 */
public static final int APPEARANCE_SPEED_COEFFICIENT = 10;

/**
 * The radius of each hexagon.
 */
private float mRadius;

/**
 * The width and height of each hexagon.
 */
private float mWidth, mHeight;

/**
 * The various hexagons as {@link Path} objects.
 */
private Path mHexagonUpperRight;
private Path mHexagonMiddleRight;
private Path mHexagonLowerRight;
private Path mHexagonLowerLeft;
private Path mHexagonMiddleLeft;
private Path mHexagonUpperLeft;
private Path mHexagonMiddleMiddle;

/**
 * The {@link Paint} objects for each hexagon. Every hexagon can have its own colour.
 */
private Paint mHexagonPaintUpperRight = new Paint();
private Paint mHexagonPaintMiddleRight = new Paint();
private Paint mHexagonPaintLowerRight = new Paint();
private Paint mHexagonPaintLowerLeft = new Paint();
private Paint mHexagonPaintMiddleLeft = new Paint();
private Paint mHexagonPaintUpperLeft = new Paint();
private Paint mHexagonPaintMiddleMiddle = new Paint();

/**
 * Field for identifying if hexagons should be currently set to the background colour or to
 * their given colour.
 */
private boolean displayHexagons = true;

private float mRadiusStep;
private float[] mHexagonRadius;

public HexagonLoadingView(Context context) {
    super(context);
}

public HexagonLoadingView(Context context, AttributeSet attrs) {
    super(context, attrs);
}

public HexagonLoadingView(Context context, AttributeSet attrs, int defStyleAttr) {
    super(context, attrs, defStyleAttr);
}

/**
 * Method for calculating the hexagons, taking into account the current radius of the specified
 * hexagon.
 */
private void calculateHexagons() {
    mHexagonPaintUpperRight.setShader(new LinearGradient(0, 0, 0, getHeight(),
            getContext().getResources().getColor(R.color.hex_loading_color_8),
            getContext().getResources().getColor(R.color.hex_loading_color_9),
            Shader.TileMode.MIRROR));
    mHexagonPaintMiddleRight.setShader(new LinearGradient(0, 0, 0, getHeight(),
            getContext().getResources().getColor(R.color.hex_loading_color_8),
            getContext().getResources().getColor(R.color.hex_loading_color_9),
            Shader.TileMode.MIRROR));
    mHexagonPaintLowerRight.setShader(new LinearGradient(0, 0, 0, getHeight(),
            getContext().getResources().getColor(R.color.hex_loading_color_8),
            getContext().getResources().getColor(R.color.hex_loading_color_9),
            Shader.TileMode.MIRROR));
    mHexagonPaintLowerLeft.setShader(new LinearGradient(0, 0, 0, getHeight(),
            getContext().getResources().getColor(R.color.hex_loading_color_8),
            getContext().getResources().getColor(R.color.hex_loading_color_9),
            Shader.TileMode.MIRROR));
    mHexagonPaintMiddleLeft.setShader(new LinearGradient(0, 0, 0, getHeight(),
            getContext().getResources().getColor(R.color.hex_loading_color_8),
            getContext().getResources().getColor(R.color.hex_loading_color_9),
            Shader.TileMode.MIRROR));
    mHexagonPaintUpperLeft.setShader(new LinearGradient(0, 0, 0, getHeight(),
            getContext().getResources().getColor(R.color.hex_loading_color_8),
            getContext().getResources().getColor(R.color.hex_loading_color_9),
            Shader.TileMode.MIRROR));
    mHexagonPaintMiddleMiddle.setShader(new LinearGradient(0, 0, 0, getHeight(),
            getContext().getResources().getColor(R.color.hex_loading_color_8),
            getContext().getResources().getColor(R.color.hex_loading_color_9),
            Shader.TileMode.MIRROR));

    mHexagonUpperLeft = calculatePath((int) -(mRadius), (int) -(mRadius * 1.7),
            mHexagonRadius[HEXAGON_UPPER_LEFT_APPEARANCE_POSITION]);
    mHexagonUpperRight = calculatePath((int) (mRadius), ((int) -(mRadius * 1.7)),
            mHexagonRadius[HEXAGON_UPPER_RIGHT_APPEARANCE_POSITION]);
    mHexagonMiddleLeft = calculatePath((int) (-1.95 * mRadius), 0,
            mHexagonRadius[HEXAGON_MIDDLE_LEFT_APPEARANCE_POSITION]);
    mHexagonMiddleMiddle = calculatePath(0, 0,
            mHexagonRadius[HEXAGON_MIDDLE_MIDDLE_APPEARANCE_POSITION]);
    mHexagonMiddleRight = calculatePath((int) (1.95 * mRadius), 0,
            mHexagonRadius[HEXAGON_MIDDLE_RIGHT_APPEARANCE_POSITION]);
    mHexagonLowerLeft = calculatePath((int) -(mRadius), (int) (mRadius * 1.7),
            mHexagonRadius[HEXAGON_LOWER_LEFT_APPEARANCE_POSITION]);
    mHexagonLowerRight = calculatePath((int) (mRadius), (int) (mRadius * 1.7),
            mHexagonRadius[HEXAGON_LOWER_RIGHT_APPEARANCE_POSITION]);
}

@Override
public void onDraw(Canvas c) {
    //Check if this is the first load, if so don't do anything and display only the background
    //for a while
    calculateHexagons();

    //Count the hexagons up i.e. down i.e. make them appear or disappear.
    //Increase always only one hexagon at a time which has not been fully drawn yet.
    //Also check which hexagons have been completed.
    int completedHexagons = 0;
    if (displayHexagons) {
        for (int i = 0; i < mHexagonRadius.length; i++) {
            if (mHexagonRadius[i] < mRadius) {
                mHexagonRadius[i] += mRadiusStep;
                break;
            }
            completedHexagons++;
        }
    } else {
        for (int i = 0; i < mHexagonRadius.length; i++) {
            if (mHexagonRadius[i] > 0) {
                mHexagonRadius[i] = (mHexagonRadius[i] + (mRadiusStep * -1) < 0) ? 0
                        : mHexagonRadius[i] + (mRadiusStep * -1);
                break;
            }
            completedHexagons++;
        }
    }

    checkDrawingMode(completedHexagons);

    //Now draw our hexagons
    c.drawPath(mHexagonUpperLeft, mHexagonPaintUpperLeft);
    c.drawPath(mHexagonUpperRight, mHexagonPaintUpperRight);
    c.drawPath(mHexagonMiddleRight, mHexagonPaintMiddleRight);
    c.drawPath(mHexagonLowerRight, mHexagonPaintLowerRight);
    c.drawPath(mHexagonLowerLeft, mHexagonPaintLowerLeft);
    c.drawPath(mHexagonMiddleLeft, mHexagonPaintMiddleLeft);
    c.drawPath(mHexagonMiddleMiddle, mHexagonPaintMiddleMiddle);
}

/**
 * Method for checking how many hexagons are completed in their drawing. If all hexagons are
 * completed (i.e. all appeared or disappeared), invert the drawing mode to the opposite of what
 * it was.
 */
private void checkDrawingMode(int completedHexagons) {
    if (completedHexagons == NUMBER_OF_HEXAGONS) {
        displayHexagons = !displayHexagons;
    }
}

@Override
protected void onAttachedToWindow() {
    super.onAttachedToWindow();

    mHexagonRadius = new float[NUMBER_OF_HEXAGONS];
    mHexagonRadius[HEXAGON_UPPER_LEFT_APPEARANCE_POSITION] = 0;
    mHexagonRadius[HEXAGON_UPPER_RIGHT_APPEARANCE_POSITION] = 0;
    mHexagonRadius[HEXAGON_MIDDLE_RIGHT_APPEARANCE_POSITION] = 0;
    mHexagonRadius[HEXAGON_LOWER_RIGHT_APPEARANCE_POSITION] = 0;
    mHexagonRadius[HEXAGON_LOWER_LEFT_APPEARANCE_POSITION] = 0;
    mHexagonRadius[HEXAGON_MIDDLE_LEFT_APPEARANCE_POSITION] = 0;
    mHexagonRadius[HEXAGON_MIDDLE_MIDDLE_APPEARANCE_POSITION] = 0;
}

@Override
public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    mWidth = MeasureSpec.getSize(widthMeasureSpec);
    mHeight = MeasureSpec.getSize(heightMeasureSpec);
    mRadius = mHeight / 6;
    mRadiusStep = mRadius / APPEARANCE_SPEED_COEFFICIENT;
}


/**
 * Calculate the path for a hexagon.
 *
 * @param xCenterScale The offset in the x direction.
 * @param yCenterScale The offset in the y direction.
 * @return The calculated hexagon as {@link Path} object.
 */
private Path calculatePath(int xCenterScale, int yCenterScale, float radius) {
    float triangleHeight = (float) (Math.sqrt(3) * radius / 2);
    float centerX = (mWidth / 2) + xCenterScale;
    float centerY = (mHeight / 2) + yCenterScale;
    Path hexagonPath = new Path();

    hexagonPath.moveTo(centerX, centerY + radius);
    hexagonPath.lineTo(centerX - triangleHeight, centerY + radius / 2);
    hexagonPath.lineTo(centerX - triangleHeight, centerY - radius / 2);
    hexagonPath.lineTo(centerX, centerY - radius);
    hexagonPath.lineTo(centerX + triangleHeight, centerY - radius / 2);
    hexagonPath.lineTo(centerX + triangleHeight, centerY + radius / 2);
    hexagonPath.moveTo(centerX, centerY + radius);

    invalidate();

    return hexagonPath;
  }


} 

我怎样才能修改动画,使它与此完全相同:https://codepen.io/wuser/pen/BgPMqE


你尝试了什么,目前在哪个步骤卡住了? - azizbekian
我不确定在这段代码中应该修改哪里才能达到那种效果。 - SRBhagwat
2个回答

6
首先,对于图形性能来说,在onDraw方法中计算每个六边形真的很昂贵,因为它创建了一个着色器,为每个六边形造成阻塞主线程的问题。您可以在onSizeChanged回调中计算您的六边形。然后,您可以使用画布的canvas.translate()canvas.scale()方法绘制每个六边形。每个六边形的平移和缩放是按照动画器经过的时间计算的。对于这样一种动画情况,您可以使用TimerAnimator。一旦在您的视图中启动TimerAnimator,它就会在每16ms调用您的回调函数。在此回调中,您可以为您的视图调用invalidate()。为了计算每个六边形的alpha值,您还应该使用经过的时间。对于此视图,只需要一个Paint即可。此外,在视图变为不可见或消失状态时,请不要忘记停止TimerAnimator。

0

我会将SVG切成单独的形状,然后可以对它们进行动画处理(或使用After Effects和Lottie,这样的动画效果非常好,例如)。这个动画的棘手之处在于,它从中心transform-origin: 50% 50%;缩放而不是它们的最终位置 - 所以这是一个向外/向内的方向移动,同时缩放它们。

基本上,这是6个ValueAnimatorAnimatorSet...

请参阅文档


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接