当前位置:   article > 正文

android中radiogroup作用,Android View系列---RadioGroup与RadioButton

android radiogroup 获取view

RadioGroup与RadioButton配合实现一组数据的单选问题。

插播一条信息,在设置RadioButton的textColor的选中效果时,不能在drawable中创建想xml,得在res/color文件中创建xml,然后引用。

radioButton.setTextColor(getResources().getColorStateList(R.color.xxx));

这个过程中,需要注意几点。

RadioButton 设置前面小圆点消失 radioButton.setButtonDrawable(null)

RadioGroup 下面的RadioButton不能用其他控件包裹,否则就会是一个一个单独的RadioButton。

在动态创建RadioButton的时候,需要设置margin时,需要使用RadioGroup.LayoutParams 来创建布局参数,不然设置margin不起作用。

如何实现在RadioGroup与RadioButton配合时,现在点击两次RadioButton,取消选中

对以上问题,具体我们分析下:

为什么RadioGroup的直接子控件必须是RadioButt呢?

先来看下RadioGroup的init()方法

private void init() {

// tracks children radio buttons checked state 追踪RadioButton的选中状态

mChildOnCheckedChangeListener = new CheckedStateTracker();

// 监听层级变化 ViewGroup的子View移除和添加都会触发相对应的方法。

mPassThroughListener = new PassThroughHierarchyChangeListener();

super.setOnHierarchyChangeListener(mPassThroughListener);

}

/**

* {@inheritDoc} 给用户提供一个方法,可以自己实现层级的监听

*/

@Override

public void setOnHierarchyChangeListener(OnHierarchyChangeListener listener) {

// the user listener is delegated to our pass-through listener

mPassThroughListener.mOnHierarchyChangeListener = listener;

}

再看下,PassThroughHierarchyChangeListener 实现的添加和移除的方法

private class PassThroughHierarchyChangeListener implements

ViewGroup.OnHierarchyChangeListener {

private ViewGroup.OnHierarchyChangeListener mOnHierarchyChangeListener;

/**

* {@inheritDoc}

*/

public void onChildViewAdded(View parent, View child) {

// 关键点一: 如果child是RadioButton,才会执行

if (parent == RadioGroup.this && child instanceof RadioButton) {

int id = child.getId();

// generates an id if it's missing

if (id == View.NO_ID) {

id = View.generateViewId();

child.setId(id);

}

// 关键点二:把追踪RadioButton选择状态的监听,设置到radiobutoon上,以实现监听

((RadioButton) child).setOnCheckedChangeWidgetListener(

mChildOnCheckedChangeListener);

}

// 如果用户自己定义,会继续走用户自己定义的方法

if (mOnHierarchyChangeListener != null) {

mOnHierarchyChangeListener.onChildViewAdded(parent, child);

}

}

。。。。

}

接着,我们来看下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());

}

}

// 父类ViewGroup的addView方法

super.addView(child, index, params);

}

ViewGroup.java

从源码里可以 addView()方法里面调用了 addViewInner()方法,在里面调用了disparchViewAdd(child)方法。

addView() —> addViewInner() —>dispatchViewAdd()

void dispatchViewAdded(View child) {

onViewAdded(child);

// 在RadioGroup init方法中,设置了该listener。在这里回调到onChildViewAdded()方法。再为radiobutton设置了OnCheckedChangeWidgetListener

if (mOnHierarchyChangeListener != null) {

mOnHierarchyChangeListener.onChildViewAdded(this, child);

}

}

理清楚他们之间的关联,现在该是点击的时候了。

之前介绍过onclick方法,之所以能执行,是整个事件分发完之后,执行了performClick()方法,然后执行clicklistener的onclick回调方法。

RadioButton继承了CompoundButton。 里面的performClick方法

CompoundButton.java

@Override

public boolean performClick() {

// 先执行radioButton的toggle方法

toggle();

// 执行 onclick方法。

final boolean handled = super.performClick();

if (!handled) {

// View only makes a sound effect if the onClickListener was

// called, so we'll need to make one here instead.

playSoundEffect(SoundEffectConstants.CLICK);

}

return handled;

}

public void toggle() {

setChecked(!mChecked);

}

RadioButton.java

/**

* {@inheritDoc}

*

* If the radio button is already checked, this method will not toggle the radio button.

*/

