**

前言

**
在Android中,我们一般通过RadioGroup来管理一组RadioButton 来达到 单选按钮的互斥效果。但是,有些需求中,需要完成N行N列这样的RadioButton组成的矩阵,但是我们的RadioGroup是一个耿直的LinearLayout,无法完成网格布局╮(╯▽╰)╭。所以,下面我就像大家来介绍一种实现网格布局的RadioButton的思路。
无图无真相, 先上一下效果图~

怎么用android profiler 怎么用android studio 用Button做网格布局_android

**

思路

**
提到网格布局,最简单的就是使用系统的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

怎么用android profiler 怎么用android studio 用Button做网格布局_自定义View_02

以上。