<turn>Android development: use Drawable XML to draw a round button with shadow effect

It's quite complicated to draw, and I just used the shape aspect, so I checked some information. Reprinted, this master's article, make it a collection, if there is any infringement, please inform, and it will be deleted.

As we all know, in Android development, in order to optimize the display effect on devices with various resolutions, the same picture material often needs to provide three types of mdpi, hdpi, xhdpi (there was also ldpi in the past), especially button materials. Considering Normal, pressed, and focused require at least 3×3=9 pictures. Although the NinePatch technology can solve some of the size flexibility problems, most of the modifications and adaptations still need to make a batch of pictures again.

According to the needs of interaction design, you can consider using Drawable XML to draw buttons. The benefits are:
* Vector drawing, easy to scale;
* Less bytes (generally speaking);
* Based on XML text, attribute values ​​​​are easy to adjust;
* Drawable components It can be nested and reused;
* XML is together with other source codes of the project, which is convenient for version control.

Of course, there are also disadvantages:
* There is no visual editor, and editing is not intuitive enough;
* Limited by basic graphics and filling methods;
* It is difficult for artists to get started.

Take the exercise "Instant Noodle Butler" ( see here ) developed by this site as an example.
The picture below is the timer of the Instant Noodle Butler. The circle in the middle (including the hollow shadow effect) is the icon indicating the state of the timer by default, and it will be transformed into a button to stop timing during the running of the timer:

Here the background of the icon is drawn with Drawable XML. In Android, Drawable XML does not support shadows. Referring to many examples on the Internet, shadows are generally implemented with additional gradients or borders. Here it is drawn by superimposing shapes.

The color block marked in the green box in the above picture can be divided into several parts from outside to inside:
* Outer circle
* Inner shadow of outer circle
* Gap
* Outer shadow of center circle
* Center circle

Use <layer-list/>, start from the bottom layer, draw the largest circle corresponding to the outermost part, and then layer by layer, expand the padding while superimposing the circle, the fill color of the circle should correspond to the corresponding color block . The res/drawable/timer_center_bg.xml code is as follows:

<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android" >
    <!-- outer circle -->
    <item>
        <shape android:shape="oval" >
            <solid android:color="#FFACB8C3" />
        </shape>
    </item>
 
    <!-- inner shadow of outer circle -->
    <item
        android:bottom="2dp"
        android:left="2dp"
        android:right="2dp"
        android:top="2dp">
        <shape android:shape="oval">
            <solid android:color="#FFbdcad6" />
        </shape>
    </item>
    <item
        android:bottom="3dp"
        android:left="3dp"
        android:right="3dp"
        android:top="3dp">
        <shape android:shape="oval">
            <solid android:color="#FFc3cfd9" />
        </shape>
    </item>
    <item
        android:bottom="4dp"
        android:left="4dp"
        android:right="4dp"
        android:top="4dp">
        <shape android:shape="oval">
            <solid android:color="#FFcbd6df" />
        </shape>
    </item>
    <item
        android:bottom="5dp"
        android:left="5dp"
        android:right="5dp"
        android:top="5dp">
        <shape android:shape="oval">
            <solid android:color="#FFd4dee5" />
        </shape>
    </item>
 
    <!-- gap -->
    <item
        android:bottom="6dp"
        android:left="6dp"
        android:right="6dp"
        android:top="6dp">
        <shape android:shape="oval" >
            <solid android:color="#FFdae2e8" />
        </shape>
    </item>
 
    <!-- outer shadow of center circle -->
    <item
        android:bottom="10dp"
        android:left="10dp"
        android:right="10dp"
        android:top="10dp">
        <shape android:shape="oval">
            <solid android:color="#FFced5dc" />
        </shape>
    </item>
    <item
        android:bottom="12dp"
        android:left="12dp"
        android:right="12dp"
        android:top="12dp">
        <shape android:shape="oval">
            <solid android:color="#FFbcc4c9" />
        </shape>
    </item>
    <item
        android:bottom="13dp"
        android:left="13dp"
        android:right="13dp"
        android:top="13dp">
        <shape android:shape="oval">
            <solid android:color="#FFb4bbc0" />
        </shape>
    </item>
    <item
        android:bottom="14dp"
        android:left="14dp"
        android:right="14dp"
        android:top="14dp">
        <shape android:shape="oval">
            <solid android:color="#FFacb3b8" />
        </shape>
    </item>
 
    <!-- center circle -->
    <item
        android:bottom="15dp"
        android:left="15dp"
        android:right="15dp"
        android:top="15dp">
        <shape android:shape="oval">
            <stroke android:width="1dp" android:color="#FFFCFCFC"/>
            <gradient
                android:angle="270"
                android:endColor="#FFCFD7DD"
                android:startColor="#FFF0F5F9" />
        </shape>
    </item>
 
</layer-list>




Note that the top is just the background of the button. As mentioned at the beginning of the article, one of the characteristics of Drawable XML is reusability. Continue to look at the code of res/drawable/stop_timer_btn.xml:


<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
 
    <!-- normal -->
    <item android:state_enabled="true" android:state_focused="false" android:state_pressed="false">
        <layer-list>
            <item android:drawable="@drawable/timer_center_bg" />
            <item android:bottom="15dp" android:left="15dp" android:right="15dp" android:top="15dp">
                <shape android:shape="oval">
                    <stroke android:width="1dp" android:color="#FFFCFCFC" />
                    <gradient android:angle="270" android:endColor="#FF91c0e8" android:startColor="#FFa7d3fa" />
                </shape>
            </item>
        </layer-list>
    </item>
 
    <!-- pressed -->
    <item android:state_enabled="true" android:state_pressed="true">
        <layer-list>
            <item android:drawable="@drawable/timer_center_bg" />
            <item android:bottom="15dp" android:left="15dp" android:right="15dp" android:top="15dp">
                <shape android:shape="oval">
                    <stroke android:width="2dp" android:color="#FFf8f640" />
                    <gradient android:angle="270" android:endColor="#FF91c0e8" android:startColor="#FFa7d3fa" />
                </shape>
            </item>
        </layer-list>
    </item>
 
    <!-- selected -->
    <item android:state_enabled="true" android:state_focused="true" android:state_pressed="false">
        <layer-list>
            <item android:drawable="@drawable/timer_center_bg" />
            <item android:bottom="15dp" android:left="15dp" android:right="15dp" android:top="15dp">
                <shape android:shape="oval">
                    <stroke android:width="2dp" android:color="#FFf8f640" />
                    <gradient android:angle="270" android:endColor="#FF91c0e8" android:startColor="#FFa7d3fa" />
                </shape>
            </item>
        </layer-list>
    </item>
 
    <!-- ...... -->
</selector>




From the above code, it can be seen that each <item/> in <selector/> is a <layer-list/>, and @drawable/timer_center_bg is used as the background to superimpose a circle on the foreground to distinguish different states.

The last thing to note is that when deciding whether a button should be rendered with Drawable XML, the following factors should be considered:
* Whether the App supports multiple resolutions;
* Whether the App needs to be slimmed down;
* Whether the pattern is simple enough;
* The pattern needs to be free Scaling;
* Whether the design and development workflow allows developers to cross boundaries;
* Development manpower is more sufficient than design manpower.

Otherwise, image rendering should be considered.


原文发表于http://evis.me/2013/05/android-dev-render-button-with-shadow-using-drawable-xml/

Guess you like

Origin blog.csdn.net/chungehenyy/article/details/44810395