一、项目概况

我们都知道RadioGroup可以实现选择框,但它有一个局限性,由于它是继承自LinearLayout的,所以只能有一个方向,横向或者纵向;但有时候仅一行的RadioGroup并不能满足实际的需求,比如在一行的宽度下显示不完所有的选项,设计上又不允许左右滑动,这时候RadioGroup就不能满足这样的功能设计了;基于此,我写了这个MultiLineRadioGroup并且开源出来;

1、程序界面效果图

2、功能接口

在Api开发上,能够用到的功能及我能想到的,基本都已经添加完毕;具体如下:

child选项添加,删除

child选项选中,取消选中

child对齐方式(左|中|右)

child行间距,左右间距

设置选择模式(单选|多选)

获取已选选项

child选择状态的监听回调查

3、Demo链接地址

二、项目分析

1、基于上面的功能设计,为了设计方便,添加了一些自定义属性;

上面的几个自定义属性分别表示

child水平间距

child上下间距

child对应的layout布局文件(后面会讲到,此属性必须配置)

初始元素个数

初始元素值列表

选择模式(单选|多选)

child对齐方式

2、在layout中使用MultiLineRadioGroup

(1)、定义一个包含MultiLineRadioGroup的xml文件

android:id="@+id/content"

android:layout_width="match_parent"

android:layout_height="wrap_content"

app:child_layout="@layout/child"

app:child_margin_horizontal="6.0dip"

app:child_margin_vertical="2.0dip"

app:child_values="@array/childvalues"

app:single_choice="true" >

(2)、定义一个根节点为CheckBox的layout文件,并把该文件id设置到MultiLineRadioGroup的child_layout属性中(注:该属性必须设置)

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:background="@drawable/bg"

android:button="@null"

android:padding="8.0dip"

android:textColor="@color/text_color" >

在MultiLineRadiaGroup中,它的子child元素为CheckBox,所以,必须指定一个要布局为CheckBox的child_layout,这个CheckBox可以根据你的需求设置它的不同状态下的样式;

3、MultiLineRadioGroup 核心方法分析

(1)、onMeasure

@Override

protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

super.onMeasure(widthMeasureSpec, heightMeasureSpec);

childCount = getChildCount();

int flagX = 0, flagY = 0, sheight = 0;

if (childCount > 0) {

for (int i = 0; i < childCount; i++) {

View v = getChildAt(i);

measureChild(v, widthMeasureSpec, heightMeasureSpec);

int w = v.getMeasuredWidth() + childMarginHorizontal * 2

+ flagX + getPaddingLeft() + getPaddingRight();

if (w > getMeasuredWidth()) {

flagY++;

flagX = 0;

}

sheight = v.getMeasuredHeight();

flagX += v.getMeasuredWidth() + childMarginHorizontal * 2;

}

rowNumber = flagY;

}

int height = (flagY + 1) * (sheight + childMarginVertical)

+ childMarginVertical + getPaddingBottom() + getPaddingTop();

setMeasuredDimension(getMeasuredWidth(), height);

}

遍历所有的child,并且调用measureChild来对child进行宽高的测量,再通过对宽度的累加与getWidth的值进行比较来判断是否需要换行,并且对需要用到的行数进行记录;

(2)、onLayout

@Override

protected void onLayout(boolean changed, int l, int t, int r, int b) {

if (!changed && !forceLayout) {

Log.d("tag", "onLayout:unChanged");

return;

}

childCount = getChildCount();

int[] sX = new int[rowNumber + 1];

if (childCount > 0) {

if (gravity != LEFT) {

for (int i = 0; i < childCount; i++) {

View v = getChildAt(i);

int w = v.getMeasuredWidth() + childMarginHorizontal * 2

+ mX + getPaddingLeft() + getPaddingRight();

if (w > getWidth()) {

if (gravity == CENTER) {

sX[mY] = (getWidth() - mX) / 2;

} else { // right

sX[mY] = (getWidth() - mX);

}

mY++;

mX = 0;

}

mX += v.getMeasuredWidth() + childMarginHorizontal * 2;

if (i == childCount - 1) {

if (gravity == CENTER) {

sX[mY] = (getWidth() - mX) / 2;

} else { // right

sX[mY] = (getWidth() - mX);

}

}

}

mX = mY = 0;

}

for (int i = 0; i < childCount; i++) {

View v = getChildAt(i);

int w = v.getMeasuredWidth() + childMarginHorizontal * 2 + mX

+ getPaddingLeft() + getPaddingRight();

if (w > getWidth()) {

mY++;

mX = 0;

}

int startX = mX + childMarginHorizontal + getPaddingLeft()

+ sX[mY];

int startY = mY * v.getMeasuredHeight() + (mY + 1)

* childMarginVertical;

v.layout(startX, startY, startX + v.getMeasuredWidth(), startY

+ v.getMeasuredHeight());

mX += v.getMeasuredWidth() + childMarginHorizontal * 2;

}

}

mX = mY = 0;

forceLayout = false;

}

和onMeasure一样,onLayout方法也需要对child进行遍历,不过,在这里的遍历就不是进行测量了,而是对child进行摆放,摆放的时候就需要用到onMeasure方法里面所测量出的子元素的宽高等属性;

遍历可能会遍历两次,如果child对齐方式是非Left的情况下,第一次遍历计算出每行的空隙,然后根据对齐方式算出每行的第一个child的偏移left的距离,第二次遍历的时候,再根据之前算出的偏移距离对child进行layout;

(3)、其它方法

