同步發表於http://avenwu.net/2015/02/05/styled_radiogroup_segmented_controljava
Fork on github https://github.com/avenwu/supportandroid
iOS中有一個Segmented Control組件,android中的RadioGroup與之相似,可是RadioGroup的默認樣式不是很美觀,可是隻須要稍微調一下就能夠長得和Segmented Control控件同樣簡潔優雅。ios
直接寫style文件固然是最快的,只需設置每一個RadioButton的對其爲居中,修改默認的android:button資源,而後加上背景、文字的selector。git
<RadioGroup android:layout_width="match_parent" android:layout_height="48dp" android:orientation="horizontal" android:gravity="center_vertical"> <RadioButton android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="A" android:id="@+id/radioButton" style="@style/FlatRadioButtonStyle" android:background="@drawable/flat_round_shape_left" /> <RadioButton android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="B" android:id="@+id/radioButton2" android:checked="true" style="@style/FlatRadioButtonStyle" android:background="@drawable/flat_round_shape_middle" /> <RadioButton android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="C" android:id="@+id/radioButton3" style="@style/FlatRadioButtonStyle" android:background="@drawable/flat_round_shape_right" /> </RadioGroup>
style樣式github
<style name="FlatRadioButtonStyle"> <item name="android:layout_weight">1</item> <item name="android:button">@null</item> <item name="android:gravity">center</item> <item name="android:textAppearance">?android:textAppearanceMedium</item> <item name="android:textColor">@color/radio_button_color</item> <item name="android:padding">5dp</item> </style>
背景selector數組
<?xml version="1.0" encoding="utf-8"?> <selector xmlns:android="http://schemas.android.com/apk/res/android"> <item android:state_checked="true"> <shape android:shape="rectangle"> <corners android:topLeftRadius="5dp" android:bottomLeftRadius="5dp" /> <solid android:color="@android:color/white" /> <stroke android:color="@android:color/white" android:width="1dp" /> </shape> </item> <item> <shape android:shape="rectangle"> <corners android:topLeftRadius="5dp" android:bottomLeftRadius="5dp" /> <solid android:color="@android:color/transparent" /> <stroke android:color="@android:color/white" android:width="1dp" /> </shape> </item> </selector>
這些都沒什麼問題,可是比較零散,每次都須要寫不少的xml及其樣式,selector等,因此能夠作一些簡單的封裝,暴露一些必要的屬性用於自定義,好比邊框線的寬度,背景色等。app
自定義RadioGroup,將必要的初始化配置在內部完成。ide
package net.avenwu.support.widget; import android.content.Context; import android.content.res.ColorStateList; import android.content.res.TypedArray; import android.graphics.Color; import android.graphics.drawable.Drawable; import android.graphics.drawable.GradientDrawable; import android.graphics.drawable.StateListDrawable; import android.util.AttributeSet; import android.util.TypedValue; import android.view.Gravity; import android.view.View; import android.view.ViewGroup; import android.widget.RadioButton; import android.widget.RadioGroup; import net.avenwu.support.R; /** * Created by chaobin on 2/4/15. */ public class FlatTabGroup extends RadioGroup { public FlatTabGroup(Context context) { this(context, null); } private int mRadius; private int mStroke; private int mHighlightColor; private String[] mItemString; private float mTextSize; private ColorStateList mTextColor; public FlatTabGroup(Context context, AttributeSet attrs) { super(context, attrs); setOrientation(HORIZONTAL); setGravity(Gravity.CENTER_VERTICAL); TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.FlatTabGroup); mHighlightColor = array.getColor(R.styleable.FlatTabGroup_tab_border_color, Color.WHITE); mStroke = array.getDimensionPixelSize(R.styleable.FlatTabGroup_tab_border_width, 2); mRadius = array.getDimensionPixelOffset(R.styleable.FlatTabGroup_tab_radius, 5); mTextColor = array.getColorStateList(R.styleable.FlatTabGroup_tab_textColor); mTextSize = array.getDimensionPixelSize(R.styleable.FlatTabGroup_tab_textSize, 14); array.recycle(); int id = array.getResourceId(R.styleable.FlatTabGroup_tab_items, 0); mItemString = isInEditMode() ? new String[]{"TAB A", "TAB B", "TAB C"} : context.getResources().getStringArray(id); generateTabView(context, attrs); updateChildBackground(); } private void generateTabView(Context context, AttributeSet attrs) { if (mItemString == null) { return; } for (String text : mItemString) { RadioButton button = new RadioButton(context, attrs); button.setGravity(Gravity.CENTER); button.setButtonDrawable(android.R.color.transparent); button.setText(text); button.setTextColor(mTextColor); button.setTextSize(TypedValue.COMPLEX_UNIT_PX, mTextSize); addView(button, new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT, 1)); } } @Override protected void onFinishInflate() { super.onFinishInflate(); updateChildBackground(); } private void updateChildBackground() { for (int i = 0; i < getChildCount(); i++) { View child = getChildAt(i); if (child instanceof RadioButton) { child.setBackgroundDrawable(generateTabBackground(i, mHighlightColor)); } } } private Drawable generateTabBackground(int position, int color) { StateListDrawable stateListDrawable = new StateListDrawable(); stateListDrawable.addState(new int[]{android.R.attr.state_checked}, generateDrawable(position, color)); stateListDrawable.addState(new int[]{}, generateDrawable(position, Color.TRANSPARENT)); return stateListDrawable; } private Drawable generateDrawable(int position, int color) { float[] radius; if (position == 0) { radius = new float[]{ mRadius, mRadius, 0, 0, 0, 0, mRadius, mRadius }; } else if (position == getChildCount() - 1) { radius = new float[]{ 0, 0, mRadius, mRadius, mRadius, mRadius, 0, 0 }; } else { radius = new float[]{ 0, 0, 0, 0, 0, 0, 0, 0 }; } GradientDrawable shape = new GradientDrawable(); shape.setCornerRadii(radius); shape.setColor(color); shape.setStroke(mStroke, mHighlightColor); return shape; } }
屬性this
定義須要暴露給外面的屬性spa
<?xml version="1.0" encoding="utf-8"?> <resources> <declare-styleable name="FlatTabGroup"> <attr name="tab_items" format="reference" /> <attr name="tab_border_width" format="dimension|reference" /> <attr name="tab_border_color" format="color|reference" /> <attr name="tab_radius" format="dimension|reference" /> <attr name="tab_textColor" format="dimension|reference" /> <attr name="tab_textSize" format="dimension|reference" /> </declare-styleable> </resources>
如今須要寫一個RadioGroup時只須要少許的的配置:
示例:
<net.avenwu.support.widget.FlatTabGroup android:layout_width="match_parent" android:layout_height="40dp" app:tab_border_width="1dp" app:tab_border_color="@android:color/white" app:tab_items="@array/demo_array" app:tab_radius="5dp" app:tab_textSize="16sp" app:tab_textColor="@color/radio_button_color_light_blue" android:paddingTop="5dp" android:paddingBottom="5dp" />
因此如今寫RadioGroup就很是方便,只須要根據需求配置相應屬性便可。好比實現文章開頭的效果,能夠這樣:
<?xml version="1.0" encoding="utf-8"?> <ScrollView xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="match_parent"> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="wrap_content" android:id="@+id/ll_container"> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:padding="20dp" android:orientation="vertical" android:background="@android:color/holo_red_dark"> <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:text="RadioGroup with custom style" android:textColor="@android:color/white" android:layout_marginTop="10dp" android:layout_marginBottom="10dp" /> <RadioGroup android:layout_width="match_parent" android:layout_height="48dp" android:orientation="horizontal" android:gravity="center_vertical"> <RadioButton android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="A" android:id="@+id/radioButton" style="@style/FlatRadioButtonStyle" android:background="@drawable/flat_round_shape_left" /> <RadioButton android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="B" android:id="@+id/radioButton2" android:checked="true" style="@style/FlatRadioButtonStyle" android:background="@drawable/flat_round_shape_middle" /> <RadioButton android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="C" android:id="@+id/radioButton3" style="@style/FlatRadioButtonStyle" android:background="@drawable/flat_round_shape_right" /> </RadioGroup> <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:text="Custom FlatTabGroup extend RadioGroup" android:textColor="@android:color/white" android:layout_marginTop="10dp" /> </LinearLayout> <FrameLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:padding="20dp" android:background="@android:color/holo_red_dark"> <net.avenwu.support.widget.FlatTabGroup android:layout_width="match_parent" android:layout_height="40dp" app:tab_border_width="1dp" app:tab_border_color="@android:color/white" app:tab_items="@array/demo_array" app:tab_radius="5dp" app:tab_textSize="16sp" app:tab_textColor="@color/radio_button_color" android:paddingTop="5dp" android:paddingBottom="5dp" /> </FrameLayout> <FrameLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:padding="20dp" android:background="@color/tab_orange"> <net.avenwu.support.widget.FlatTabGroup android:layout_width="match_parent" android:layout_height="40dp" app:tab_border_width="1dp" app:tab_border_color="@android:color/white" app:tab_items="@array/demo_array" app:tab_radius="5dp" app:tab_textSize="16sp" app:tab_textColor="@color/radio_button_color_orange" android:paddingTop="5dp" android:paddingBottom="5dp" /> </FrameLayout> <FrameLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:padding="20dp" android:background="@color/tab_purple"> <net.avenwu.support.widget.FlatTabGroup android:layout_width="match_parent" android:layout_height="40dp" app:tab_border_width="1dp" app:tab_border_color="@android:color/white" app:tab_items="@array/demo_array" app:tab_radius="5dp" app:tab_textSize="16sp" app:tab_textColor="@color/radio_button_color_purple" android:paddingTop="5dp" android:paddingBottom="5dp" /> </FrameLayout> <FrameLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:padding="20dp" android:background="@color/tab_blue"> <net.avenwu.support.widget.FlatTabGroup android:layout_width="match_parent" android:layout_height="40dp" app:tab_border_width="1dp" app:tab_border_color="@android:color/white" app:tab_items="@array/demo_array" app:tab_radius="5dp" app:tab_textSize="16sp" app:tab_textColor="@color/radio_button_color_blue" android:paddingTop="5dp" android:paddingBottom="5dp" /> </FrameLayout> <FrameLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:padding="20dp" android:background="@color/tab_light_blue"> <net.avenwu.support.widget.FlatTabGroup android:layout_width="match_parent" android:layout_height="40dp" app:tab_border_width="1dp" app:tab_border_color="@android:color/white" app:tab_items="@array/demo_array" app:tab_radius="5dp" app:tab_textSize="16sp" app:tab_textColor="@color/radio_button_color_light_blue" android:paddingTop="5dp" android:paddingBottom="5dp" /> </FrameLayout> <FrameLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:padding="20dp" android:background="@color/tab_green"> <net.avenwu.support.widget.FlatTabGroup android:layout_width="match_parent" android:layout_height="40dp" app:tab_border_width="1dp" app:tab_border_color="@android:color/white" app:tab_items="@array/demo_array" app:tab_radius="5dp" app:tab_textSize="16sp" app:tab_textColor="@color/radio_button_color_green" android:paddingTop="5dp" android:paddingBottom="5dp" /> </FrameLayout> </LinearLayout> </ScrollView>
顏色selector
<?xml version="1.0" encoding="utf-8"?> <selector xmlns:android="http://schemas.android.com/apk/res/android"> <item android:color="@color/tab_light_blue" android:state_checked="true" /> <item android:color="@android:color/white" /> </selector>
tab數組
<string-array name="demo_array"> <item>A</item> <item>B</item> <item>C</item> </string-array>
完整代碼能夠再這裏獲取: