ProgressBar drawable如何工作?

and*_*per 4 android android-progressbar android-drawable

背景

我想作一个圆形的进度条是确定的(意思是机器人:不确定="假"),所以我在网上搜索,发现罗曼盖伊的简短的回答,在这里.

所以我抓住了代码并在示例项目中使用它:

布局文件的(部分):

<ProgressBar
    android:layout_width="50dp"
    android:layout_height="50dp"
    android:background="@color/backColor"
    android:indeterminate="false"
    android:indeterminateOnly="false"
    android:max="100"
    android:progress="33"
    android:progressDrawable="@drawable/progress" />
Run Code Online (Sandbox Code Playgroud)

绘制/ progress.xml

<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android" >

<!--    <item android:drawable="@drawable/progress_circular_background"/> -->
    <item>
        <shape  
            android:innerRadiusRatio="3.4"
            android:shape="ring"
            android:thicknessRatio="6.0" >
            <gradient
                android:endColor="#ffffffff"
                android:startColor="#ff000000"  
                android:type="sweep"
                android:useLevel="true" />

        </shape>
    </item>

    <item>
        <rotate
            android:drawable="@drawable/progress_particle"
            android:fromDegrees="0"
            android:pivotX="50%"
            android:pivotY="50%"
            android:toDegrees="360" />
    </item>

</layer-list>
Run Code Online (Sandbox Code Playgroud)

截图(不完全是当前代码):

在此输入图像描述

这个问题

它工作正常,但我不明白它是如何工作的.

进度条如何知道在drawables上究竟要改变什么,以及如何改变?

例如,它如何知道如何从右边0度而不是从其他地方获取戒指形状?

是否可以自定义它的工作方式?

mat*_*ash 8

ProgressBar通过更改关联的drawable 的级别来工作.在doRefreshProgress():

final int level = (int) (scale * MAX_LEVEL);
(progressDrawable != null ? progressDrawable : d).setLevel(level);
Run Code Online (Sandbox Code Playgroud)

一个可绘制的水平是,基本上,可能有不同类型的不同含义的整数Drawable子类.

这允许可绘制的基于连续控制器改变其图像,例如以显示进度或音量水平.

如果此级别更改导致Drawable的外观发生更改(因此需要无效),则返回true,否则返回false.

特别是,a GradientDrawable(有useLevel="true",例如这个)使用等级值来知道应该绘制哪个部分的可绘制部分.例如,对于从左到右的线性渐变,矩形计算如下:

final float level = st.mUseLevel ? (float) getLevel() / 10000.0f : 1.0f;    
x0 = r.left;            y0 = r.top;
x1 = level * r.right;   y1 = y0;
Run Code Online (Sandbox Code Playgroud)

在像这样的环形梯度的情况下,水平确定应该绘制总360度角的哪个部分:

float sweep = st.mUseLevelForShape ? (360.0f * getLevel() / 10000.0f) : 360f;
Run Code Online (Sandbox Code Playgroud)

简而言之,当setProgress()调用该方法时,该值改变,并且环逐渐填充.

至于RotateDrawable它,它使用相同的精确机制来progress_particle围绕其中心旋转位图(它只是一个90度的白点的透明正方形):

mState.mCurrentDegrees = mState.mFromDegrees +
    (mState.mToDegrees - mState.mFromDegrees) * ((float) level / MAX_LEVEL);
Run Code Online (Sandbox Code Playgroud)

最后,关于"它如何知道如何从右边0度采取环形"部分,这只是一个常规问题.Ring GradientDrawables从右侧开始.环路径计算中的第一行是:

// inner top
ringPath.moveTo(x + radius, y);
// outer top
ringPath.lineTo(x + radius + thickness, y);
Run Code Online (Sandbox Code Playgroud)