首页 > 代码库 > 自定义漂亮的RadioButon(使用shape)

自定义漂亮的RadioButon(使用shape)

效果图:                                 技术分享




一、首先介绍下selecter状态下各个状态

我们在定义一个drawable的时候可以通过xml定义的drawable对象。它使得一个图片能在不同的状态下显示不同的图案,比如一个Button,它有pressed,focused,或者其它状态,通过使用state list drawable,你就可以为每种状态提供不同的图片。

先看一个范例:

XML file saved at res/drawable/button.xml:

[java] view plaincopy
  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <selector xmlns:android="http://schemas.android.com/apk/res/android">  
  3.     <item android:state_pressed="true" android:state_enabled="true" android:state_window_focused="false"  
  4.           android:drawable="@drawable/button_pressed" /> <!-- pressed,enable等多个属性 -->  
  5.     <item android:state_focused="true"  
  6.           android:drawable="@drawable/button_focused" /> <!-- focused -->  
  7.     <item android:state_hovered="true"  
  8.           android:drawable="@drawable/button_focused" /> <!-- hovered -->  
  9.     <item android:drawable="@drawable/button_normal" /> <!-- default -->  
  10. </selector>  


 

This layout XML applies the state list drawable to a Button:

[java] view plaincopy
  1. <Button  
  2.     android:layout_height="wrap_content"  
  3.     android:layout_width="wrap_content"  
  4.     android:background="@drawable/button" />  



android:drawable 放一个drawable资源
android:state_pressed 是否按下,如一个按钮触摸或者点击。
android:state_focused 是否取得焦点,比如用户选择了一个文本框。
android:state_hovered 光标是否悬停,通常与focused state相同,它是4.0的新特性
android:state_selected 被选中,它与focus state并不完全一样,如一个list view 被选中的时候,它里面的各个子组件可能通过方向键,被选中了。
android:state_checkable 组件是否能被check。如:RadioButton是可以被check的。
android:state_checked 被checked了,如:一个RadioButton可以被check了。
android:state_enabled 能够接受触摸或者点击事件
android:state_activated 被激活(这个麻烦举个例子,不是特明白)
android:state_window_focused 应用程序是否在前台,当有通知栏被拉下来或者一个对话框弹出的时候应用程序就不在前台了

 

注意:如果有多个item,那么程序将自动从上到下进行匹配,最先匹配的将得到应用。(不是通过最佳匹配)
如果一个item没有任何的状态说明,那么它将可以被任何一个状态匹配。


二、 drawable下各个selecter.xml文件(左、中、右、单个RadioButton的状态定义)

1. radiobutton_left.xml

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

    <item android:state_checked="true" android:state_focused="true" android:state_pressed="false"><shape>

            <!-- 开始颜色="" 结束颜色="" 颜色渐变="" -->
            <gradient android:angle="270" android:endColor="@color/radiobutton_pressed" android:startColor="@color/radiobutton_pressed" />
            <!-- //渐变方向     按钮边缘="" 边缘宽="" -->
            <stroke android:width="1sp" android:color="@color/radiobutton_pressed" />
            <!-- //边缘颜色   按钮四个圆角="" -->
            <corners android:bottomLeftRadius="5dip" android:bottomRightRadius="0dip" android:topLeftRadius="5dip" android:topRightRadius="0dip" />
            <!-- //半径    内边距="" 按钮文字和边缘距离="" -->
            <padding android:bottom="10dp" android:left="10dp" android:right="10dp" android:top="10dp" />
        </shape></item>
    <item android:state_checked="true" android:state_focused="false" android:state_pressed="false"><shape>
            <gradient android:angle="270" android:endColor="@color/radiobutton_pressed" android:startColor="@color/radiobutton_pressed" />

            <stroke android:width="1sp" android:color="@color/radiobutton_pressed" />

            <corners android:bottomLeftRadius="5dip" android:bottomRightRadius="0dip" android:topLeftRadius="5dip" android:topRightRadius="0dip" />

            <padding android:bottom="10dp" android:left="10dp" android:right="10dp" android:top="10dp" />
        </shape></item>
    <item android:state_pressed="true"><shape>
            <gradient android:angle="270" android:endColor="@color/radiobutton_pressed" android:startColor="@color/radiobutton_pressed" />

            <stroke android:width="1sp" android:color="@color/radiobutton_pressed" />

            <corners android:bottomLeftRadius="5dip" android:bottomRightRadius="0dip" android:topLeftRadius="5dip" android:topRightRadius="0dip" />

            <padding android:bottom="10dp" android:left="10dp" android:right="10dp" android:top="10dp" />
        </shape></item>
    <item android:state_checked="false"><shape>
            <gradient android:angle="270" android:endColor="@color/radiobutton_normal" android:startColor="@color/radiobutton_normal" />

            <stroke android:width="1sp" android:color="@color/radiobutton_normal" />

            <corners android:bottomLeftRadius="5dip" android:bottomRightRadius="0dip" android:topLeftRadius="5dip" android:topRightRadius="0dip" />

            <padding android:bottom="10dp" android:left="10dp" android:right="10dp" android:top="10dp" />
        </shape></item>
    <item><shape>
            <gradient android:angle="270" android:endColor="@color/radiobutton_normal" android:startColor="@color/radiobutton_normal" />

            <stroke android:width="1sp" android:color="@color/radiobutton_normal" />

            <corners android:bottomLeftRadius="5dip" android:bottomRightRadius="0dip" android:topLeftRadius="5dip" android:topRightRadius="0dip" />

            <padding android:bottom="10dp" android:left="10dp" android:right="10dp" android:top="10dp" />
        </shape></item>
    <!-- default -->

