Android:记录一次自定义View的不同实现方式

开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 17 天,点击查看活动详情

做过开发的应该都知道自定义View,它是Android开发进阶的必经之路。为什么要自定义View呢?因为在实际开发过程中,项目中需要的视图效果使用原生控件例如ImageView、TextView、Button等是无法满足的,这就有了自定义View,实际就是继承View或者ViewGroup,对其加入相关内容以满足需求。

接下来就之前项目中遇到的一个效果展开说明:

1675996460465.jpg

上图可以发现,没有原生控件能实现该效果,看到的第一思路就是需要自定义View。大概分析思路如下:

  • 继承View,绘制一个半圆和一个矩形再进行求和
  • 根据UI图尺寸计算各线条坐标完成内部线条绘制
  • 在onTouchEvent方法中拦截第一步图形以外的点击事件,判断每个区域内的点击事件并做个标识用于区分

可以看得出来,前两步都比较简单,最重要的就是计算点击位置的判断。不过这个图还好,算是一个相对正常一点的图形组成,那么对于第三步的计算来说也不是很难,无外乎就是判断点击位置是否在半圆内,这里有个判断公式:

/**
 * 计算距离 勾股定理计算圆心到圆上距离
 */
private fun getDistanceFromTwoSpot(x: Float, y: Float): Float {
    val mx = mWith / 2 - x//相对原点x
    val my = radius - y//相对原点y
    return sqrt(mx * mx + my * my)
}

// 距离中心点之间的直线距离
val distance = getDistanceFromTwoSpot(event.x, event.y)
//在圆内
if(distance <= radius){
   ......
}

通过勾股定理算出点击位置的坐标点和圆心左边点的距离是否小于等于圆的半径即可。内部的其他区域再根据点击位置的X和Y坐标做并集判断基本就实现了该功能。

转念一想,如果最外层是被不规则图形包裹又该如何实现呢,点击事件拦截又该怎么做?

的确,如果外层是不规则图形,那自定义View使用画笔画轮廓的时候几乎不可能完成。突然有一天脑洞大开,我们可不可以让UI将外部轮廓切出来,我们再自定义ViewGroup的时候将其填充进去。没错,这次不再继承View,这里继承自LinearLayout,重写dispatchDraw方法将轮廓图画入,其他的子视图就如同被包裹在LinearLayout内,但这么做就无法精确的拦截轮廓外的点击事件,这得取决于不规则图形的形状。

好了,以上便是这次分享的全部内容,希望对大家有所帮助。

开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 17 天,点击查看活动详情