创建具有特定滚动动画效果的自定义圆形进度条 [英] Creating a custom circular progress bar with a particular scroll animation effect

查看:128
本文介绍了创建具有特定滚动动画效果的自定义圆形进度条的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试创建一个具有特定滚动动画效果的自定义进度条,该效果看起来或多或少类似于 mi fit android应用中的滚动效果,请参见以下屏幕截图: 如果仔细查看gif,您会发现两件事-

I am trying to create a custom progress bar with a particular scroll animation effect that looks more or less like the one in mi fit android app, see screen shot below : If you see the gif carefully you will notice two things -

  1. 围绕进度条外圈旋转的发光运动

  1. A glowing motion revolving around the progress bars outer ring

向下或向上滚动(崩溃效果)时,效果为 美丽

when scrolled down or up (collapsing effect), the effects are beautiful

我正在尝试实现这两种效果,感谢您的帮助:)

I am trying to achieve these two effects here, any help is appreciated :)

我使进度条正常工作-参见下面带有更新代码的屏幕截图:

我接下来要创建三层,一层用于外圆,另一层用于虚线圆,另一层用于用实心圆填充虚线. 然后在三个进度栏中使用这三个形状,请参见下面的代码: layout.xml :

What I am following is creating three layers, one for outer circle other for dash circle and another for filling the dashed with solid circle. Then using these three shapes in three progress bars, see code below : layout.xml :

<?xml version="1.0" encoding="utf-8"?><RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/colorPrimary"
android:gravity="center">

<ProgressBar
                    android:id="@+id/progressBar1"
                    style="?android:attr/progressBarStyleHorizontal"
                    android:layout_width="250dp"
                    android:layout_height="250dp"
                    android:layout_centerInParent="true"
                    android:max="100"
                    android:progress="100"
                    android:progressDrawable="@drawable/circular_layer_outer" />

                <ProgressBar
                    android:id="@+id/progressBar2"
                    style="?android:attr/progressBarStyleHorizontal"
                    android:layout_width="230dp"
                    android:layout_height="230dp"
                    android:layout_centerInParent="true"
                    android:max="100"
                    android:progress="100"
                    android:progressDrawable="@drawable/circular_layer_dash_inner" />

                <ProgressBar
                    android:id="@+id/main_progressBar"
                    style="?android:attr/progressBarStyleHorizontal"
                    android:layout_width="226dp"
                    android:layout_height="226dp"
                    android:layout_centerInParent="true"
                    android:max="100"
                    android:progress="80"
                    android:progressDrawable="@drawable/circular_layer_dash_filler"
                    android:visibility="visible" />

两种形状的进度: circular_layer_dash_inner.xml :

And the shapes for both progress : circular_layer_dash_inner.xml :

<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android"
    android:paddingBottom="13dp"
    android:paddingLeft="13dp"
    android:paddingRight="13dp"
    android:paddingTop="13dp">
    <item>
        <rotate
            android:fromDegrees="270"
            android:pivotX="50%"
            android:pivotY="50%"
            android:toDegrees="270">
            <shape
                android:dither="true"
                android:innerRadiusRatio="3"
                android:shape="ring"
                android:thickness="0sp"
                android:useLevel="true">
                <solid android:color="@color/white" />
                <stroke
                    android:width="1dp"
                    android:color="@color/white"
                    android:dashGap="2dp"
                    android:dashWidth="1dp" />
            </shape>
        </rotate>
    </item>
</layer-list>

circular_layer_dash_filler.xml

circular_layer_dash_filler.xml

<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android"
    android:paddingBottom="13dp"
    android:paddingLeft="13dp"
    android:paddingRight="13dp"
    android:paddingTop="13dp">
    <item>
        <rotate
            android:fromDegrees="270"
            android:pivotX="50%"
            android:pivotY="50%"
            android:toDegrees="270">
            <shape
                android:dither="true"
                android:innerRadiusRatio="3"
                android:shape="ring"
                android:thickness="2sp"
                android:useLevel="true">
                <solid android:color="@color/white" />
            </shape>
        </rotate>
    </item>
</layer-list>

circular_layer_outer.xml :

circular_layer_outer.xml :

<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item>
    <shape
        android:innerRadiusRatio="3"
        android:shape="ring"
        android:thickness="8sp"
        android:useLevel="true">
        <solid android:color="@color/white" />
    </shape>
</item>

p.s.对不起,很长的帖子.

p.s. sorry for the long post.

推荐答案

我能够通过以下方式创建动画:

I was able to create the animation through the following way :

<android.support.design.widget.AppBarLayout
    android:id="@+id/appBar"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:background="@color/blue"
    android:fitsSystemWindows="true">

    <android.support.design.widget.CollapsingToolbarLayout
        android:id="@+id/collapsingToolbar"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:fitsSystemWindows="true"
        app:expandedTitleGravity="center_horizontal"
        app:layout_scrollFlags="scroll|exitUntilCollapsed">

        <RelativeLayout
            android:id="@+id/layers_progress"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:background="@color/blue_safe"
            app:layout_collapseMode="parallax">

            <ProgressBar
                android:id="@+id/progressBar1"
                style="?android:attr/progressBarStyleHorizontal"
                android:layout_width="250dp"
                android:layout_height="250dp"
                android:layout_centerInParent="true"
                android:max="100"
                android:progress="100"
                android:progressDrawable="@drawable/circular_layer_outer" />

            <ProgressBar
                android:id="@+id/progressBar2"
                style="?android:attr/progressBarStyleHorizontal"
                android:layout_width="230dp"
                android:layout_height="230dp"
                android:layout_centerInParent="true"
                android:max="100"
                android:progress="100"
                android:progressDrawable="@drawable/circular_layer_dash_inner" />

            <ProgressBar
                android:id="@+id/main_progressBar"
                style="?android:attr/progressBarStyleHorizontal"
                android:layout_width="226dp"
                android:layout_height="226dp"
                android:layout_centerInParent="true"
                android:max="100"
                android:progress="80"
                android:progressDrawable="@drawable/circular_layer_dash_filler"
                android:visibility="visible" />

        </RelativeLayout>

        <TextView
            android:id="@+id/score_val"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center"
            android:text="Score"
            android:textColor="@color/white"
            android:textSize="36sp"
            android:textStyle="bold"
            android:visibility="visible"
            app:layout_collapseMode="parallax" />

    </android.support.design.widget.CollapsingToolbarLayout>
