Search code examples
androidandroid-selectorandroid-imagebuttonandroid-shape

Unexpected result on using the different shapes with an ImageButton states


My simple target is to change the background of ImageButton on different button states. So, what I have is

mylayout.xml

<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:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    android:paddingBottom="@dimen/activity_vertical_margin"
    tools:context=".MyActivity"
    android:orientation="vertical"
    android:id="@+id/idBackground">
    ...
    <ImageButton
        android:id="@+id/btnCapture"
        android:layout_height="wrap_content"
        android:layout_width="wrap_content"
        android:background="@drawable/ic_photo_selector"
        android:src="@drawable/ic_photo"
        android:padding="25dp"
        android:layout_alignParentBottom="true"
        android:layout_centerHorizontal="true"/>
    ...
</RelativeLayout>

ic_photo_selector.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="oval" >

            <gradient
                android:centerColor="#3311ffed"
                android:centerX="0.5"
                android:centerY="0.5"
                android:endColor="#8011ffed"
                android:gradientRadius="150"
                android:startColor="#2711ffed"
                android:type="radial" />

            <stroke
                android:width="2dp"
                android:color="#3300DDFF" />

            <padding
                android:bottom="15dp"
                android:left="15dp"
                android:right="15dp"
                android:top="15dp" />

        </shape>
    </item>

    <item android:drawable="@drawable/capture_button_bg"/>

</selector>

capture_button_bg.xml

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

    <gradient
        android:centerColor="#1111ffed"
        android:centerX="0.5"
        android:centerY="0.5"
        android:endColor="#5E11ffed"
        android:gradientRadius="150"
        android:startColor="#0511ffed"
        android:type="radial" />

    <stroke
        android:width="2dp"
        android:color="#1100DDFF" />

    <padding
        android:bottom="15dp"
        android:left="15dp"
        android:right="15dp"
        android:top="15dp" />

</shape>

ic_photo.png(it is transparent image but due to this web site has white background I posted it on black layer)

enter image description here

So, as you can see, the visual difference between both states (pressed and default) should be just in transparence. But the design mode as the real devices are showed another result

                        Default State              Pressed State
enter image description here enter image description here

My mind really is blocked. Why the default button has the such color difference with the pressed button? As I expected, the difference should be just in transparency mode.

Any ideas? Or may be it's something wrong in my code snippets?


Solution

  • I found the solution of my issue, but it is something strange.

    The occasion of the behaviour described above was consisted in using the inline <shape> for pressed state and the reference to the drawable for default state.

    Solutions:

    1) Using the inline <shape> both for pressed state and default state

    <?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="oval" >
    
                <gradient
                    android:centerColor="#3311ffed"
                    android:centerX="0.5"
                    android:centerY="0.5"
                    android:endColor="#8011ffed"
                    android:gradientRadius="150"
                    android:startColor="#2711ffed"
                    android:type="radial" />
    
                <stroke
                    android:width="2dp"
                    android:color="#3300DDFF" />
    
                <padding
                    android:bottom="15dp"
                    android:left="15dp"
                    android:right="15dp"
                    android:top="15dp" />
    
            </shape>
        </item>
    
        <item>
            <shape android:shape="oval" >
    
                <gradient
                    android:centerColor="#1111ffed"
                    android:centerX="0.5"
                    android:centerY="0.5"
                    android:endColor="#5E11ffed"
                    android:gradientRadius="150"
                    android:startColor="#0511ffed"
                    android:type="radial" />
    
                <stroke
                    android:width="2dp"
                    android:color="#1100DDFF" />
    
                <padding
                    android:bottom="15dp"
                    android:left="15dp"
                    android:right="15dp"
                    android:top="15dp" />
    
            </shape>
        </item>
    
    </selector>
    

    2) Using the reference to the drawable for the pressed state and the inline <shape> for default state

    <?xml version="1.0" encoding="utf-8"?>
    <selector xmlns:android="http://schemas.android.com/apk/res/android">
    
        <item android:state_pressed="true" android:drawable="@drawable/capture_button_bg_pressed"/>
    
        <item>
            <shape android:shape="oval" >
    
                <gradient
                    android:centerColor="#1111ffed"
                    android:centerX="0.5"
                    android:centerY="0.5"
                    android:endColor="#5E11ffed"
                    android:gradientRadius="150"
                    android:startColor="#0511ffed"
                    android:type="radial" />
    
                <stroke
                    android:width="2dp"
                    android:color="#1100DDFF" />
    
                <padding
                    android:bottom="15dp"
                    android:left="15dp"
                    android:right="15dp"
                    android:top="15dp" />
    
            </shape>
        </item>
    
    </selector>
    

    capture_button_bg_pressed.xml

    <?xml version="1.0" encoding="utf-8"?>
    
                <shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="oval" >
    
                    <gradient
                        android:centerColor="#3311ffed"
                        android:centerX="0.5"
                        android:centerY="0.5"
                        android:endColor="#8011ffed"
                        android:gradientRadius="150"
                        android:startColor="#2711ffed"
                        android:type="radial" />
    
                    <stroke
                        android:width="2dp"
                        android:color="#3300DDFF" />
    
                    <padding
                        android:bottom="15dp"
                        android:left="15dp"
                        android:right="15dp"
                        android:top="15dp" />
    
                </shape>
    

    Also, main point is that the default state should be followed last (below any other states).

    I can't explain why it is so, but it works for me.