Android自定义View之RadioGroup实现跨多行显示

本文实例为大家分享了Android RadioGroup跨多行显示的具体代码,供大家参考,具体内容如下

此自定义View源于网络,具体出处不详。

import android.content.Context;
import android.content.res.TypedArray;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityNodeInfo;
import android.widget.CompoundButton;
import android.widget.LinearLayout;
import android.widget.RadioButton;

public class RadioGroup extends LinearLayout {
 // holds the checked id; the selection is empty by default
 private int mCheckedId = -1;
 // tracks children radio buttons checked state
 private CompoundButton.OnCheckedChangeListener mChildOnCheckedChangeListener;
 // when true, mOnCheckedChangeListener discards events
 private boolean mProtectFromCheckedChange = false;
 private OnCheckedChangeListener mOnCheckedChangeListener;
 private PassThroughHierarchyChangeListener mPassThroughListener;

 /**
  * {@inheritDoc}
  */
 public RadioGroup(Context context) {
  super(context);
  setOrientation(VERTICAL);
  init();
 }

 /**
  * {@inheritDoc}
  */
 public RadioGroup(Context context, AttributeSet attrs) {
  super(context, attrs);
  mCheckedId = View.NO_ID;

  final int index = VERTICAL;
  setOrientation(index);

  init();
 }

 private void init() {
  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;
   setCheckedId(mCheckedId);
  }
 }

 @Override
 public void addView(final View child, int index, ViewGroup.LayoutParams params) {
  if (child instanceof RadioButton) {
   child.setOnTouchListener(new OnTouchListener() {

    @Override
    public boolean onTouch(View v, MotionEvent event) {
     ((RadioButton) child).setChecked(true);
     checkRadioButton((RadioButton) child);
     if (mOnCheckedChangeListener != null) {
      mOnCheckedChangeListener.onCheckedChanged(RadioGroup.this, child.getId());
     }
     return true;
    }
   });
  } else if (child instanceof LinearLayout) {
   int childCount = ((LinearLayout) child).getChildCount();
   for (int i = 0; i < childCount; i++) {
    View view = ((LinearLayout) child).getChildAt(i);
    if (view instanceof RadioButton) {
     final RadioButton button = (RadioButton) view;
     button.setOnTouchListener(new OnTouchListener() {

      @Override
      public boolean onTouch(View v, MotionEvent event) {
       button.setChecked(true);
       checkRadioButton(button);
       if (mOnCheckedChangeListener != null) {
        mOnCheckedChangeListener.onCheckedChanged(RadioGroup.this, button.getId());
       }
       return true;
      }
     });
    }
   }
  }
  super.addView(child, index, params);
 }

 private void checkRadioButton(RadioButton radioButton) {
  View child;
  int radioCount = getChildCount();
  for (int i = 0; i < radioCount; i++) {
   child = getChildAt(i);
   if (child instanceof RadioButton) {
    if (child == radioButton) {
     // do nothing
    } else {
     ((RadioButton) child).setChecked(false);
    }
   } else if (child instanceof LinearLayout) {
    int childCount = ((LinearLayout) child).getChildCount();
    for (int j = 0; j < childCount; j++) {
     View view = ((LinearLayout) child).getChildAt(j);
     if (view instanceof RadioButton) {
      final RadioButton button = (RadioButton) view;
      if (button == radioButton) {
       // do nothing
      } else {
       button.setChecked(false);
      }
     }
    }
   }
  }
 }

 /**
  * <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;
 }

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

 /**
  * <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 #check(int)
  * @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 #check(int)
  * @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;
 }

 /**
  * {@inheritDoc}
  */
 @Override
 public LayoutParams generateLayoutParams(AttributeSet attrs) {
  return new RadioGroup.LayoutParams(getContext(), attrs);
 }

 /**
  * {@inheritDoc}
  */
 @Override
 protected boolean checkLayoutParams(ViewGroup.LayoutParams p) {
  return p instanceof RadioGroup.LayoutParams;
 }

 @Override
 protected LinearLayout.LayoutParams generateDefaultLayoutParams() {
  return new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
 }

 @Override
 public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
  super.onInitializeAccessibilityEvent(event);
  event.setClassName(RadioGroup.class.getName());
 }

 @Override
 public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
  super.onInitializeAccessibilityNodeInfo(info);
  info.setClassName(RadioGroup.class.getName());
 }

 public static class LayoutParams extends LinearLayout.LayoutParams {
  /**
   * {@inheritDoc}
   */
  public LayoutParams(Context c, AttributeSet attrs) {
   super(c, attrs);
  }

  /**
   * {@inheritDoc}
   */
  public LayoutParams(int w, int h) {
   super(w, h);
  }

  /**
   * {@inheritDoc}
   */
  public LayoutParams(int w, int h, float initWeight) {
   super(w, h, initWeight);
  }

  /**
   * {@inheritDoc}
   */
  public LayoutParams(ViewGroup.LayoutParams p) {
   super(p);
  }

  /**
   * {@inheritDoc}
   */
  public LayoutParams(MarginLayoutParams source) {
   super(source);
  }

  /**
   * <p>Fixes the child's width to
   * {@link android.view.ViewGroup.LayoutParams#WRAP_CONTENT} and the child's
   * height to {@link android.view.ViewGroup.LayoutParams#WRAP_CONTENT}
   * when not specified in the XML file.</p>
   *
   * @param a   the styled attributes set
   * @param widthAttr the width attribute to fetch
   * @param heightAttr the height attribute to fetch
   */
  @Override
  protected void setBaseAttributes(TypedArray a, int widthAttr, int heightAttr) {
   if (a.hasValue(widthAttr)) {
    width = a.getLayoutDimension(widthAttr, "layout_width");
   } else {
    width = WRAP_CONTENT;
   }

   if (a.hasValue(heightAttr)) {
    height = a.getLayoutDimension(heightAttr, "layout_height");
   } else {
    height = WRAP_CONTENT;
   }
  }
 }

 /**
  * <p>Interface definition for a callback to be invoked when the checked
  * radio button changed in this group.</p>
  */
 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
   */
  void onCheckedChanged(RadioGroup group, int checkedId);
 }

 private class CheckedStateTracker implements CompoundButton.OnCheckedChangeListener {
  public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
   // prevents from infinite recursion
   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 == RadioGroup.this && child instanceof RadioButton) {
    int id = child.getId();
    // generates an id if it's missing
    if (id == View.NO_ID) {
     id = child.hashCode();
     child.setId(id);
    }
    ((RadioButton) child).setOnCheckedChangeListener(mChildOnCheckedChangeListener);
   }

   if (mOnHierarchyChangeListener != null) {
    mOnHierarchyChangeListener.onChildViewAdded(parent, child);
   }
  }

  /**
   * {@inheritDoc}
   */
  public void onChildViewRemoved(View parent, View child) {
   if (parent == RadioGroup.this && child instanceof RadioButton) {
    ((RadioButton) child).setOnCheckedChangeListener(null);
   }

   if (mOnHierarchyChangeListener != null) {
    mOnHierarchyChangeListener.onChildViewRemoved(parent, child);
   }
  }
 }
}