</android.support.design.widget.AppBarLayout>

在这里可以看到在AppBarLayout内部使用了CollapsingToolbarLayout,然后使用AppBarLayout并设置OnOffsetChangedListener来监听AppBarLayout的高度值变化,请参见下面的代码:

Here one can see a CollapsingToolbarLayout is used inside AppBarLayout and then using the AppBarLayout and setting an OnOffsetChangedListener to listen to change in value of height of AppBarLayout, See code below :

AppBarLayout appbar = findViewById(R.id.appBar);
        appbar.addOnOffsetChangedListener(DashboardScore.this);

然后在onOffsetChanged中:

@Override
public void onOffsetChanged(AppBarLayout appBarLayout, int verticalOffset) {
    if (mMaxScrollSize == 0)
        mMaxScrollSize = appBarLayout.getTotalScrollRange();

    currentScrollPercentage = (Math.abs(verticalOffset)) * 100 / mMaxScrollSize;
    Log.d("Debug info", "% == " + currentScrollPercentage + "  -- mMaxScrollSize  == " + mMaxScrollSize + " vertical offset - " + verticalOffset);
    showAnim(oldScrollPercentage, currentScrollPercentage);
    oldScrollPercentage = currentScrollPercentage;
}

此处private int mMaxScrollSize; private int currentScrollPercentage, oldScrollPercentage = 0;

Here private int mMaxScrollSize; private int currentScrollPercentage, oldScrollPercentage = 0;

showAnim()使用,此处parentProgress是您的ProgressBars父级:

And for showAnim() use and here parentProgress is your parent of ProgressBars:

void showAnim(int fromDegree, int toDegree) {
    final float centerX = parentProgress.getWidth() / 2.0f;
    final float centerY = parentProgress.getHeight() / 2.0f;
    final Rotate3dAnimation rotation = new Rotate3dAnimation(fromDegree, toDegree, centerX, centerY, 5.0f, false);
    rotation.setDuration(400);
    rotation.setFillAfter(true);
    rotation.setInterpolator(new AccelerateInterpolator());
    parentProgress.startAnimation(rotation);
    if (currentScrollPercentage > 0) {
        if (fromDegree < 90)
            parentProgress.setAlpha(1 - Math.abs((float) currentScrollPercentage / 100f));
        else
            parentProgress.setAlpha(0);

        Log.d("Debug info", "setAlpha ==  " + (1 - Math.abs((float) currentScrollPercentage / 100f)));
    }
}

对于Rotate3dAnimation,请使用:

public class Rotate3dAnimation extends Animation {
private final float mFromDegrees;
private final float mToDegrees;
private final float mCenterX;
private final float mCenterY;
private final float mDepthZ;
private final boolean mReverse;
private Camera mCamera;

/**
 * Creates a new 3D rotation on the Y axis. The rotation is defined by its
 * start angle and its end angle. Both angles are in degrees. The rotation
 * is performed around a center point on the 2D space, definied by a pair
 * of X and Y coordinates, called centerX and centerY. When the animation
 * starts, a translation on the Z axis (depth) is performed. The length
 * of the translation can be specified, as well as whether the translation
 * should be reversed in time.
 *
 * @param fromDegrees the start angle of the 3D rotation
 * @param toDegrees   the end angle of the 3D rotation
 * @param centerX     the X center of the 3D rotation
 * @param centerY     the Y center of the 3D rotation
 * @param reverse     true if the translation should be reversed, false otherwise
 */
public Rotate3dAnimation(float fromDegrees, float toDegrees,
                         float centerX, float centerY, float depthZ, boolean reverse) {
    mFromDegrees = fromDegrees;
    mToDegrees = toDegrees;
    mCenterX = centerX;
    mCenterY = centerY;
    mDepthZ = depthZ;
    mReverse = reverse;
}

@Override
public void initialize(int width, int height, int parentWidth, int parentHeight) {
    super.initialize(width, height, parentWidth, parentHeight);
    mCamera = new Camera();
}

@Override
protected void applyTransformation(float interpolatedTime, Transformation t) {
    final float fromDegrees = mFromDegrees;
    float degrees = fromDegrees + ((mToDegrees - fromDegrees) * interpolatedTime);

    final float centerX = mCenterX;
    final float centerY = mCenterY;
    final Camera camera = mCamera;

    final Matrix matrix = t.getMatrix();

    camera.save();
    if (mReverse) {
        camera.translate(0.0f, 0.0f, mDepthZ * interpolatedTime);
    } else {
        camera.translate(0.0f, 0.0f, mDepthZ * (1.0f - interpolatedTime));
    }
    //camera.rotateY(degrees);
    camera.rotateX(degrees);
    camera.getMatrix(matrix);
    camera.restore();

    matrix.preTranslate(-centerX, -centerY);
    matrix.postTranslate(centerX, centerY);
}
}

还要选中

Also Check this and this for more understanding

这篇关于创建具有特定滚动动画效果的自定义圆形进度条的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