ring shapes for L preview not working

后端 未结 3 1869
忘了有多久
忘了有多久 2020-12-14 11:11

Just testing the new developer preview and noticed that my existing ring drawables are not rendering properly. Instead of a ring it\'s a full circle. Is it a bug or has some

相关标签:
3条回答
  • 2020-12-14 11:28

    You need to add android:useLevel="true" in the progress item. This didn't seem necessary in previous versions, but L wants it.

    <item android:id="@android:id/progress">
        <shape
            android:innerRadiusRatio="3"
            android:shape="ring"
            android:thicknessRatio="7.0"
            android:useLevel="true" >
            <solid android:color="#ff5698fb"/>
        </shape>
    </item>
    
    0 讨论(0)
  • 2020-12-14 11:33

    TL;DR: Explicitly set the value of useLevel for all ring shapes used in custom progress bars.


    Kano's answer is the way to solve your problem. I'm complementing it to add general info about ring shapes in custom progress bars.

    It seems as if the default value for useLevel has changed over the Android versions. Here is a piece on investigation related to it.

    The following is a working implementation of a progress bar using a ring as a progress indicator, and another ring as the progress background:

    <?xml version="1.0" encoding="utf-8"?>
    
    <layer-list xmlns:android="http://schemas.android.com/apk/res/android">
        <!-- Progress background -->
        <item android:id="@android:id/background">
            <shape
                android:shape="ring"
                android:useLevel="false">
                <solid
                    android:color="#dae1e6"/>
            </shape>
        </item>
    
        <!-- Progress -->
        <item android:id="@android:id/progress">
            <!-- Rotation of the progress to start at the top-->
            <rotate
                android:fromDegrees="-90"
                android:pivotX="50%"
                android:pivotY="50%"
                android:toDegrees="-90">
                <shape
                    android:shape="ring"
                    android:useLevel="true">
                    <solid
                        android:color="#61bcf9"/>
                </shape>
            </rotate>
        </item>
    
    </layer-list>
    

    Using it as a progressDrawable in a ProgressBar:

    <ProgressBar
        style="?android:attr/progressBarStyleHorizontal"
        android:layout_width="100dp"
        android:layout_height="100dp"
        android:progressDrawable="@drawable/custom_horizontal"
        android:progress="50"
        android:max="100"
        android:id="@+id/progressBar"
        android:layout_gravity="center"/>
    

    Setting useLevel=true to the progress ring shape and useLevel=false in the background ring shape, gives the correct desired behavior for all Android versions:

    Correct in both versions

    Removing useLevel from the background shape:

    Pre 5.0 (left) | 5.0 (right)

    Incorrect in KitKat Correct in Lollipop

    Removing useLevel from the progress shape:

    Pre 5.0 (left) | 5.0 (right)

    Correct in KitKat Incorrect in Lollipop


    So, as I understand, useLevel is used to indicate whether the shape is affected by the progress value. If it isn't (false), it'll be fully painted; if it is (true), it'll be painted as much as the progress value is.

    To sum up, it seems that:

    • useLevel is defaulted to true in Android < 5.0, causing the background ring to follow the progress value if useLevel is not set in its ring shape, thus making it hidden behind the progress indicator ring.
    • useLevel is defaulted to false in Android >= 5.0, causing the progress indicator ring to be fully painted if useLevel is not set in its ring shape.

    So, due to this inconsistency, it's better to explicitly set the value of useLevel to true in the shapes which depend on the progress, and to false in the ones that don't.

    This behavior is based on my observations, I haven't found any source confirming it. The official Android docs are not very clear about it...

    0 讨论(0)
  • 2020-12-14 11:37

    Just want to add some references in framework source code to confirm that useLevel is defaulted to true in Android API version < 21 (< 5.0) and defaulted to false in API version >= 21 (>= 5.0) as Christian García previously stated.

    In android-20, file GradientDrawable.java, line 820-835:

    if (shapeType == RING) {
        ....
        st.mUseLevelForShape = a.getBoolean(
                        com.android.internal.R.styleable.GradientDrawable_useLevel, true);
    }
    

    In android-21, file GradientDrawable.java, line 1028-1047:

    if (state.mShape == RING) {
        ....
        state.mUseLevelForShape = a.getBoolean(
                        R.styleable.GradientDrawable_useLevel, state.mUseLevelForShape);
    }
    
    0 讨论(0)
提交回复
热议问题