先看下效果
修改 RadioGroup 源码自定义了一个RadioButton,有需要的就直接拿去吧
github https://github.com/781015928/SoftRadioGroup
public class SoftRadioGroup extends LinearLayout {
// holds the checked id; the selection is empty by default
private int mCheckedId = -1;
private boolean orientation;
// tracks children radio buttons checked state
private SoftRadioButton.OnCheckedChangeListener mChildOnCheckedChangeListener;
// when true, mOnCheckedChangeListener discards events
private boolean mProtectFromCheckedChange = false;
private OnCheckedChangeListener mOnCheckedChangeListener;
private PassThroughHierarchyChangeListener mPassThroughListener;
/**
* {@inheritDoc}
*/
public SoftRadioGroup(Context context) {
super(context);
init();
}
/**
* {@inheritDoc}
*/
public SoftRadioGroup(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
private void init() {
//setOrientation(HORIZONTAL);
mChildOnCheckedChangeListener = new CheckedStateTracker();
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;
}
/**
* {@inheritDoc}
*/
@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;
}
}
@Override
public void addView(View child, int index, ViewGroup.LayoutParams params) {
if (child instanceof SoftRadioButton) {
final SoftRadioButton button = (SoftRadioButton) child;
if (button.isChecked()) {
mProtectFromCheckedChange = true;
if (mCheckedId != -1) {
setCheckedStateForView(mCheckedId, false);
}
mProtectFromCheckedChange = false;
}
}
super.addView(child, index, params);
}
/**
* <p>Sets the selection to the radio button whose identifier is passed in
* parameter. Using -1 as the selection identifier clears the selection;
* such an operation is equivalent to invoking {@link #clearCheck()}.</p>
*
* @param id the unique id of the radio button to select in this group
* @see #getCheckedRadioButtonId()
* @see #clearCheck()
*/
public void check(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);
}
private void setCheckedId(int id) {
mCheckedId = id;
}
public OnCheckedChangeListener getOnCheckedChangeListener() {
return mOnCheckedChangeListener;
}
public interface OnCheckedChangeListener {
/**
* <p>Called when the checked radio button has changed. When the
* selection is cleared, checkedId is -1.</p>
*
* @param group the group in which the checked radio button has changed
* @param checkedId the unique identifier of the newly checked radio button
*/
public void onCheckedChanged(SoftRadioGroup group, @IdRes int checkedId, boolean orientation);
}
private void setCheckedStateForView(int viewId, boolean checked) {
View checkedView = findViewById(viewId);
if (checkedView != null && checkedView instanceof SoftRadioButton) {
SoftRadioButton radioButton = (SoftRadioButton) checkedView;
((SoftRadioButton) checkedView).setChecked(checked,radioButton.isOrientation());
}
}
/**
* <p>Returns the identifier of the selected radio button in this group.
* Upon empty selection, the returned value is -1.</p>
*
* @return the unique id of the selected radio button in this group
* @attr ref android.R.styleable#RadioGroup_checkedButton
* @see #clearCheck()
*/
public int getCheckedRadioButtonId() {
return mCheckedId;
}
/**
* <p>Clears the selection. When the selection is cleared, no radio button
* in this group is selected and {@link #getCheckedRadioButtonId()} returns
* null.</p>
*
* @see #getCheckedRadioButtonId()
*/
public void clearCheck() {
check(-1);
}
/**
* <p>Register a callback to be invoked when the checked radio button
* changes in this group.</p>
*
* @param listener the callback to call on checked state change
*/
public void setOnCheckedChangeListener(OnCheckedChangeListener listener) {
mOnCheckedChangeListener = listener;
}
private class CheckedStateTracker implements SoftRadioButton.OnCheckedChangeListener {
public void onCheckedChanged(SoftRadioButton buttonView, boolean isChecked) {
// prevents from infinite r ecursion
if (mProtectFromCheckedChange) {
return;
}
mProtectFromCheckedChange = true;
if (mCheckedId != -1) {
setCheckedStateForView(mCheckedId, false);
}
mProtectFromCheckedChange = false;
int id = buttonView.getId();
setCheckedId(id);
}
}
/**
* <p>A pass-through listener acts upon the events and dispatches them
* to another listener. This allows the table layout to set its own internal
* hierarchy change listener without preventing the user to setup his.</p>
*/
private class PassThroughHierarchyChangeListener implements
ViewGroup.OnHierarchyChangeListener {
private ViewGroup.OnHierarchyChangeListener mOnHierarchyChangeListener;
/**
* {@inheritDoc}
*/
public void onChildViewAdded(View parent, View child) {
if (parent == SoftRadioGroup.this && child instanceof SoftRadioButton) {
int id = child.getId();
// generates an id if it's missing
if (id == View.NO_ID) {
throw new RuntimeException("SoftRadioButton must set Id");
}
((SoftRadioButton) child).setOnCheckedChangeWidgetListener(mChildOnCheckedChangeListener);
}
if (mOnHierarchyChangeListener != null) {
mOnHierarchyChangeListener.onChildViewAdded(parent, child);
}
}
/**
* {@inheritDoc}
*/
public void onChildViewRemoved(View parent, View child) {
if (mOnHierarchyChangeListener != null) {
mOnHierarchyChangeListener.onChildViewRemoved(parent, child);
}
}
}
}
@SuppressLint("AppCompatCustomView") public class SoftRadioButton extends FrameLayout implements SoftCheckable { /** * down false up true */ private boolean mBroadcasting; private boolean orientation; private TextView mTv_checkable_text; private ImageView mIv_checkable_up; private ImageView mIv_checkable_down; private OnCheckedChangeListener mOnCheckedChangeWidgetListener; private int textColor = Color.BLACK; private int textColorChecked = Color.RED; private int upImageRes, upImageResChecked, downImageRes, downImageResChecked; private SoftRadioButton(Context context) { super(context); } public SoftRadioButton(Context context, AttributeSet attrs) { super(context, attrs); initView(attrs); } public SoftRadioButton(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); initView(attrs); } private void initView(AttributeSet attrs) { TypedArray ta = getContext().obtainStyledAttributes(attrs, R.styleable.SoftRadioButton); String text = ta.getString(R.styleable.SoftRadioButton_text); textColor = ta.getColor(R.styleable.SoftRadioButton_textColor, textColor); textColorChecked = ta.getColor(R.styleable.SoftRadioButton_textColorChecked, textColorChecked); upImageRes = ta.getResourceId(R.styleable.SoftRadioButton_upImage, 0); downImageRes = ta.getResourceId(R.styleable.SoftRadioButton_downImage, 0); upImageResChecked = ta.getResourceId(R.styleable.SoftRadioButton_upImageChecked, 0); downImageResChecked = ta.getResourceId(R.styleable.SoftRadioButton_downImageChecked, 0); ta.recycle(); LayoutInflater inflate = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE); View view = inflate.inflate(R.layout.soft_item_view, this, true); mTv_checkable_text = (TextView) findViewById(R.id.tv_checkable_text); mIv_checkable_up = (ImageView) findViewById(R.id.iv_checkable_up); mIv_checkable_down = (ImageView) findViewById(R.id.iv_checkable_down); mTv_checkable_text.setText(text); refreshView(); setOnClickListener(null); } private boolean ischecked; public void setText(CharSequence text) { mTv_checkable_text.setText(text); } public CharSequence getText() { return mTv_checkable_text.getText(); } private OnClickListener ml; @Override public void setOnClickListener(@Nullable OnClickListener l) { ml = l; super.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { if (ml != null) { ml.onClick(v); } if (isChecked()) { orientation = !orientation; setChecked(true, orientation); } else { setChecked(true, orientation); } refreshView(); } }); } private SoftRadioGroup softGroup; public SoftRadioGroup getGroup() { if (softGroup == null) { if (getParent() != null && getParent() instanceof SoftRadioGroup) { softGroup = (SoftRadioGroup) getParent(); } } return softGroup; } @Override public void setChecked(boolean checked, boolean isOrientation) { if (checked) { makeCallBack(isOrientation); } if (ischecked != checked) {//刷新其他的 ischecked = checked; refreshView(); if (mBroadcasting) { return; } mBroadcasting = true; if (mOnCheckedChangeWidgetListener != null) { mOnCheckedChangeWidgetListener.onCheckedChanged(this, ischecked); } mBroadcasting = false; } else { if (isOrientation != orientation) { refreshView(); if (mBroadcasting) { return; } mBroadcasting = true; if (mOnCheckedChangeWidgetListener != null) { mOnCheckedChangeWidgetListener.onCheckedChanged(this, ischecked); } mBroadcasting = false; } } } private void makeCallBack(boolean isOrientation) { SoftRadioGroup group = getGroup(); if (group != null && group.getOnCheckedChangeListener() != null) { group.getOnCheckedChangeListener().onCheckedChanged(group, getId(), isOrientation); } } @Override public boolean isChecked() { return ischecked; } public boolean isOrientation() { return orientation; } @Override public void toggle() { ischecked = !ischecked; refreshView(); } private void refreshView() { if (isChecked()) { if (orientation) { mIv_checkable_up.setImageResource(upImageResChecked); mIv_checkable_down.setImageResource(downImageRes); } else { mIv_checkable_up.setImageResource(upImageRes); mIv_checkable_down.setImageResource(downImageResChecked); } mTv_checkable_text.setTextColor(textColorChecked); } else { mIv_checkable_up.setImageResource(upImageRes); mIv_checkable_down.setImageResource(downImageRes); mTv_checkable_text.setTextColor(textColor); } } public void setOnCheckedChangeWidgetListener(OnCheckedChangeListener onCheckedChangeWidgetListener) { mOnCheckedChangeWidgetListener = onCheckedChangeWidgetListener; } public interface OnCheckedChangeListener { /** * Called when the checked state of a compound button has changed. * * @param buttonView The compound button view whose state has changed. * @param isChecked The new checked state of buttonView. */ void onCheckedChanged(SoftRadioButton buttonView, boolean isChecked); } }
<declare-styleable name="SoftRadioButton">
<attr name="text" format="string"></attr>
<attr name="textSize" format="dimension"></attr>
<attr name="textColorChecked" format="color"></attr>
<attr name="textColor" format="color"></attr>
<attr name="upImage" format="reference"></attr>
<attr name="downImage" format="reference"></attr>
<attr name="upImageChecked" format="reference"></attr>
<attr name="downImageChecked" format="reference"></attr>
</declare-styleable>
public class MainActivity extends AppCompatActivity implements SoftRadioGroup.OnCheckedChangeListener { SoftRadioGroup radiogroup; TextView text_content; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); radiogroup = (SoftRadioGroup) findViewById(R.id.radiogroup); text_content = (TextView) findViewById(R.id.text_content); radiogroup.setOnCheckedChangeListener(this); } @Override public void onCheckedChanged(SoftRadioGroup group, @IdRes int checkedId, boolean orientation) { SoftRadioButton softradiogroup = (SoftRadioButton) radiogroup.findViewById(checkedId); text_content.setText(softradiogroup.getText() + (orientation ? "上" : "下")); } }