【问题标题】:Creating a custom circular progress bar with a particular scroll animation effect创建具有特定滚动动画效果的自定义圆形进度条
【发布时间】:2018-02-07 07:43:16
【问题描述】:

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

  1. 围绕进度条外环旋转的发光动作

  2. 向下或向上滚动(折叠效果)时,效果为 漂亮

我正在尝试在这里实现这两种效果,感谢任何帮助:)

编辑:我使进度条正常工作 - 请参阅下面更新代码的屏幕截图:

我要创建三层,一层用于外圈,另一层用于虚线圈,另一层用于用实心圈填充虚线。 然后在三个进度条中使用这三个形状,见下面的代码: 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:

<?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

<?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:

<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>

附言很抱歉发了这么长的帖子。

【问题讨论】:

    标签: android progress-bar android-animation customization shape


    【解决方案1】:

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

    <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>
    

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

    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;

    对于showAnim() 使用这里parentProgress 是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);
    }
    }
    

    还可以查看this 和this 以获得更多了解

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-10-30
      • 2023-04-02
      • 2021-01-21
      • 2021-07-23
      • 2021-10-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多