一个圆形的布局设计,先看效果图

一般我们自定义UI,当然是先写一个类继承View(ViewGroup),然后定义几个我们可以自定义的属性,在此处笔者定义了以下这些属性

var angle: Float = 0fset (value) {field = value % 360frequestLayout()}/***  第一个控件所在的位置,为0时表示为顺时针90度,为正数时则从顺时针90度开始逆时针反转,否则为顺时针,*/var angleOffset: Float = 0fset (value) {field = value % 360frequestLayout()}/*** 圆的半径*/var radius = FITS_LARGEST_CHILDset(value) {field = valuerequestLayout()}/*** 该布局是顺时针还是逆时针。*/var direction = COUNTER_CLOCKWISEset(value) {field = Math.signum(value.toFloat()).toInt()requestLayout()}/*** 是否有中心布局*/val hasCenterView: Booleanget() = centerView != null && centerView?.visibility != GONE

然后在xml文件中定义属性

<declare-styleable name="CircleLayout"><attr name="cl_centerView" format="reference" /><attr name="cl_angle" format="float" /><attr name="cl_angleOffset" format="float" /><attr name="cl_radius" format="dimension"><enum name="fitsSmallestChild" value="-1" /><enum name="fitsLargestChild" value="-2" /></attr><attr name="cl_direction"><enum name="clockwise" value="-1" /><enum name="counterClockwise" value="1" /></attr>
</declare-styleable>

使用时,我们定义好具体的值

<com.zhangjun.circlelayout.CircleLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:cl="http://schemas.android.com/apk/res-auto"android:layout_width="match_parent"android:layout_height="match_parent"cl:cl_angleOffset="180"cl:cl_angle="0"cl:cl_direction="clockwise">
</com.zhangjun.circlelayout.CircleLayout>

然后我们就可以根据定义的这些属性来布置视图了,我们需要重写ViewGroup的onMeasure和onLayout方法,在此我们重点关注以下onLayout方法

