当前位置:   article > 正文

自定义适配单选和多选情况的RadioButton和RadioGroup_安卓开发利用radio button实现单选

安卓开发利用radio button实现单选

一、效果展示

 

        在 Android 应用程序开发中,按钮是常见的 UI 元素。虽然 Android 提供了各种默认的按钮样式,但有时您可能需要自定义按钮以满足特定的设计需求。为此,我创建了一个自定义 RadioButton 类 CustomRadioButton,它继承自 AndroidX 中的 AppCompatTextView,实现单选题和多选题的效果,如上图所示。       

        在左侧的多选题中,如果选择了ABD三个选项但未提交,选中的文字、背景和边框会呈现棕色,未选中的则会呈现灰色。

        右侧的单选题中,如果选择了A选项但正确答案是C选项,你会看到正确选项和错误选项有不同的效果。正确选项会显示一个绿色的勾,而错误选项则会显示一个红色的叉,它们的文字、背景和边框颜色也是有区别的。

以下是在xml中使用的代码:

  1. <com.noblel.baselibrary.view.CustomRadioButtonGroup
  2. android:id="@+id/rgOptions"
  3. android:layout_width="match_parent"
  4. android:layout_height="wrap_content"
  5. android:layout_marginLeft="10dp"
  6. android:layout_marginRight="10dp"
  7. android:orientation="vertical">
  8. <com.noblel.baselibrary.view.CustomRadioButton
  9. android:id="@+id/cb_choice1"
  10. android:padding="8dp"
  11. android:layout_width="match_parent"
  12. android:minHeight="48dp"
  13. android:layout_height="wrap_content"/>
  14. <com.noblel.baselibrary.view.CustomRadioButton
  15. android:id="@+id/cb_choice2"
  16. android:layout_marginTop="10dp"
  17. android:padding="8dp"
  18. android:layout_width="match_parent"
  19. android:minHeight="48dp"
  20. android:layout_height="wrap_content"/>
  21. <com.noblel.baselibrary.view.CustomRadioButton
  22. android:id="@+id/cb_choice3"
  23. android:layout_marginTop="10dp"
  24. android:padding="8dp"
  25. android:layout_width="match_parent"
  26. android:minHeight="48dp"
  27. android:layout_height="wrap_content"/>
  28. <com.noblel.baselibrary.view.CustomRadioButton
  29. android:id="@+id/cb_choice4"
  30. android:layout_marginTop="10dp"
  31. android:padding="8dp"
  32. android:layout_width="match_parent"
  33. android:minHeight="48dp"
  34. android:layout_height="wrap_content"/>
  35. </com.noblel.baselibrary.view.CustomRadioButtonGroup>

        那么,应该如何实现这种效果呢?