</selector>

2. radiobutton_middle.xml

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

    <item  android:state_checked="true" android:state_focused="true" android:state_pressed="false">
        <shape>

            <!-- 开始颜色="" 结束颜色="" 颜色渐变="" -->
            <gradient android:angle="270" android:endColor="@color/radiobutton_pressed" android:startColor="@color/radiobutton_pressed" />
            <!-- //渐变方向     按钮边缘="" 边缘宽="" -->
            <stroke android:width="1sp" android:color="@color/radiobutton_pressed" />
            <!-- //边缘颜色   按钮四个圆角="" -->
            <corners android:bottomLeftRadius="0dip" android:bottomRightRadius="0dip" android:topLeftRadius="0dip" android:topRightRadius="0dip" />
            <!-- //半径    内边距="" 按钮文字和边缘距离="" -->
            <padding android:bottom="10dp" android:left="10dp" android:right="10dp" android:top="10dp" />
        </shape>
        
    </item>
    
    
<item android:state_checked="true"  android:state_pressed="false" >
    
          <shape>

            <gradient android:angle="270" android:endColor="@color/radiobutton_pressed" android:startColor="@color/radiobutton_pressed" />
            <stroke android:width="1sp" android:color="@color/radiobutton_pressed" />
            <corners android:bottomLeftRadius="0dip" android:bottomRightRadius="0dip" android:topLeftRadius="0dip" android:topRightRadius="0dip" />
            <padding android:bottom="10dp" android:left="10dp" android:right="10dp" android:top="10dp" />
        </shape>
    
</item>
    <item  android:state_pressed="true">
        <shape>

            <gradient android:angle="270" android:endColor="@color/radiobutton_pressed" android:startColor="@color/radiobutton_pressed" />
            <stroke android:width="1sp" android:color="@color/radiobutton_pressed" />
            <corners android:bottomLeftRadius="0dip" android:bottomRightRadius="0dip" android:topLeftRadius="0dip" android:topRightRadius="0dip" />
            <padding android:bottom="10dp" android:left="10dp" android:right="10dp" android:top="10dp" />
        </shape>
    </item>
    <item  android:state_checked="false">
        <shape>
            <gradient android:angle="270" android:endColor="@color/radiobutton_normal" android:startColor="@color/radiobutton_normal" />

            <stroke android:width="1sp" android:color="@color/radiobutton_normal" />

            <corners android:bottomLeftRadius="0dip" android:bottomRightRadius="0dip" android:topLeftRadius="0dip" android:topRightRadius="0dip" />

            <padding android:bottom="10dp" android:left="10dp" android:right="10dp" android:top="10dp" />
        </shape>
    </item>
    <item android:state_checked="false" android:state_focused="false">
        <shape>
            <gradient android:angle="270" android:endColor="@color/radiobutton_normal" android:startColor="@color/radiobutton_normal" />

            <stroke android:width="1sp" android:color="@color/radiobutton_normal" />

            <corners android:bottomLeftRadius="0dip" android:bottomRightRadius="0dip" android:topLeftRadius="0dip" android:topRightRadius="0dip" />

            <padding android:bottom="10dp" android:left="10dp" android:right="10dp" android:top="10dp" />
        </shape>
        
    </item>
 <!-- default -->

