记录RadioGroup和RadioButton的单选实现原理

很多时候,需要在开发中需要实现类似RadioGroup和RadioButton结合使用实现的单选效果,但是RadioGroup和RadioButton结合的实现效果不能完全定制化,不能适应所有的APP开发需求,这里简单的剖析下RadioGroup的实现原理,来完成自定义RadioGroup显示单选。
在之前写这种实现的时候,因为没有阅读过源码,实现的比较挫,简单的用一个List存放所有的单元Item,然后在点击事件中,遍历所有的View,挨个设置点击事件,虽然也能实现点击效果但是效率低的不行,而且感觉写起来就是一种垃圾代码,写过几次之后,决定研究下原生的代码写法,脱离低级,向优秀进发。
下面看一下RadioGroup的源码吧:
首先RadioGroup是继承的LinearLayout,这就很多时候限制了我们一些开发的实现

public class RadioGroup extends LinearLayout

如果自定义的话,这东西就灵活多了
实现单选的关键部分是

  private int mCheckedId = -1;

这个是用来存储单选选中的view的id值的,
RadioGroup重写了addView方法

  @Override
    public void addView(View child, int index, ViewGroup.LayoutParams params) {
        if (child instanceof RadioButton) {
            final RadioButton button = (RadioButton) child;
            if (button.isChecked()) {
                mProtectFromCheckedChange = true;
                if (mCheckedId != -1) {
                    setCheckedStateForView(mCheckedId, false);
                }
                mProtectFromCheckedChange = false;
                setCheckedId(button.getId());
            }
        }

        super.addView(child, index, params);
    }

可以看到首先RadioGroup会先判断子view是否是RadioButton,如果是,判断是否默认已经被选择

   private void setCheckedStateForView(int viewId, boolean checked) {
        View checkedView = findViewById(viewId);
        if (checkedView != null && checkedView instanceof RadioButton) {
            ((RadioButton) checkedView).setChecked(checked);
        }
    }

setCheckedStateForView(int viewId, boolean checked)方法是用来实现点击效果的,这个地方很好理解。
那么addView剩下的只剩一个setCheckedId(id)这个方法了

private void setCheckedId(@IdRes int id) {
        mCheckedId = id;
        if (mOnCheckedChangeListener != null) {
            mOnCheckedChangeListener.onCheckedChanged(this, mCheckedId);
        }
    }

这里就是实现之前说的,将单选的view的id赋值给mCheckedId ,并且,额外的,绑定了监听器
在addView之后,RadioGroup重新了这个方法

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

        // checks the appropriate radio button as requested in the XML file
        if (mCheckedId != -1) {
            mProtectFromCheckedChange = true;
            setCheckedStateForView(mCheckedId, true);
            mProtectFromCheckedChange = false;
            setCheckedId(mCheckedId);
        }
    }

这个方法是确保在整个addView结束后,最终确定显示被点击的Item;
单选电机的实现原理主要是以下这个方法:

    public void check(@IdRes int id) {
        // don't even bother
        if (id != -1 && (id == mCheckedId)) {
            return;
        }

        if (mCheckedId != -1) {
            setCheckedStateForView(mCheckedId, false);
        }

        if (id != -1) {
            setCheckedStateForView(id, true);
        }

        setCheckedId(id);
    }

这里的意思就是,首先确定点击的是原来被选中的项,不作处理,如果是新的项,那么先把原来的项的点击显示变成false,之后,把当前电机的项的显示变为显示状态,之后,将当前点击的id赋值给mCheckedId;

那么最后总结下逻辑:
首先,初始化mCheckedId=-1,然后addView中处理默认的点击项,点击项的id传给mCheckedId,当每次点击新的项时,根据mCheckedId,将原来的点击项置为未点击,然后根据新的项的id,把新的项置为点击,最后,新的项的id赋值给mCheckedId,来维护单选。

你可能感兴趣的:(Android方向)