public override fun onLayout(changed: Boolean, l: Int, t: Int, r: Int, b: Int) {val displayAreaLeft = left + paddingLeftval displayAreaTop = top + paddingTopval displayAreaRight = right - paddingRightval displayAreaBottom = bottom - paddingBottomval displayAreaWidth = displayAreaRight - displayAreaLeftval displayAreaHeight = displayAreaBottom - displayAreaTopval centerX = paddingLeft + displayAreaWidth / 2//计算圆心的X坐标val centerY = paddingRight + displayAreaHeight / 2//计算圆心的Y坐标val outerRadius = Math.min(displayAreaWidth, displayAreaHeight) / 2//计算半径centerView?.layoutFromCenter(centerX, centerY)//若有中心视图,则摆放到中心var minChildRadius = outerRadiusvar maxChildRadius = 0childrenToLayout.clear()for (i in 0..childCount - 1) {val child = getChildAt(i)if ((hasCenterView && child.id == centerViewId) || child.visibility == GONE) {continue}childrenToLayout.add(child)maxChildRadius = Math.max(maxChildRadius, child.radius)minChildRadius = Math.min(minChildRadius, child.radius)}//控件之间的角度距离,参考angel属性的备注。val angleIncrement = if (angle != 0f) angle else getEqualAngle(childrenToLayout.size)val layoutRadius = getLayoutRadius(outerRadius, maxChildRadius, minChildRadius)//摆放子视图layoutChildrenAtAngle(centerX, centerY, angleIncrement, angleOffset, layoutRadius, childrenToLayout)}

onLayout方法主要计算了ViewGroup所占的范围,圆心半径等,其中最关键的一步是添加摆放子视图,摆放子视图的代码如下所示:

private fun layoutChildrenAtAngle(cx: Int, cy: Int, angleIncrement: Float, angleOffset: Float, radius: Int, childrenToLayout: List<View>) {val angleIncrementRad = Math.toRadians(angleIncrement.toDouble())var currentAngleRad = Math.toRadians(angleOffset.toDouble())for (i in 0..childrenToLayout.size - 1) {val child = childrenToLayout[i]val childCenterX = polarToX(radius.toDouble(), currentAngleRad)//计算子视图相对圆心的X坐标,val childCenterY = polarToY(radius.toDouble(), currentAngleRad)//计算子视图相对圆心的Y坐标child.layoutFromCenter((cx + childCenterX).toInt(), (cy - childCenterY).toInt())currentAngleRad += angleIncrementRad * direction}}

到这里我们的工作基本上就算是完成了,是不是非常简单呢。

最后,附上源码地址 :源码

Android圆形布局相关推荐

  1. android 一分钟掌握圆形布局原理--圆形菜单控件 so easy

    前言:首先看看我们的两个demo效果,一个类似支付宝网格属性图,一个类似建行圆形菜单. 这两个效果,第一个涉及自定义view,第二个涉及ViewGroup.如果对于自定义view有一点了解实现起来都不 ...

  2. Android圆形头像图Circle ImageView

    <Android圆形头像图Circle ImageView> 需要处理的原始图(pic): 使用CircleImageView处理后的图(作为头像): 现在很多的应用都有设置头像的功能,如 ...

  3. Android 圆形图片 CircleImageView(Xfermode方式)

    Android中实现圆形图片,总的说来有2种方法. Xfermode方式,就是本文要讲的实现方式. BitmapShader(着色器)和Matrix(矩阵)方式 第二种实现方式的代表作,就是Henni ...

  4. 仿微信、短信、QQ等消息数目右上角红色小圆球气泡显示(基于Android XML布局文件实现)

    效果图如下: 仿微信.短信.来电未接数目.QQ等消息数目右上角红色小圆球气泡显示(基于Android XML布局文件实现).这种实现方式主要有两种途径:(1)重写View的onDraw().(2)写布 ...

  5. android如何看百分比版本,【JAVA】Android百分比布局

    开发我人生第一个app的时候,我在想有没有这么一种布局能适应任何手机的分辨率,今天让我们一起来看看Android 百分比布局PercentRelativeLayout. 使用这种布局首先我们要在gra ...

  6. Android开发——布局性能优化的一些技巧(一)

    0. 前言 上一篇我们分析了为什么LinearLayout会比RelativeLayout性能更高,意义在于分析了这两种布局的实现源码,算是对一个小结论的证明过程,但是对布局性能的优化效果,对这两种布 ...

  7. 浅谈Android五大布局——LinearLayout、FrameLayout和AbsoulteLa

    为什么80%的码农都做不了架构师?>>>    Android的界面是有布局和组件协同完成的,布局好比是建筑里的框架,而组件则相当于建筑里的砖瓦.组件按照布局的要求依次排列,就组成了 ...

  8. android源代码居中字体,Android (布局优化) TextView实现drawable图标大小 位置与第一行文本居中...

    先看大众点评的购买须知 大众.png 如上图,需求在每条提示语句前加一个小圆点,我刚看到需求就想到用 android:drawableLeft 来做,可做完发现:当TextView内容为单行的时候是没 ...

  9. android圆形菜单

    实习第三天开发在android圆形菜单 知识参考:http://www.cnblogs.com/zwl12549/archive/2011/04/13/2015366.html和http://www. ...

最新文章

  1. 使用C#实现网站用户登录 (转)
  2. HTTPS安全超文本传输协议
  3. 【渝粤教育】广东开放大学 javaweb 动态网站开发技术 形成性考核 (53)
  4. 二进制文件转成文本保存,并可以读回
  5. Linux 正在吞噬 Windows 和 Chrome OS!
  6. qDebug用法详解
  7. 邮箱总是被垃圾邮件轰炸?来试试这个临时邮箱生成器吧!
  8. Linux局域网多人聊天软件
  9. 程序没问题但是报错Could_not_autowired
  10. 两个分数相加(结果最简)
  11. 端口碰撞技术让开放端口更安全
  12. 008 计算某一日是这一年的第几天
  13. matlab画图双坐标轴和多坐标轴代码
  14. (C语言)实现strcpy
  15. 云原生是什么?细数云原生的5大特征
  16. (最简单)Java 格式化数字每3位加逗号分隔(自己封装好的工具类,直接可用)
  17. 88是python语言的整数类型_少儿Python编程_第三讲:常量变量和数据类型
  18. pick定理及其证明
  19. 倪老师计算机,北京交通大学计算机与信息技术学院导师教师师资介绍简介-倪蓉蓉...
  20. java + typeahead 使用

热门文章

  1. 即时通讯技术 好友列表实现
  2. 在哪里查看苹果/Mac电脑的硬件配置情况?
  3. 制作菜单栏、选择题、搓组合键、小僵尸-unity3D游戏开发入门
  4. 拉结尔6月21日服务器维护,拉结尔6.20开服 国创暗黑刷新巅峰
  5. Spring配置文件报错问题
  6. arcgis gp 选择图层_【干货】ArcGIS的一些常用解决方法
  7. 八进制数字字符转化为十进制详解
  8. 数据库 索引类型及其区别
  9. 数据库字段类型、JDBC类型、Java类型映射关系
  10. 关于文字向上滚动效果