**
前言
**
在Android中,我们一般通过RadioGroup来管理一组RadioButton 来达到 单选按钮的互斥效果。但是,有些需求中,需要完成N行N列这样的RadioButton组成的矩阵,但是我们的RadioGroup是一个耿直的LinearLayout,无法完成网格布局╮(╯▽╰)╭。所以,下面我就像大家来介绍一种实现网格布局的RadioButton的思路。
无图无真相, 先上一下效果图~
**
思路
**
提到网格布局,最简单的就是使用系统的GridView来实现,我们需要做的就是 将RadioButton加入GridView中,然后自己来实现RadioButton之间的互斥。
1. 自定义RadioButton:
自定义一个RadioButton ,命名为IconRadioButton
/** * Created by jk on 2016/1/20. * 自定义 RadioButton */public class IconRadioButton extends LinearLayout { private Context mContext; private Resources mResources; private boolean mIsCheck; private View mContentView; private ImageView mRadio; private TextView mTextView; private ColorStateList mTextColor; public IconRadioButton(Context context) { this(context, null); } public IconRadioButton(Context context, AttributeSet attrs) { this(context, attrs, 0); } public IconRadioButton(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); init(context); } private void init(Context context) { mContext = context; mResources = context.getResources(); mContentView = LayoutInflater.from(context).inflate(R.layout.btn_icon_radio, this); mRadio = (ImageView) mContentView.findViewById(R.id.radio); mTextView = (TextView) mContentView.findViewById(R.id.text); } public void setChecked(boolean isChecked) { mIsCheck = isChecked; changeUIByChecked(isChecked); } public boolean isChecked() { return mIsCheck; } private void changeUIByChecked(boolean isChecked) { if (mRadio.getVisibility() != GONE) { mRadio.setImageResource(isChecked ? R.drawable.radio_selected : R.drawable.radio_unselected); } mTextView.setEnabled(isChecked); } public void setTextColor(ColorStateList color){ mTextColor = color; mTextView.setTextColor(color); } public void setText(CharSequence text) { mTextView.setText(text); } public void setText(int resId) { mTextView.setText(resId); } public void hiddenRadio(boolean isHidden) { mRadio.setVisibility(isHidden ? GONE : VISIBLE); }}
这个IconRadioButton很简单 就是一个LinearLayout,内部封装了根据是否选中来改变文字和按钮样式的方法。
btn_icon_radio.xml
<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="wrap_content" android:layout_height="wrap_content" android:orientation="horizontal" android:gravity="left" android:paddingBottom="5dp" android:paddingTop="5dp"> <ImageView android:id="@+id/radio" android:layout_width="42dp" android:layout_height="match_parent" android:layout_gravity="center_vertical" android:gravity="center" android:src="@drawable/radio_selected" android:textColor="#FF1CBFA6" /> <TextView android:id="@+id/text" android:layout_width="wrap_content" android:layout_height="match_parent" android:layout_gravity="center_vertical" android:gravity="center" android:textColor="#FF999999" android:textSize="14dp" /></LinearLayout>
布局文件很简单 就是一个LinearLayout里面放了一个ImageView和一个TextView
2 . 定义数据模型
/** * Created by admin on 2016/1/20. */public class RadioItemModel { public String text; //RadioButton的文字 public boolean isChecked;//是否选中 public boolean hiddenRadio;//是否需要隐藏radio public ColorStateList textColor;//文字的不同状态的颜色 public RadioItemModel(String text, boolean isChecked, boolean hiddenRadio, ColorStateList textColor) { this.text = text; this.isChecked = isChecked; this.hiddenRadio = hiddenRadio; this.textColor = textColor; } public RadioItemModel(String text) { this.isChecked = false; this.hiddenRadio = false; this.textColor = null; this.text = text; } public void setText(String text) { this.text = text; } public String getText() { return text; } public boolean isChecked() { return isChecked; }}
我们定义了一个数据模型来存放RadioButton的各种属性。其中ColorStateList是用来控制TextView在不同状态下的颜色的 比如:state_pressed等。
3. 定义Adapter:
既然是使用GridView 那就需要定义我们的Adapter,我们的互斥逻辑也是在Adapter中实现的。
/** * Created by jk on 2016/1/20. * function: 单选矩阵的适配器 * purpose: 系统的RadioGroup是个耿直的LinearLayout╮(╯▽╰)╭ 只能线性排列,无法完成 * N行N列的布局。So 为了实现单选按钮的网格布局 ,重定义 */public class GridRadioAdapter extends BaseAdapter { private List<RadioItemModel> mList; private Context mContext; private Resources mResources; private OnItemCheckedListener mListener; //RadioButton选中时的回调函数 public interface OnItemCheckedListener { void onItemChecked(RadioItemModel model, int position); } public void setOnItemCheckedListener(OnItemCheckedListener listener) { this.mListener = listener; } public GridRadioAdapter(Context context, List<RadioItemModel> list) { mContext = context; mList = list; check(); } private void check() { if (mList.size()>=0 && mList!=null) { checkDefaultChecked(); checkMutex(); } } /** * 检查互斥事件 默认只能选中一个 如果有多个选择,就选中最后一个 */ private void checkMutex() { int checkCount = 0; for (RadioItemModel item : mList) { if (item.isChecked) { checkCount++; } } if (checkCount >= 2) { setOtherUnChecked(checkCount - 1); } } private void setOtherUnChecked(int position) { for (int i = 0; i < mList.size(); i++) { if (i != position) { RadioItemModel item = mList.get(i); item.isChecked = false; } else { mList.get(position).isChecked = true; } } } public RadioItemModel getItemChecked() { for (int i = 0; i < mList.size(); i++) { RadioItemModel item = mList.get(i); if (item.isChecked) return item; } return null; } /** * 检查是否有默认选中的按钮 如果没有 默认第一个选中 */ private void checkDefaultChecked() { for (RadioItemModel item : mList) { if (item.isChecked) return; } mList.get(0).isChecked = true; } @Override public int getCount() { return mList == null ? 0 : mList.size(); } @Override public Object getItem(int position) { if (mList != null && mList.size() > position) return mList.get(position); return null; } @Override public long getItemId(int position) { return position; } @Override public View getView(final int position, View convertView, ViewGroup parent) { IconRadioButton iconBean = null; iconBean = new IconRadioButton(mContext); final RadioItemModel model = mList.get(position); if (!TextUtils.isEmpty(model.text)) { iconBean.setText(model.text); } iconBean.setChecked(model.isChecked); if (model.textColor != null) { iconBean.setTextColor(model.textColor); } iconBean.hiddenRadio(model.hiddenRadio); final IconRadioButton finalIconBean = iconBean; iconBean.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { if (!finalIconBean.isChecked()) { setOtherUnChecked(position); if (mListener != null) { mListener.onItemChecked(model, position); } notifyDataSetChanged(); } } }); return iconBean; } public void addAll(List<RadioItemModel> list){ mList.clear(); if(list.size()>=0 && list!=null){ mList.addAll(list); check(); notifyDataSetChanged(); } }}
在构造函数中,我们调用了check方法来实现默认选中检查和 互斥检查。
(1)checkDefaultChecked函数用来实现默认选中功能,如果传递给我们的数据中没有按钮是默认选中的 ,那我们就让第一个按钮默认选中。
(2)checkMutex函数是用来检查互斥事件的,如果有多个按钮同时被选中,我们就设置被选中的最后一个按钮为选中状态,其他置为非选中状态。比如 按钮1,3,5同时被选中,那么我们就让5置为选中状态,1和3为非选中状态。
(3)OnItemCheckedListener是当按钮被选中时的回调方法。
4.使用方式
使用方式就非常简单粗暴了~
public class MainActivity extends Activity { private GridView mGridLayout; private GridRadioAdapter mAdapter; private List<RadioItemModel> mItemList; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); } private void initData() { mItemList = new ArrayList<RadioItemModel>(); ColorStateList csl = getResources().getColorStateList(R.color.ddt_color_tab_text); mItemList.add(new RadioItemModel("全部", false, true, csl)); mItemList.add(new RadioItemModel("早餐前", false, true, csl)); mItemList.add(new RadioItemModel("午餐前", false, true, csl)); mItemList.add(new RadioItemModel("晚餐前", false, true, csl)); mItemList.add(new RadioItemModel("早餐后", false, true, csl)); mItemList.add(new RadioItemModel("午餐后", false, true, csl)); mItemList.add(new RadioItemModel("晚餐后", false, true, csl)); mItemList.add(new RadioItemModel("睡前", false, true, csl)); mAdapter.notifyDataSetChanged(); } }
PS: 如果设置hiddenRadio这个属性为true,我们就可以实现下面这种效果了。所以这个东西也是可以用来做切换Fragment的选项卡的哦~~~ O(∩_∩)O
以上。
- 1楼adfghjkl9小时前
- 挺好