二、CustomRadioButton 实现

        CustomRadioButton 中包含了多种状态,如普通状态、选中状态、正确状态和错误状态。它还包含了 isChecked 和 isCorrect 属性来标记当前是否选中和是否为正确答案。以下是         CustomRadioButton 类的代码:

  1. public class CustomRadioButton extends androidx.appcompat.widget.AppCompatTextView {
  2. //当前状态
  3. private State mState;
  4. //普通状态
  5. NormalState normalState;
  6. //选中状态
  7. CheckedState checkedState;
  8. //正确状态
  9. CorrectState correctState;
  10. //错误状态
  11. WrongState wrongState;
  12. //是否选中
  13. private boolean isChecked = false;
  14. //是否正确
  15. private boolean isCorrect = false;
  16. public CustomRadioButton(Context context) {
  17. super(context);
  18. init(context);
  19. }
  20. public CustomRadioButton(Context context, AttributeSet attrs) {
  21. super(context, attrs);
  22. init(context, attrs);
  23. }
  24. public CustomRadioButton(Context context, AttributeSet attrs, int defStyle) {
  25. super(context, attrs, defStyle);
  26. init(context, attrs);
  27. }
  28. // 设置状态方法
  29. private void setState(State state, TypedArray styleAttrs) {
  30. mState = state;
  31. mState.applyStyle(this);
  32. mState.setMargin(this, styleAttrs);
  33. mState.setPadding(this, styleAttrs);
  34. }
  35. @Override
  36. public void setText(CharSequence text, BufferType type) {
  37. // 调用父类方法设置文字
  38. super.setText(text, type);
  39. // 如果状态对象不为空,则应用状态样式
  40. if (mState != null) {
  41. mState.applyStyle(this);
  42. }
  43. }
  44. private void setState(State state) {
  45. mState = state;
  46. mState.applyStyle(this);
  47. }
  48. private void init(Context context, AttributeSet attrs) {
  49. TypedArray styleAttrs = context.obtainStyledAttributes(attrs, R.styleable.CustomRadioButton);
  50. try {
  51. //普通样式
  52. normalState = new NormalState(context, styleAttrs);
  53. //选中样式
  54. checkedState = new CheckedState(context, styleAttrs);
  55. //正确样式
  56. correctState = new CorrectState(context, styleAttrs);
  57. //错误样式
  58. wrongState = new WrongState(context, styleAttrs);
  59. setState(normalState, styleAttrs);
  60. } finally {
  61. styleAttrs.recycle();
  62. }
  63. }
  64. private void init(Context context) {
  65. normalState = new NormalState(context);
  66. checkedState = new CheckedState(context);
  67. correctState = new CorrectState(context);
  68. wrongState = new WrongState(context);
  69. setState(normalState);
  70. }
  71. void setTextSize(int size) {
  72. // 设置文字大小
  73. setTextSize(TypedValue.COMPLEX_UNIT_PX, size);
  74. }
  75. void setIcon(Drawable drawable) {
  76. // 设置左侧图标
  77. setCompoundDrawablesWithIntrinsicBounds(drawable, null, null, null);
  78. }
  79. public boolean isChecked() {
  80. return isChecked;
  81. }
  82. public void setChecked(boolean doCheckOrNot) {
  83. isChecked = doCheckOrNot;
  84. // 更新当前选中的选项
  85. //还可以点击
  86. if (isEnabled()) {
  87. if (isChecked) {
  88. setState(checkedState);
  89. } else {
  90. setState(normalState);
  91. }
  92. }
  93. }
  94. public boolean isCorrect() {
  95. return isCorrect;
  96. }
  97. public void setCorrect(boolean correct) {
  98. isCorrect = correct;
  99. }
  100. public void setAfterSubmit() {
  101. if (isCorrect) {
  102. setState(correctState);
  103. } else {
  104. if (isChecked) {
  105. setState(wrongState);
  106. } else {
  107. setState(normalState);
  108. }
  109. }
  110. }
  111. }

        CustomRadioButton是一个自定义的RadioButton,继承自AppCompatTextView,通过设置不同的状态,可以实现不同的按钮样式。

        其中,CustomRadioButton包含四种状态:NormalState(普通状态)、CheckedState(选中状态)、CorrectState(正确状态)和WrongState(错误状态),分别表示四种不同的按钮状态。

        在CustomRadioButton中,定义了以下方法:

  • setState(State state):设置CustomRadioButton的状态,参数为State类型,表示要设置的状态。
  • setTextSize(int size):设置CustomRadioButton的文本大小。
  • setIcon(Drawable drawable):设置CustomRadioButton的左侧图标。
  • isChecked():获取CustomRadioButton是否被选中。
  • setChecked(boolean doCheckOrNot):设置CustomRadioButton是否被选中,参数为boolean类型,表示是否被选中。
  • isCorrect():获取CustomRadioButton是否为正确选项。
  • setCorrect(boolean correct):设置CustomRadioButton是否为正确选项,参数为boolean类型,表示是否为正确选项。
  • setAfterSubmit():设置CustomRadioButton的状态,表示用户提交答案后的状态。

        CustomRadioButton使用了状态模式来管理不同状态下的样式。

        状态模式是一种行为型设计模式,它允许对象在内部状态改变时改变其行为。状态模式将状态封装到单独的类中,并将对象的行为委托给当前状态的对象。

        在CustomRadioButton中,状态对象被封装到不同的类中,包括NormalState、CheckedState、CorrectState和WrongState。每个状态都继承了State父类,它包含了在状态改变时需要执行的操作。

        当CustomRadioButton被创建时,它会初始化所有状态,并将初始状态设置为NormalState。当CustomRadioButton的状态发生变化时,它会调用setState方法来设置新的状态。在setState方法中,CustomRadioButton会将新状态应用于当前View,并更新视图的外观和行为。

        通过使用状态模式,CustomRadioButton能够更好地管理不同状态下的样式,并且能够更加灵活地处理状态变化,使得代码更加简洁和易于维护。