@Override

public void toggle() {

// we override to prevent toggle when the radio is already

// checked (as opposed to check boxes widgets)

// 关键点四:如果该RadioButton已经选中了,就不执行了,这也是RadioButton一旦被选择了,就不能取消选中的根本原因。

if (!isChecked()) {

super.toggle();

}

}

那RadioButton怎么和RadioGroup联系到一起的呢?

RadioButton的父类CompoundButton的toggle

public void toggle() {

setChecked(!mChecked);

}

/**

*

Changes the checked state of this button.

* 真正改变RadioButton状态的方法。

* @param checked true to check the button, false to uncheck it

*/

public void setChecked(boolean checked) {

if (mChecked != checked) {

mChecked = checked;

// 刷新选中态的UI

refreshDrawableState();

notifyViewAccessibilityStateChangedIfNeeded(

AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED);

// Avoid infinite recursions if setChecked() is called from a listener

if (mBroadcasting) {

return;

}

mBroadcasting = true;

if (mOnCheckedChangeListener != null) {

mOnCheckedChangeListener.onCheckedChanged(this, mChecked);

}

// 由前面关键点二可知,在RadioGroup中设置这个listener,所以回调到RadioGroup中

if (mOnCheckedChangeWidgetListener != null) {

mOnCheckedChangeWidgetListener.onCheckedChanged(this, mChecked);

}

mBroadcasting = false;

}

}

再来看下CheckedChangeWidgetListener的具体实现 CheckedStateTracker

private class CheckedStateTracker implements CompoundButton.OnCheckedChangeListener {

public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {

// prevents from infinite recursion

if (mProtectFromCheckedChange) {

return;

}

mProtectFromCheckedChange = true;

//关键点三:将其他的RadioButton置为未选中 mCheckedId是之前选择的View Id,

if (mCheckedId != -1) {

setCheckedStateForView(mCheckedId, false);

}

mProtectFromCheckedChange = false;

int id = buttonView.getId();

// 更新 mCheckedId

setCheckedId(id);

}

}

private void setCheckedStateForView(int viewId, boolean checked) {

// 找到之前选中的RadioButton。设置它的选中状态。

View checkedView = findViewById(viewId);

if (checkedView != null && checkedView instanceof RadioButton) {

((RadioButton) checkedView).setChecked(checked);

}

}

以上分析了整个RadioGroup为什么子View必须是RadioButton 才能起到一组单选的效果,以及整个流程。

2、怎么实现RadioButton点击两次,取消选中呢?

由关键点四,可以知道如果RadioButton选中了,就不会执行setChecked()方法也就无法通知RadioGroup。

但是他扔会走touch方法、click方法。

我写的思路就是,在RadioButton的点击事件里面,人为的设置radiobutton的选中状态。

但是RadioButton的click事件是发生在RadioButton自己的setChecked()之后,所以

radioButton.setOnClickListener(new OnClickListener(){

@Override

public void onClick(View v){

// 不管该控件的状态之前是选中态还是未选中态,这个时候,都已经是选中状态了

// 所以这个时候,radioButton的isChecked()得到的都是true

// 所以关键是找到之前的选中的是哪个控件。

if (checkedId == v.getId()){

// 说明是第二次点击该控件,所以要做清除选中逻辑

// 清除选中,其实纵观整个RadioGroup,只有当前的RadioButton被选中了,而此时恰恰需要清除选中,则只需要把RadioGroup全部清空状态即可。

radioGroup.clearCheck();

}

}

})

根据View的整个事件分发机制,click事件,是最后触发的。

所以我们可以在touch事件中获得到之前选中的状态。

又根据RadioGroup提供了一个方法getCheckedRadioButtonId(),返回选中态RadioButton的id

int checkedId = -1;

radioButton.setOnTouchListener(new OnTouchListener(){

@Override

public boolean onTouch(View v, MotionEvent event){

// 这时候,新的button状态还没有设置,所以返回的是之前选中的button

checkedId = radioGroup.getCheckedRadioButtonId();

// 不消耗掉该事件,接着往下传递给click事件。

return false;

}

})

这样就是整个过程了。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Monodyee/article/detail/733693
推荐阅读
相关标签
  

闽ICP备14008679号