需求描述:

实现一个带圆角的imageView,要求自定义view方式实现。

需求分析:

我们可以自定义一个view,继承ImageView,并只需要重写ImageView的onDraw()方法即可。带圆角意味着要把控件的四个顶角做一个裁切。由于不能影响imageview主体的正常绘制, 想到了可以在执行super.onDraw()方法之前进行对画布canvas的裁切。 这样接下来绘制的控件就只会在裁切范围内。从而实现了我们的需求。

代码实现:

实现流程步骤

1、定义好自定义view用到的的属性;

2、自定义view,使之继承ImageView,并在其构造函数中获取自定义属性值;

3、重写ImageView的onDraw()方法, 在执行super.onDraw()之前利用Path创建一个路径对象,然后使用画布沿着path路径裁切;

4、调用super.onDraw()绘制imageview的主体内容

1、定义自定义view属性:

在attrs.xml中声明如下

<resources><declare-styleable name="RoundImageView"><attr name="radius" format="dimension"/><attr name="leftTopRadius" format="dimension"/><attr name="rightTopRadius" format="dimension"/><attr name="leftBottomRadius" format="dimension"/><attr name="rightBottomRadius" format="dimension"/></declare-styleable>...
</resources>

这里有一点需要注意下,控件的尺寸相关属性的类型需要使用dimension,而不是int或float。

2、自定义view获取属性值 & 重写onDraw方法

class RoundImageView: AppCompatImageView {private var rightBottomRadius: Intprivate var leftBottomRadius: Intprivate var rightTopRadius: Intprivate var leftTopRadius: Intprivate var radius: Int =0constructor(context: Context): this(context, null)constructor(context: Context, attributeSet: AttributeSet?): this(context, attributeSet, 0)constructor(context: Context, attributeSet: AttributeSet?, defStyleAttr: Int):super(context, attributeSet, defStyleAttr) {var typeArray = context.obtainStyledAttributes(attributeSet, R.styleable.RoundImageView)val defaultRadius = 0radius = typeArray.getDimensionPixelOffset(R.styleable.RoundImageView_radius, defaultRadius)leftTopRadius = typeArray.getDimensionPixelOffset(R.styleable.RoundImageView_leftTopRadius,defaultRadius)rightTopRadius = typeArray.getDimensionPixelOffset(R.styleable.RoundImageView_rightTopRadius,defaultRadius)leftBottomRadius = typeArray.getDimensionPixelOffset(R.styleable.RoundImageView_leftBottomRadius,defaultRadius)rightBottomRadius = typeArray.getDimensionPixelOffset(R.styleable.RoundImageView_rightBottomRadius,defaultRadius)if (radius != 0) {if (leftTopRadius == 0) {leftTopRadius = radius}if (rightTopRadius == 0) {rightTopRadius = radius;}if (leftBottomRadius == 0) {leftBottomRadius = radius;}if (rightBottomRadius == 0) {rightBottomRadius = radius;}}typeArray.recycle()}override fun onDraw(canvas: Canvas?) {// 保证图片宽高大于圆角宽高, 获取圆角的宽高// 取横着大的长度val maxLeft = Math.max(leftTopRadius, leftBottomRadius)val maxRight = Math.max(rightTopRadius, rightBottomRadius)val minWidth = maxLeft + maxRight// 取竖着大的长度val maxTop = Math.max(leftTopRadius, rightTopRadius)val maxBottom = Math.max(leftBottomRadius, rightBottomRadius)val minHeight = maxTop + maxBottomif (width > minWidth && height > minHeight) {val path = Path()//四个角:右上,右下,左下,左上path.moveTo(leftTopRadius.toFloat(), 0F)path.lineTo((width - rightTopRadius).toFloat() , 0F)path.quadTo(width.toFloat(), 0F, width.toFloat(), rightTopRadius.toFloat())path.lineTo(width.toFloat(), (height - rightBottomRadius).toFloat())path.quadTo(width.toFloat(), height.toFloat(), (width - rightBottomRadius).toFloat(), height.toFloat())path.lineTo(leftBottomRadius.toFloat(), height.toFloat())path.quadTo(0F, height.toFloat(), 0F, (height - leftBottomRadius).toFloat())path.lineTo(0F, leftTopRadius.toFloat())path.quadTo(0F, 0F, leftTopRadius.toFloat(), 0F)canvas!!.clipPath(path)/*val paint = Paint()paint.setColor(Color.BLUE)paint.style = Paint.Style.STROKEpaint.strokeWidth = 2fcanvas!!.drawPath(path, paint)*/}super.onDraw(canvas)}}

1、当声明了radius属性,并且某个方向的radiusX属性没有声明时, 则使用radius的值替代该放下的radiusX;

2、画布裁切需要在super.onDraw(canvas)之前执行;

3、本程序对裁切进行了一些限制(假如不符合你的需求,你可以去掉这些限制并写上你的限制条件)

限制1:自定义view控件的宽度必须大于(view左半边最大半径和view右半边最大半径之和),即

必须满足条件:

宽度 :view的width > (maxLeft + maxRight)

高度 :同理

//左半边的最大半径
val maxLeft = Math.max(leftTopRadius, leftBottomRadius)
//右半边的最大半径
val maxRight = Math.max(rightTopRadius, rightBottomRadius)//maxLeft + maxRight 就是view需要满足的最小宽度,同理height

4、创建一个Path路径对象来描述画布应该沿着什么路径进行裁切。执行canvas.clipPath(),之后在canvas上进行的绘制操作就只会在这部分区域进行绘制了。

这里强调一下绘制圆角使用的是贝塞尔曲线(没接触过的话可以参考下贝塞尔曲线简单介绍)。

3、xml中引用自定义view

<LinearLayoutandroid:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"android:gravity="center"><com.example.helloworld.views.RoundImageViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"app:leftTopRadius="70dp"app:leftBottomRadius="60dp"app:rightTopRadius="25dp"app:rightBottomRadius="60dp"android:src="@drawable/maps"/>
</LinearLayout>

原图:

程序效果:

解释一下:

1、可以看到drawable图片的像素值为419 x 418;

2、xml中RoundImageView的宽高都是设置为wrap_content, 这意味着控件的宽高是根据控件内部装载的内容大小来决定的。在onDraw方法中, 已经测量出了RoundImageView的宽高,即为图片的宽高(系统在onMeasure时已经测量出来尺寸)。在xml中设置的四个方向的半径值满足程序的条件,即view的width > (maxLeft + maxRight)===>419 > (70 + 60)x2,这里要乘以2是因为xml使用的是dp作为长度单位,测试机器的1dp=2px,高度同理。 所以会裁切RoundImageView的四个顶角。

Android 自定义ImageView实现圆角相关推荐