三、RadioButtonGroup实现

        这是自定义的 RadioButtonGroup 类,可以和 CustomRadioButton 配合使用,实现单选或多选功能。该类继承自 LinearLayout,可以在布局中直接使用。该类主要包含以下成员变量和方法:

  1. public class CustomRadioButtonGroup extends LinearLayout {
  2. private OnCheckedChangeListener mCheckedChangeListener;
  3. //选中了哪些按钮
  4. private List<CustomRadioButton> mSelectedRadioButtonList;
  5. //是否为单选
  6. private boolean singleChoose = false;
  7. public boolean isSingleChoose() {
  8. return singleChoose;
  9. }
  10. public void setSingleChoose(boolean singleChoose) {
  11. this.singleChoose = singleChoose;
  12. }
  13. // 设置选中状态变化的监听器
  14. public void setOnCheckedChangeListener(OnCheckedChangeListener listener) {
  15. mCheckedChangeListener = listener;
  16. }
  17. // 定义一个选中状态变化的监听器接口
  18. public interface OnCheckedChangeListener {
  19. void onCheckedChanged(CustomRadioButtonGroup group, int checkedId);
  20. }
  21. private void init() {
  22. }
  23. @Override
  24. protected void onFinishInflate() {
  25. super.onFinishInflate();
  26. // 使用 Handler 添加一个延时任务
  27. new Handler().postDelayed(new Runnable() {
  28. @Override
  29. public void run() {
  30. // 在延时任务中获取子视图的数量
  31. // 这里可以对子视图进行操作,例如获取子视图的属性或者进行其他逻辑处理
  32. // ...
  33. int count = getChildCount();
  34. for (int i = 0; i < count; i++) {
  35. View child = getChildAt(i);
  36. if (child instanceof CustomRadioButton) {
  37. final CustomRadioButton radioButton = (CustomRadioButton) child;
  38. radioButton.setOnClickListener(new OnClickListener() {
  39. @Override
  40. public void onClick(View view) {
  41. selectRadioButton(radioButton);
  42. }
  43. });
  44. }
  45. }
  46. }
  47. }, 150); // 这里的延时时间可以根据实际情况进行调整,单位为毫秒
  48. }
  49. /**
  50. * 设置按钮的点击事件
  51. *
  52. * @param radioButton 按钮
  53. */
  54. private void selectRadioButton(CustomRadioButton radioButton) {
  55. //判断是否已经选中
  56. boolean checked = radioButton.isChecked();
  57. if (singleChoose) {
  58. // 如果是单选模式,先清除之前选中的按钮
  59. clearSelectedRadioButtons();
  60. }
  61. //设置选中或者未选中状态转变
  62. radioButton.setChecked(!checked);
  63. //选中按钮list集合
  64. if (mSelectedRadioButtonList == null) {
  65. mSelectedRadioButtonList = new ArrayList<>();
  66. }
  67. //如何当前按钮是选中了
  68. if (radioButton.isChecked()) {
  69. //将当前按钮添加到list集合
  70. if (!mSelectedRadioButtonList.contains(radioButton)) {
  71. mSelectedRadioButtonList.add(radioButton);
  72. }
  73. } else {
  74. //从list集合中移除按钮
  75. mSelectedRadioButtonList.remove(radioButton);
  76. }
  77. //通知点击状态已经改变
  78. if (mCheckedChangeListener != null) {
  79. mCheckedChangeListener.onCheckedChanged(this, radioButton.getId());
  80. }
  81. }
  82. private void clearSelectedRadioButtons() {
  83. if (mSelectedRadioButtonList != null) {
  84. for (CustomRadioButton radioButton : mSelectedRadioButtonList) {
  85. radioButton.setChecked(false);
  86. }
  87. mSelectedRadioButtonList.clear();
  88. }
  89. }
  90. //获取选择的button
  91. public List<CustomRadioButton> getSelectedIndex() {
  92. List<CustomRadioButton> selectedCheckBoxes = new ArrayList<>();
  93. if (mSelectedRadioButtonList != null) {
  94. for (CustomRadioButton cb : mSelectedRadioButtonList) {
  95. if (cb.isChecked()) {
  96. selectedCheckBoxes.add(cb);
  97. cb.setChecked(true);
  98. }
  99. }
  100. }
  101. return selectedCheckBoxes;
  102. }
  103. public void setShowAnswer() {
  104. int count = getChildCount();
  105. for (int i = 0; i < count; i++) {
  106. View child = getChildAt(i);
  107. if (child instanceof CustomRadioButton) {
  108. final CustomRadioButton radioButton = (CustomRadioButton) child;
  109. radioButton.setEnabled(false);
  110. radioButton.setAfterSubmit();
  111. }
  112. }
  113. }
  114. public CustomRadioButtonGroup(Context context) {
  115. super(context);
  116. init();
  117. }
  118. public CustomRadioButtonGroup(Context context, AttributeSet attrs) {
  119. super(context, attrs);
  120. init();
  121. }
  122. public CustomRadioButtonGroup(Context context, AttributeSet attrs, int defStyle) {
  123. super(context, attrs, defStyle);
  124. init();
  125. }
  126. }

        RadioButtonGroup 是一种自定义的 View 组,可以用于组合多个 CustomRadioButton 控件,从而实现单选或多选的功能。其主要作用是方便用户在一组选项中进行选择,使得用户可以在多个选项中选择一个或多个,从而满足用户不同的需求,提升用户体验。同时,通过在 RadioButtonGroup 中设置 OnCheckedChangeListener 接口,可以监听 RadioButton 的选中状态变化,从而实现相应的逻辑操作。

完整代码见:https://gitee.com/liuhaikang/custom-radio-button.git

使用的位置在:

  • question/app/src/main/java/com/lidan/xiao/danquestion/activity/QuestionActivity.java
  • question/app/src/main/res/layout/queitem.xml

定义的位置在:

  • question/baselibrary/src/main/java/com/noblel/baselibrary/view/CustomRadioButton.java
  • question/baselibrary/src/main/java/com/noblel/baselibrary/view/CustomRadioButtonGroup.java

直接按关键字全局搜索一下就能找到。

最后,对此篇文章有任何疑问欢迎在评论区提出。

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

闽ICP备14008679号