Drawing top border on a shape on Android

2019-02-02 08:55发布

问题:

I'm creating a custom progress bar (positioned under a WebView) and what I would like to draw is a 1dp-wide line between the WebView and the ProgressBar. I'm modifying existing drawable, namely progress_horizontal.xml, and tried something like this:

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

  (...)

  <item>
    <shape android:shape="line">
      <stroke android:width="1dp" android:color="#FF000000" />
    </shape>
  </item>

</layer-list>

This line however is vertically centered but I want it to be drawn on top of the drawable. The only idea I could come up with is to use this "hacky" gradient below:

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

  (...)

  <item>
    <shape>
      <gradient
          android:startColor="#FF000000"
          android:centerColor="#00000000"
          android:centerY="0.01"
          android:endColor="#00000000"
          android:angle="270"
      />
    </shape>
  </item>

</layer-list>

Do you have better ideas how to draw a single line shape aligned to the top of the drawable defined with layer-list?

回答1:

I spent a while trying to figure this out as well. Hopefully there is a better way to do it but here is the method I used, which is also kind of hackish, but in case it helps someone, I thought I would share.

The first item in your layer list should be a solid of whatever color you want to be your border. Following that would be the thing(s) you want to have the border, with padding on whatever side you want the border to be on.

For example:

<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
    <item>
        <shape android:shape="rectangle">
            <solid android:color="YOUR BORDER COLOR" />
        </shape>
    </item>
    <item android:top="YOUR TOP BORDER THICKNESS">
        THE THING YOU WANT A BORDER ON
    </item>
</layer-list>

The idea is that the padding on the item reveals the solid shape behind it, giving the border appearance. You could add padding to any side to add a border. I imagine you could get more complicated and have different colored borders this way as well.

Seems like a hack but it worked for me.

EDIT: I said "padding" but in layer-lists it's more of an offset.



回答2:

i was going through all related topics but no one could solve my problem. But some of them were very useful to understand how the layer-list or shape parameters work.

My problem was to define a button with a linear gradient and draw a top and a bottom line in different colors. After all I hacked this solution. I saved the file unter res/drawable/blue_btn.xml

    <?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android" >
   <item android:state_pressed="true" >        
        <shape android:shape="rectangle">
            <solid android:color="@color/blue_end" />
            <padding 
                   android:left="10dp"
                android:top="10dp"
                android:right="10dp"
                android:bottom="10dp" />
            <stroke   
                android:width="1dp"
                android:color="@color/bottomline_btn" />                        
        </shape>    
    </item>
    <item>
        <layer-list xmlns:android="http://schemas.android.com/apk/res/android" >
           <item>
                <shape android:shape="rectangle">
                    <solid android:color="@color/blue" />
                    <gradient
                        android:startColor="@color/blue"
                        android:endColor="@color/blue_end"
                        android:angle="270" />
                </shape>
            </item>
            <item android:top="0dp" android:bottom="-1dp" android:left="-1dp" android:right="-1dp">
                <shape android:shape="rectangle">
                    <stroke   
                        android:width="1dp"
                        android:color="@color/topline_btn" />                       
                    <solid android:color="#00000000" />
                    <corners android:radius="0dp" />
                </shape>
            </item>
            <item android:top="-1dp" android:bottom="0dp" android:left="-1dp" android:right="-1dp">
                <shape android:shape="rectangle">
                    <stroke   
                        android:width="1dp"
                        android:color="@color/bottomline_btn" />                        
                    <solid android:color="#00000000" />
                    <corners android:radius="0dp" />
                </shape>
            </item>         
        </layer-list>
    </item>  
</selector>


<color name="topline_btn">#31ffffff</color>
<color name="bottomline_btn">#31000000</color>

<color name="blue">#449def</color>
<color name="blue_end">#2f6699</color>


回答3:

Did you try offsetting it by something like this

http://android.amberfog.com/?p=9



回答4:

My solution is to add 9-patch as the last layer item :

<layer-list xmlns:android="http://schemas.android.com/apk/res/android" >
    <item>
        <shape>
            <solid android:color="@color/tab_button_active_layer2" />
        </shape>
    </item>
    <item android:bottom="@dimen/tab_button_active_bottom_bar_width">
        <shape>
            <solid android:color="@color/tab_button_active_layer1" />
        </shape>
    </item>
    <!-- 9-patch drawable -->
    <item android:drawable="@drawable/tab_button_border_top"/>
</layer-list>