</selector>

3. radiobutton_right.xml

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

    <item  android:state_checked="true" android:state_focused="true" android:state_pressed="false">
        <shape>

            <!-- 开始颜色="" 结束颜色="" 颜色渐变="" -->
            <gradient android:angle="270" android:endColor="@color/radiobutton_pressed" android:startColor="@color/radiobutton_pressed" />
            <!-- //渐变方向     按钮边缘="" 边缘宽="" -->
            <stroke android:width="1sp" android:color="@color/radiobutton_pressed" />
            <!-- //边缘颜色   按钮四个圆角="" -->
            <corners android:bottomLeftRadius="5dip" android:bottomRightRadius="0dip" android:topLeftRadius="5dip" android:topRightRadius="0dip" />
            <!-- //半径    内边距="" 按钮文字和边缘距离="" -->
            <padding android:bottom="10dp" android:left="10dp" android:right="10dp" android:top="10dp" />
        </shape>
        
    </item>

    <item android:state_checked="true"  android:state_pressed="false" >
    
          <shape>

            <gradient android:angle="270" android:endColor="@color/radiobutton_pressed" android:startColor="@color/radiobutton_pressed" />
            <stroke android:width="1sp" android:color="@color/radiobutton_pressed" />
            <corners android:bottomLeftRadius="0dip" android:bottomRightRadius="5dip" android:topLeftRadius="0dip" android:topRightRadius="5dip" />
            <padding android:bottom="10dp" android:left="10dp" android:right="10dp" android:top="10dp" />
        </shape>
    
</item>
    
    <item  android:state_pressed="true">
        <shape>

            <gradient android:angle="270" android:endColor="@color/radiobutton_pressed" android:startColor="@color/radiobutton_pressed" />
            <stroke android:width="1sp" android:color="@color/radiobutton_pressed" />
            <corners android:bottomLeftRadius="0dip" android:bottomRightRadius="5dip" android:topLeftRadius="0dip" android:topRightRadius="5dip" />
            <padding android:bottom="10dp" android:left="10dp" android:right="10dp" android:top="10dp" />
        </shape>
    </item>
    <item  android:state_checked="false">
        <shape>
            <gradient android:angle="270" android:endColor="@color/radiobutton_normal" android:startColor="@color/radiobutton_normal" />

            <stroke android:width="1sp" android:color="@color/radiobutton_normal" />

            <corners android:bottomLeftRadius="0dip" android:bottomRightRadius="5dip" android:topLeftRadius="0dip" android:topRightRadius="5dip" />

            <padding android:bottom="10dp" android:left="10dp" android:right="10dp" android:top="10dp" />
        </shape>
    </item>
    <item >
        <shape>
            <gradient android:angle="270" android:endColor="@color/radiobutton_normal" android:startColor="@color/radiobutton_normal" />

            <stroke android:width="1sp" android:color="@color/radiobutton_normal" />

            <corners android:bottomLeftRadius="0dip" android:bottomRightRadius="5dip" android:topLeftRadius="0dip" android:topRightRadius="5dip" />

            <padding android:bottom="10dp" android:left="10dp" android:right="10dp" android:top="10dp" />
        </shape>
        
    </item>
 <!-- default -->

</selector>