append(String str) 附加一个child;

insert(int position, String str) 往指定位置插入child;

getCheckedValues()|getCheckedItems() 获取选中项;

remove(int position) 删除指定位置的child;

setItemChecked(int position) 选中指定位置的child;

setGravigy(int gravity) 设置child对齐方式;

这些方法都是根据常用或者可能用到的方法来进行实现的,比较简单,就不再贴出代码,上面的Demo链接中都有;

Over!

radiogroup多选_Android 自定义View实现多行RadioGroup (MultiLineRadioGroup)相关推荐

  1. 安卓中自定义view控件代替radiogroup实现颜色渐变效果的写法

    利用自定义控件代替radiogroup,同时实现在使用viewpager进行翻页的时候,实现颜色渐变的效果. 一: 首先创建一个自定义view类继承自View类,所有的控件均用canvas绘制出来(包 ...

  2. android canvas绘制圆角_Android自定义View撸一个渐变的温度指示器(TmepView)

    秦子帅明确目标,每天进步一点点..... 作者 |  andy 地址 |  blog.csdn.net/Andy_l1/article/details/82910061 1.概述 自定义View对需要 ...

  3. android绘制心形_Android自定义View系列(一)——打造一个爱心进度条

    写作原因:Android进阶过程中有一个绕不开的话题--自定义View.这一块是安卓程序员更好地实现功能自主化必须迈出的一步.下面这个系列博主将通过实现几个例子来认识安卓自定义View的方法.从自定义 ...

  4. android 图片圆角 遮罩_Android 自定义View练手Demo(一)实现圆角遮罩效果

    Android 自定义View系列文章 Android自定义View实现圆角遮罩效果 一图胜千言,有一个遮罩就会凸显出重点区域 1-1.jpg 本文通过两种方式来实现这种效果,来达到自定义View练手 ...

  5. android java 圆角_Android自定义View实现带4圆角或者2圆角的效果

    1 问题 实现任意view经过自定义带4圆角或者2圆角的效果 2 原理 1) 实现view 4圆角 我们只需要把左边的图嵌入到右边里面去,最终显示左边的图就行. 2) 实现view上2圆角 我们只需要 ...

  6. android app自动更新界面_Android自定义view之模仿登录界面文本输入框(华为云APP)...

    好久不见!!!!!,最近终于挤出时间来更新文章了,废话不多说,直接开始. 效果图如下: 01 分析 1.组合多个控件完成此输入框静态效果 2.hint值上浮下潜动画 3.一些功能 02 步骤 01 自 ...

  7. android 清空canvas部分内容_Android自定义View实现圆形头像效果

    在我们的APP中通常会遇到,展示圆形头像的需求,一般通过Glide就能实现,但是让我们做一个圆形头像,如果让我们自定义实现这种效果,该怎样做呢? 好,接下来本文通过三种方式来实现这种效果! 注意:这是 ...

  8. java 手写签名_Android 自定义View手写签名并保存图片

    GIF压缩有问题,运行很顺滑!!! 1.自定义View--支持设置画笔颜色,画笔宽度,画板颜色,清除画板,检查是否有签名,保存画板图片(复制粘贴可直接使用) /*** Created by YyyyQ ...

  9. android刷新时的圆形动画_Android自定义view渐变圆形动画

    本文实例为大家分享了Android自定义view渐变圆形动画的具体代码,供大家参考,具体内容如下 直接上效果图 自定义属性 attrs.xml文件 创建一个类 ProgressRing继承自 view ...

最新文章

  1. php mvc实例下载,php实现简单的MVC框架实例
  2. python 进度条程序_Python:显示程序运行进度条
  3. oracle 数据库讲解,oracle数据库基本讲解(菜鸟篇)
  4. VTK:图像索贝尔Sobel用法实战
  5. Flurry调查报告:图片和视频应用增长速度最快
  6. 为什么vacuum后表还是继续膨胀?
  7. C#:生成哈希字符串
  8. python语法与java语法的区别_Python语言与java语法的异同之处
  9. Win虚拟机查询不到自己的IP地址
  10. 上海工程技术大学c语言商店存货管理系统,商店存货管理系统课程设计.doc
  11. C1. Skyscrapers (从easy到hard)
  12. unity2D笔记-控制人物相关
  13. 清新漂亮简约好看的个人博客网站模板
  14. Photoshop抠图大决战
  15. 关于contiki中的Ctimer和Etimer
  16. 学习coreldraw
  17. Linux刻录光盘win10认不到,win10系统刻录光盘光驱无法识别光盘的具体方法
  18. pandas 处理缺失值[dropna、drop、fillna]
  19. 揭秘POS机套现江湖:代理商层层抽佣,支付机构“默许”?
  20. 五杆桁架matlab有限元分析,桁架结构及有限元分析matlab

热门文章

  1. Ubuntu深度学习环境配置一箩筐
  2. Qt实战案例(42)——利用Qt实现自定义标题栏功能(自定义最大化、最小化、关闭等功能)
  3. 计算机取整函数用法,【Excel】数值取整的n种方法
  4. golang 获取文件修改时间
  5. 手机直播开发杂谈之:直播原生源码+APP+直播系统推流SDK(Android)
  6. Spring实现自动装配(spring注解详解)和手动注入比较
  7. Love Love Love
  8. 几款语音转文字神器,玩转录音转文字,工作学习效率提升300%
  9. Windows 11 跳过联网激活
  10. 360手机进 android什么,关于安卓手机双清,你知道多少?