  1. Android 自定义ImageView实现圆角图片

    圆角ImageView 大概就是这个样子的 四个直角改成圆角的 度数可以自定义 自定义ImageView 方法一:BitmapShader方式 首先简单了解下BitmapShader BitmapSh ...

  2. Android自定义ImageView圆角

    圆角的实现方式 在Android项目中经常遇见圆角的图片的展示问题,但是很可惜,Android中的imageView并不是原生就支持圆角的,那么在Android中实现展示圆角图片的方式有几种呢?这里笔 ...

  3. Android 自定义View 圆形圆角图片

    [Android 自定义View 圆形圆角图片] 基于Xfermode 实现 1.概述 在很久以前也写过一个利用Xfermode 实现圆形.圆角图片的(Android 完美实现图片圆角和圆形(对实现进 ...

  4. android背景颜色动态修改,Android自定义TextView带圆角及背景颜色(动态改变圆角背景颜色)...

    最近根据项目需求自定义了一个TextView控件,主要用来做状态的标识,比如一个订单状态有各种,当然了这种设置在Android中可以直接用xml文件来处理,但是对于xml文件太过于麻烦,针对不同的颜色 ...

  5. Android 自定义ImageView加载图片

    自定义imageview功能: 可以实现设置图片显示的时候,依据本身的比例进行图片的缩放 加载图片效果: 使用ImageLoader来加载 图片: 首先将ImageLoader的jar包关联到项目中 ...

  6. android自定义listview实现圆角

    在项目中我们会经常遇到这种圆角效果,因为直角的看起来确实不那么雅观,可能大家会想到用图片实现,试想上中下要分别做三张图片,这样既会是自己的项目增大也会增加内存使用量,所以使用shape来实现不失为一种 ...

  7. android 自定义ImageView控件实现圆形图片-适用于用户头像

    android开发中常常涉及到一种情况,就是将用户上传的图片以圆形样式显示,但是用户上传的图片可以有直角.圆角.正方形等多种不确定样式,这时就用到了自定义ImageView控件,在安卓客户端使接收到的 ...

  8. Android --- 自定义ImageView 实现圆形图片

    自定义ImageView实现圆形图片,主要是在onDraw()方法中实现绘制圆形图片,在onMeasure()中测量圆形的半径并设置View的宽高.效果如下图 代码如下 public class Ci ...

  9. android 自定义ImageView实现图片手势滑动,多点触摸放大缩小效果

    首先呢,还是一贯作风,我们先来看看众多应用中的示例:(这种效果是很常见的,可以说应用的必须品.)                搜狐客户端                               ...

最新文章

  1. python listen_python socket编程中listen和accept的区别
  2. 开课吧python小课值得么-领导想提拔你,从来看的不是努力!
  3. PAT甲级1002 A+B for Polynomials:[C++题解]字符串、多项式加法或高精度加法
  4. 解压与压缩ramdisk.img文件
  5. 继电反馈法自整定_基于继电反馈PID自整定方法在Buck―Boost电路中应用.doc
  6. ELK报错expected block end, but found BlockMappingStart
  7. nodejs missing script: dev_nodejs深入学习系列之v8基础篇
  8. 源码共享,希望一起互相学习
  9. (87)FPGA读文件激励(readmemb)
  10. java用gui如何写退格_emWin(ucGui)的Edit控件退格处理方法 worldsing
  11. Docker 安装(学习笔记一)
  12. jdk7 HashSet和HashMap源码分析
  13. 《乔布斯传.神一样的传奇》读后感
  14. 第一次组装台式机记录
  15. stm32F407的串口6卡死问题
  16. php20以内的勾股数,[求助]编程求100以内的所有勾股数
  17. Android 支付宝支付SDK接入
  18. php: 远程操作浏览器cookie存储入门
  19. 增加firefox的搜索选项
  20. vue+echarts GL3d中国地图

热门文章

  1. 最强服务器电脑的性能数据,服务器:数据中心的“最强大脑”
  2. 听了一场讲座的感想!
  3. 利用ipv6远程桌面,彻底解决校园网掉线问题
  4. Linux创建文件的四种方式
  5. 26岁,月入3万,癌症晚期:熬夜没什么,就是容易死!
  6. java 锐化_Java Opencv 实现锐化
  7. 【App】Anki快捷键
  8. WPF Button添加图片样式
  9. [735]利用UItraISO软碟通制作U盘启动盘安装Ubuntu16.04系统
  10. 五、项目管理五大过程组及十大知识领域