4. radiobutton_single.xml

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

    <item  android:state_checked="true" android:state_focused="true" android:state_pressed="false">
        <shape>

            <!-- 开始颜色="" 结束颜色="" 颜色渐变="" -->
            <gradient android:angle="270" android:endColor="@color/radiobutton_pressed" android:startColor="@color/radiobutton_pressed" />
            <!-- //渐变方向     按钮边缘="" 边缘宽="" -->
            <stroke android:width="1sp" android:color="@color/radiobutton_pressed" />
            <!-- //边缘颜色   按钮四个圆角="" -->
            <corners android:bottomLeftRadius="5dip" android:bottomRightRadius="0dip" android:topLeftRadius="5dip" android:topRightRadius="0dip" />
            <!-- //半径    内边距="" 按钮文字和边缘距离="" -->
            <padding android:bottom="10dp" android:left="10dp" android:right="10dp" android:top="10dp" />
        </shape>
        
    </item>
    
    <item android:state_checked="true"  android:state_pressed="false" >
    
          <shape>

            <gradient android:angle="270" android:endColor="@color/radiobutton_pressed" android:startColor="@color/radiobutton_pressed" />
            <stroke android:width="1sp" android:color="@color/radiobutton_pressed" />
            <corners android:bottomLeftRadius="5dip" android:bottomRightRadius="5dip" android:topLeftRadius="5dip" android:topRightRadius="5dip" />
            <padding android:bottom="10dp" android:left="10dp" android:right="10dp" android:top="10dp" />
        </shape>
    
</item>

    <item  android:state_pressed="true">
        <shape>

            <gradient android:angle="270" android:endColor="@color/radiobutton_pressed" android:startColor="@color/radiobutton_pressed" />
            <stroke android:width="1sp" android:color="@color/radiobutton_pressed" />
            <corners android:bottomLeftRadius="5dip" android:bottomRightRadius="5dip" android:topLeftRadius="5dip" android:topRightRadius="5dip" />
            <padding android:bottom="10dp" android:left="10dp" android:right="10dp" android:top="10dp" />
        </shape>
    </item>
    <item  android:state_checked="false">
        <shape>
            <gradient android:angle="270" android:endColor="@color/radiobutton_normal" android:startColor="@color/radiobutton_normal" />

            <stroke android:width="1sp" android:color="@color/radiobutton_normal" />

            <corners android:bottomLeftRadius="5dip" android:bottomRightRadius="5dip" android:topLeftRadius="5dip" android:topRightRadius="5dip" />

            <padding android:bottom="10dp" android:left="10dp" android:right="10dp" android:top="10dp" />
        </shape>
    </item>
    <item >
        <shape>
            <gradient android:angle="270" android:endColor="@color/radiobutton_normal" android:startColor="@color/radiobutton_normal" />

            <stroke android:width="1sp" android:color="@color/radiobutton_normal" />

            <corners android:bottomLeftRadius="5dip" android:bottomRightRadius="5dip" android:topLeftRadius="5dip" android:topRightRadius="5dip" />

            <padding android:bottom="10dp" android:left="10dp" android:right="10dp" android:top="10dp" />
        </shape>
        
    </item>
 <!-- default -->

</selector>

三、Java代码


1.com.jun.widget包下 CommonRadioGroup.java文件内容