使用:

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • Android RadioGroup多行显示效果 解决单选问题

    导语 如下图所示,这是一个导航选择弹框.进行单项选择,然后会监听回调选择的事件.问题是Android的RadioButton是一般是放在RadioGroup中进行管理的,而RadioGroup又是线性布局,即单行有效,多行无效.如图那种就需要两个RadioGroup来进行合作.那么如果进行合作呢? 分析:RadioGroup多行显示其实就是两个RadioGroup进行切换,使用RadioGroup的clearCheck()方法进行操作. 但是在使用clearCheck()之前,如果RadioGr

  • 详解Android TextView属性ellipsize多行失效的解决思路

    本文介绍了Android TextView属性ellipsize多行失效的解决思路,分享给大家,具体如下: 多余文字显示省略号的常规做法 android:ellipsize="end" //省略号显示在末尾 android:ellipsize="middle" //省略号显示在中间 但是设置android:maxLines="2" 以后,ellipsize的值end有效,middle无效,本方法解决middle无效的问题 /** * 字符串显示到

  • Android中实现多行、水平滚动的分页的Gridview实例源码

    功能要求: (1)比如每页显示2X2,总共2XN,每个item显示图片+文字(点击有链接). 如果单行水平滚动,可以用Horizontalscrollview实现. 如果是多行水平滚动,则结合Gridview(一般是垂直滚动的)和Horizontalscrollview实现. (2)水平滚动翻页,下面有显示当前页的icon. 1.实现自定义的HorizontalScrollView(HorizontalScrollView.java): 因为要翻页时需要传当前页给调用者,所以fling函数中自己

  • android TextView多行文本(超过3行)使用ellipsize属性无效问题的解决方法

    布局文件中的TextView属性 复制代码 代码如下: <TextViewandroid:id="@+id/businesscardsingle_content_abstract"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_marginTop="5dp"android:lineSpacingMu

  • Android UI实现多行文本折叠展开效果

    上文介绍了单行文本水平触摸滑动效果,通过EditText实现TextView单行长文本水平滑动效果. 本文继续介绍了多行文本折叠展开,自定义布局View实现多行文本折叠和展开 1.概述 经常在APP中能看到有引用文章或大段博文的内容,他们的展示样式也有点儿意思,默认是折叠的,当你点击文章之后它会自动展开.再次点击他又会缩回去. 网上有找到部分效果,感觉不是很满意.最后自己尝试用 自定义布局layout 写了个demo.比较简陋,不过可以用了.有这方面需求的朋友可以稍加改造下.如有更好的创意,也不

  • Android自定义View之RadioGroup实现跨多行显示

    本文实例为大家分享了Android RadioGroup跨多行显示的具体代码,供大家参考,具体内容如下 此自定义View源于网络,具体出处不详. import android.content.Context; import android.content.res.TypedArray; import android.util.AttributeSet; import android.view.MotionEvent; import android.view.View; import androi

  • Android 自定义View实现任意布局的RadioGroup效果

    前言 RadioGroup是继承LinearLayout,只支持横向或者竖向两种布局.所以在某些情况,比如多行多列布局,RadioGroup就并不适用 . 本篇文章通过继承RelativeLayout实现自定义RadioGroup,实现RadioButton的任意布局.效果图如下: 代码(RelativeRadioGroup) /** * Author : BlackHao * Time : 2018/10/26 10:46 * Description : 自定义 RadioGroup */ p

  • Android自定义view实现阻尼效果的加载动画

    效果: 需要知识: 1. 二次贝塞尔曲线 2. 动画知识 3. 基础自定义view知识 先来解释下什么叫阻尼运动 阻尼振动是指,由于振动系统受到摩擦和介质阻力或其他能耗而使振幅随时间逐渐衰减的振动,又称减幅振动.衰减振动.[1] 不论是弹簧振子还是单摆由于外界的摩擦和介质阻力总是存在,在振动过程中要不断克服外界阻力做功,消耗能量,振幅就会逐渐减小,经过一段时间,振动就会完全停下来.这种振幅随时间减小的振动称为阻尼振动.因为振幅与振动的能量有关,阻尼振动也就是能量不断减少的振动.阻尼振动是非简谐运

  • Android 自定义View 密码框实例代码

    暴露您view中所有影响可见外观的属性或者行为. •通过XML添加和设置样式 •通过元素的属性来控制其外观和行为,支持和重要事件交流的事件监听器 详细步骤见:Android 自定义View步骤 效果图展示: 支持的样式 可以通过XML定义影响外边和行为的属性如下 边框圆角值,边框颜色,分割线颜色,边框宽度,密码长度,密码大小,密码颜色 <declare-styleable name="PasswordInputView"> <attr name="borde

  • Android自定义View详解

    转载请标明出处:http://blog.csdn.net/lmj623565791/article/details/24252901 很多的Android入门程序猿来说对于Android自定义View,可能都是比较恐惧的,但是这又是高手进阶的必经之路,所有准备在自定义View上面花一些功夫,多写一些文章.先总结下自定义View的步骤: 1.自定义View的属性 2.在View的构造方法中获得我们自定义的属性 [ 3.重写onMesure ] 4.重写onDraw 我把3用[]标出了,所以说3不一

  • Android自定义View中attrs.xml的实例详解

    Android自定义View中attrs.xml的实例详解 我们在自定义View的时候通常需要先完成attrs.xml文件 在values中定义一个attrs.xml 然后添加相关属性 这一篇先详细介绍一下attrs.xml的属性. <?xml version="1.0" encoding="utf-8"?> <resources> //自定义属性名,定义公共属性 <attr name="titleText" for

  • Android自定义View 仿QQ侧滑菜单的实现代码

    先看看QQ的侧滑效果 分析一下 先上原理图(不知道能否表达的清楚 ==) -首先这里使用了 Android 的HorizontalScrollView 水平滑动布局作为容器,当然我们需要继承它自定义一个侧滑视图 - 这个容器里面有一个父布局(一般用LinerLayout,本demo用的是),这个父布局里面有且只有两个子控件(布局),初始状态菜单页的位置在Y轴上存在偏移这样可以就可以形成主页叠在菜单页的上方的视觉效果:然后在滑动的过程程中 逐渐修正偏移,最后菜单页和主页并排排列.原理搞清了实现起来

  • Android自定义View绘制随机生成图片验证码

    本篇文章讲的是Android自定义View之随机生成图片验证码,开发中我们会经常需要随机生成图片验证码,但是这个是其次,主要还是想总结一些自定义View的开发过程以及一些需要注意的地方. 按照惯例先看看效果图: 一.先总结下自定义View的步骤: 1.自定义View的属性 2.在View的构造方法中获得我们自定义的属性 3.重写onMesure 4.重写onDraw 其中onMesure方法不一定要重写,但大部分情况下还是需要重写的 二.View 的几个构造函数 1.public CustomV

  • Android自定义View绘制的方法及过程(二)

    上一篇<Android 自定义View(一) Paint.Rect.Canvas介绍>讲了最基础的如何自定义一个View,以及View用到的一些工具类.下面讲下View绘制的方法及过程 public class MyView extends View { private String TAG = "--------MyView"; private int width, height; public MyView(Context context, AttributeSet a

  • Android自定义View实现等级滑动条的实例

     Android自定义View实现等级滑动条的实例 实现效果图: 思路: 首先绘制直线,然后等分直线绘制点: 绘制点的时候把X值存到集合中. 然后绘制背景图片,以及图片上的数字. 点击事件down的时候,换小图片为大图片.move的时候跟随手指移动. up的时候根据此时的X计算最近的集合中的点,然后自动吸附回去. 1,自定义属性 <?xml version="1.0" encoding="utf-8"?> <resources> <de

随机推荐