/*
 * Copyright (C) 2011 Make Ramen, LLC
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.jun.widget;

import com.jun.radiobutton.R;

import android.content.Context;
import android.util.AttributeSet;
import android.widget.RadioGroup;

public class CommonRadioGroup extends RadioGroup {

	public CommonRadioGroup(Context context) {
		super(context);
	}

	public CommonRadioGroup(Context context, AttributeSet attrs) {
		super(context, attrs);
	}

	@Override
	protected void onFinishInflate() {
		super.onFinishInflate();
		changeButtonsImages();
	}

	private void changeButtonsImages(){
		int count = super.getChildCount();

		if(count > 1){
			super.getChildAt(0).setBackgroundResource(R.drawable.radiobutton_left);
			for(int i=1; i < count-1; i++){
				super.getChildAt(i).setBackgroundResource(R.drawable.radiobutton_middle);
			}
			super.getChildAt(count-1).setBackgroundResource(R.drawable.radiobutton_right);
		}else if (count == 1){
			super.getChildAt(0).setBackgroundResource(R.drawable.radiobutton_single);
		}
	}
}

2. com.jun.radiobutton 包下MainActivity.java文件内容:

package com.jun.radiobutton;

import com.jun.widget.CommonRadioGroup;

import android.support.v7.app.ActionBarActivity;
import android.text.InputFilter.LengthFilter;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.RadioButton;
import android.widget.RadioGroup;
import android.widget.Toast;
import android.widget.RadioGroup.OnCheckedChangeListener;

public class MainActivity extends ActionBarActivity implements OnCheckedChangeListener {
	
	private CommonRadioGroup segmentText;
	private RadioButton buttonAll;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		
		init();
	}

	private final void init() {
		// TODO Auto-generated method stub
        segmentText = (CommonRadioGroup) findViewById(R.id.segment_text);
        segmentText.setOnCheckedChangeListener(this);
        buttonAll = (RadioButton) findViewById(R.id.button_all);
        buttonAll.setChecked(true);
	}

	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		// Inflate the menu; this adds items to the action bar if it is present.
		getMenuInflater().inflate(R.menu.main, menu);
		return true;
	}

	@Override
	public boolean onOptionsItemSelected(MenuItem item) {
		// Handle action bar item clicks here. The action bar will
		// automatically handle clicks on the Home/Up button, so long
		// as you specify a parent activity in AndroidManifest.xml.
		int id = item.getItemId();
		if (id == R.id.action_settings) {
			return true;
		}
		return super.onOptionsItemSelected(item);
	}

	@Override
	public void onCheckedChanged(RadioGroup group, int checkedId) {
		// TODO Auto-generated method stub
		if (group == segmentText) {
			if (checkedId == R.id.button_all) {
				Toast.makeText(getApplicationContext(), "全部", Toast.LENGTH_SHORT).show();
			} else if (checkedId == R.id.button_one) {
				Toast.makeText(getApplicationContext(), "选项一", Toast.LENGTH_SHORT).show();
			} else if (checkedId == R.id.button_two) {
				Toast.makeText(getApplicationContext(), "选项二", Toast.LENGTH_SHORT).show();
			} else if (checkedId == R.id.button_three) {
				Toast.makeText(getApplicationContext(), "选项三", Toast.LENGTH_SHORT).show();
			}
		}
		
		
	}
}

四、layout下MainActivity的布局文件activity_main.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:background="#FFFFFFFF" >

    <com.jun.widget.CommonRadioGroup
        android:id="@+id/segment_text"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true"
        android:layout_margin="5dip"
        android:checkedButton="@+id/button_one"
        android:orientation="horizontal" >

        <RadioButton
            android:id="@+id/button_all"
            android:button="@null"
            android:gravity="center"
            android:minHeight="33dip"
            android:minWidth="70dip"
            android:text="全部 "
            android:textAppearance="?android:attr/textAppearanceSmall"
            android:textColor="@color/radio_colors" />

        <RadioButton
            android:id="@+id/button_one"
            android:button="@null"
            android:gravity="center"
            android:minHeight="33dip"
            android:minWidth="70dip"
            android:text="选项一"
            android:textAppearance="?android:attr/textAppearanceSmall"
            android:textColor="@color/radio_colors" />

        <RadioButton
            android:id="@+id/button_two"
            android:button="@null"
            android:gravity="center"
            android:minHeight="33dip"
            android:minWidth="70dip"
            android:text="选项二"
            android:textAppearance="?android:attr/textAppearanceSmall"
            android:textColor="@color/radio_colors" />

        <RadioButton
            android:id="@+id/button_three"
            android:button="@null"
            android:gravity="center"
            android:minHeight="33dip"
            android:minWidth="70dip"
            android:text="选项三"
            android:textAppearance="?android:attr/textAppearanceSmall"
            android:textColor="@color/radio_colors" />
    </com.jun.widget.CommonRadioGroup>

</RelativeLayout>


五、颜色配置文件color.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>

    <color name="radiobutton_normal">#85000000</color>
    <color name="radiobutton_pressed">#FFFE007F</color>
    <color name="radio_colors">#FFFFFFFF</color>
    
 
</resources>


github代码托管地址:https://github.com/Juneor/custom-radiobutton



自定义漂亮的RadioButon(使用shape)