先扯两句

不知道多长时间没有登录发文章了,正好今天不太忙进来看一眼,然后看到好多人都已经开始自己公众号了,看看自己的工作年限也不短了,可是感觉好久没有干正事了,还是老老实实打开文档开始写吧。

正文

随着UI越来越美观,原本直来直去的布局样式越来越不受喜欢,圆角样式,这个最简单的优化方案在越来越多的场合下被应用到。而具体怎么样才能展示出圆角的效果,相比大家都有N多中方案,我这里就列举一些自己常用的方案吧。当然,还有一些第三方的框架支持,这里就不列举了,主要是我个人感觉为了一个简单的效果,集成一个库不太划算,尤其是库中很大一部分功能都用不到的时候。而且第三方的框架贡献者实力不等,有很多都要导入源码进一步优化,分析太麻烦了,一向懒汉自称的我是不可能这么勤快去列举的,大家有兴趣可以自行研究。
样式参考就已自如房型列表的item为例吧:

方案0

首先说明一下,什么叫做方案0,不是因为程序员,计数一定要从0开始的洁癖,单纯是因为这些方案算是比较常用的,大家遇到类似的需求很快就能想到的。这里只是简单介绍一下,给一些新入门的同学看看,在遇到相应的圆角需求的时候,可以最方便的解决问题。
当然,还是同样的,如果一定要找一个第三方框架,一个参数控制去实现也不是不可以,性能各方面我这里也没有去具体评估过,也没办法说一定谁好谁坏。所以对于一切反对意见,我这里的回应都是:“我错了!你说的对!”

1 圆角背景:xml

圆角的背景,可以实现的效果就是上面图中的下半部分

首先我们需要分析这个部分有什么要求:

可以看到有两个地方有要求,分别是:1.白色背景;2.灰色边框。所以对应的xml只需要满足这两点就可以了。

  1. 创建drawable的xml文件
  2. 命名,并将对应的跟元素设置为shape(形状)
  3. 配置属性
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"><!--中间的白色实心背景--><solid android:color="#FFFFFF" /><!--灰色边框,色值和宽度--><strokeandroid:width="0.5dp"android:color="#999999" /><!--圆角角度:左下和右下--><cornersandroid:bottomLeftRadius="5dp"android:bottomRightRadius="5dp" />
</shape>

其中需要注意的是,图中可以看到,需要有圆角的区域只在下半部分,所以这里配置的时候也要只配置下半部,不然图片与背景的交接处就会有相当怪异。

这里可能有人会说,直接绘制一个白色的全圆角背景放到下面,上面盖上一个圆角的图片不就好了吗?你真是一个小机灵鬼,这个方案当然可行。但是性能稍微有点追求的建议了解一些过度绘制,虽然不是说背景上面叠加一张图片就会对性能造成断崖式影响,但是雪崩之下,可没有哪朵雪花是无辜的。
当然,这里为了看得清晰,页面的背景设置成了黑色,圆角也调整到了20dp,正常情况下也会出现问题,但是不会这么明显,能不能发现就看测试团队和UI团队的审查力度了。

2 纯图片Glide

现在用的比较多的,或者是我工作这么多年用的比较多的图片框架就是glide,想当初在刚开始用glide的时候还不支持圆角,需要额外添加一堆配置,还要导入第三方的库,现在好了,没有几行代码,基本属于一键配置了。

Glide.with(this).load(R.drawable.bg_scene).apply(RequestOptions.bitmapTransform(RoundedCorners(dip2px(this, 20f)))).into(findViewById(R.id.test_img))

其中apply中的内容就是圆角的配置,当然,猜也能猜出来,这里只配置了一个角度,显示的时候底部肯定有问题,应该只配置顶部的两个圆角才对,这里给大家找了个链接:Glide 加载部分圆角图片,作为一个懒汉,没有做测试,哪位如果正好赶上有这个需求可以测试一下,我们直接进入下一个原生方案。

3 CardView

UI样式的大趋势,作为Android的幕后大boss google怎么可能不知道呢,所以官方控件里也有这么一个小朋友可以实现这个功能,那就是CardView,直接上代码:

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:app="http://schemas.android.com/apk/res-auto"xmlns:tools="http://schemas.android.com/tools"android:id="@+id/item_tv"android:layout_width="200dp"android:layout_height="wrap_content"android:background="#fefefe"android:padding="15dp"tools:ignore="SpUsage"tools:viewBindingIgnore="true"><androidx.cardview.widget.CardViewandroid:layout_width="match_parent"android:layout_height="wrap_content"app:cardCornerRadius="5dp"><LinearLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content"android:orientation="vertical"><androidx.appcompat.widget.AppCompatImageViewandroid:id="@+id/test_img"android:layout_width="match_parent"android:layout_height="wrap_content"android:adjustViewBounds="true"android:scaleType="centerInside"android:src="@drawable/bg_scene" /><Viewandroid:layout_width="match_parent"android:layout_height="80dp"android:background="20dp" /></LinearLayout></androidx.cardview.widget.CardView>
</FrameLayout>

然后看效果:

可以看到,前面的两个问题,在这里都直接搞定了,背景图也不用设置圆角了,glide也不用设置圆角了,在CardView中添加了app:cardCornerRadius="5dp"后,一切问题都迎刃而解了,是不是特别爽,特别开心!

缺点分析

上面虽然说实现了功能,但是能放到方案0上,就代表还有其他在我个人的能力水平内能看到的更好的方案(具体是不是还是要交给大神们评估),那就先说说上面的这些我所看到的缺点吧。

  1. xml只能对简单的色块等做配置,如果是图片的虽然也可以通过layer-list来完成拼接绘制,但是绘制难度跟在layout的xml中的绘制难度就不是一个量级的(比如位置的相对关系)
  2. glide针对的主要是图片的处理,另外还有一个问题对于加载中的网络图片的支持可以,但是图片加载前的占位图和图片加载后的缺省图支持的就不是很好,一旦图片请求失败,展示个没有圆角的图,测试绝对会来找你的麻烦
  3. CardView看起来可以完美的规避掉上面两种方案的问题,但是可以看到,我们在绘制页面的时候,CardView中需要添加一个子View去绘制其中各个View的相对关系,毕竟CardView的父控件是FrameLayout,又没有重写onLayout方法,所以子View的展示逻辑,可以理解为就是FrameLayout。这样为了实现一个效果就需要多一层View嵌套。且同样,CardView配置圆角的时候,也是四个角同步配置的,如果需要部分配置的时候也是不支持的。

那么我们就进入到为大家准备的其他方案。

方案一:自定义View圆角

这个方案就是通过declare-styleable配置圆角角度,然后在执行onDraw的时候,通过裁剪Carvas实现圆角效果,代码如下:

<declare-styleable name="XXXView"><!-- 通用圆角配置 --><attr format="dimension" name="radius"/><!-- 右上圆角 --><attr format="dimension" name="rightTopRadius"/><!-- 左上圆角 --><attr format="dimension" name="leftTopRadius"/><!-- 右下圆角 --><attr format="dimension" name="rightBottomRadius"/><!-- 左下圆角 --><attr format="dimension" name="leftBottomRadius"/>
</declare-styleable>

自定义View代码

class XXXView @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0
) : AppCompatImageView(context, attrs, defStyleAttr) {private val mPath = Path()private val mPaint = Paint(Paint.ANTI_ALIAS_FLAG)/*** 左上角 圆角大小*/private var leftTopRadius: Float = 0f/*** 右上角 圆角大小*/private var rightTopRadius: Float = 0f/*** 左下角 圆角大小*/private var leftBottomRadius: Float = 0f/*** 右下角 圆角大小*/private var rightBottomRadius: Float = 0f/*** 全部圆角*/private var radius: Float = 0fprivate val clipRectF = RectF()init {val obtainStyledAttributes = getContext().obtainStyledAttributes(attrs, R.styleable.XXXView)radius= obtainStyledAttributes.getDimension(R.styleable.XXXView_radius, radius)if (radius != 0f) {//不知道为啥 不能 leftTopRadius=rightTopRadius=rightBottomRadius=leftBottomRadius = radiusleftTopRadius = radiusrightTopRadius = radiusrightBottomRadius = radiusleftBottomRadius = radius} else {leftTopRadius = obtainStyledAttributes.getDimension(R.styleable.XXXView_leftTopRadius, leftTopRadius)rightTopRadius = obtainStyledAttributes.getDimension(R.styleable.XXXView_rightTopRadius, rightTopRadius)leftBottomRadius = obtainStyledAttributes.getDimension(R.styleable.XXXView_leftBottomRadius, leftBottomRadius)rightBottomRadius = obtainStyledAttributes.getDimension(R.styleable.XXXView_rightBottomRadius, rightBottomRadius)}obtainStyledAttributes.recycle()}override fun onDraw(canvas: Canvas?) {//1.//dx,dy 成对出现,控制上右下左,四个位置圆角val array = floatArrayOf(leftTopRadius, leftTopRadius, rightTopRadius, rightTopRadius, rightBottomRadius, rightBottomRadius, leftBottomRadius, leftBottomRadius);clipRectF.set(0f, 0f, width.toFloat(), height.toFloat())mPath.addRoundRect(clipRectF, array, Path.Direction.CW)//2.//3.canvas?.clipPath(mPath)//4.super.onDraw(canvas)}
}

自定义ViewGroup圆角(onDraw替换为dispatchDraw)

override fun dispatchDraw(canvas: Canvas) {//1.//dx,dy 成对出现,控制上右下左,四个位置圆角val array = floatArrayOf(leftTopRadius, leftTopRadius, rightTopRadius, rightTopRadius, rightBottomRadius, rightBottomRadius, leftBottomRadius, leftBottomRadius);mPath.addRoundRect(RectF(0f, 0f, width.toFloat(), height.toFloat()), array, Path.Direction.CW)//2.//3.canvas.clipPath(mPath)//4.super.dispatchDraw(canvas)}

注:
1. canvas裁剪需要放置在super之前
2. 频繁刷新UI,会导致频繁在onDraw执行canvas裁剪,出现黑色闪屏

方案二:ViewOutlineProvider

其实我较多的时候使用的还是方案一,直到一次的需求需要频繁刷新UI,才发现了黑色闪屏的问题,查找其他方案的时候,才知道的ViewOutlineProvider,参考链接:Material Design :ViewOutlineProvider

demo代码如下:

<declare-styleable name="XXXView"><!-- 圆角角度 --><attr format="dimension" name="radius"/>
</declare-styleable>

圆角View

class XXXView @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null
) : FrameLayout(context, attrs) {private var radius = 0finit {val obtainStyledAttributes =getContext().obtainStyledAttributes(attrs, R.styleable.XXXView)radius =obtainStyledAttributes.getDimension(R.styleable.XXXView_radius, radius)obtainStyledAttributes.recycle()clipToOutline = trueoutlineProvider = object : ViewOutlineProvider() {override fun getOutline(view: View?, outline: Outline?) {view?.let {outline?.setRoundRect(0 + paddingLeft,0 + paddingTop,it.width - paddingRight,it.height - paddingBottom,radius)}}}}// 业务代码逻辑// ...
}

布局:

<com.example.demo.widget.radius.RadiusViewandroid:layout_width="match_parent"android:layout_height="wrap_content"android:layout_margin="20dp"android:padding="15dp"app:radius="50dp"><LinearLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content"android:orientation="vertical"><!--图片自己网上随便找一张就可以--><androidx.appcompat.widget.AppCompatImageViewandroid:id="@+id/test_img"android:layout_width="match_parent"android:layout_height="wrap_content"android:adjustViewBounds="true"android:scaleType="centerInside"android:src="@drawable/bg_scene" /><Viewandroid:layout_width="match_parent"android:layout_height="80dp"android:background="@android:color/holo_purple" /></LinearLayout>
</com.example.demo.widget.radius.RadiusView>

效果如图:

注:
1. 代码中圆角的位置是会收到padding影响的,如果不想收到影响,去掉setRoundRect中的四个padding参数即可,具体依据具体需求调整
2. 由于ViewOutlineProvider api的限制,暂时能配置的都是四个角统一角度,如果想要分别配置,该方案不适用

方案三 切图覆盖

可以看到,上面的所有方案在特定的情况下都会有所限制,所以在相应的场景下,产品经历还是要求我们实现对应的圆角效果,我们又不能让他闭嘴的时候,只能再想其他方案。
这里的建议就是切图覆盖,也就是让UI切一个颜色与背景色相同的圆角边框,覆盖到需要圆角展示的View上方,假装实现了一个圆角的效果。

圆角图片:

绘制布局:

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"android:id="@+id/item_tv"android:layout_width="200dp"android:layout_height="200dp"tools:viewBindingIgnore="true"><androidx.appcompat.widget.AppCompatImageViewandroid:id="@+id/test_img"android:layout_width="match_parent"android:layout_height="match_parent"android:adjustViewBounds="true"android:scaleType="centerCrop"android:src="@drawable/bg_scene" /><Viewandroid:layout_width="match_parent"android:layout_height="match_parent"android:background="@drawable/mask" />
</FrameLayout>

圆角效果:

优点:基本可以兼容产品的所有圆角样式需求
缺点:需要多绘制一层View,不够优雅

总结

上面列举的就是我现阶段想到的所有圆角效果的实现方案,在工作场景中,其实大多数情况也都够用了,当然,大家如果有其他的方案,也欢迎分享一下,大家共同进步。
这里也说过了,是没有列举第三方的方案的,都是一些原生的实现方案,虽然说用第三方的方案很爽,但是大多数情况下,还是建议自己学习一下具体的实现,较少一些不必要的引用。
另外,关于最后一条要说几句,其实这个方案是一次看网课有学生提问,老师提到的方案,结果是学生感觉这种方案是在忽悠他,最终不欢而散。其实说实话,这个方案,我个人也不是那么建议使用的,只是有很多情况我们并没有办法很快的实现产品或者UI想要的一些效果,不得不使用一些折中的方案,也算是工作中的一种妥协和无奈。
这里不是建议大家一点不用,但是最好应付过关后,在空闲时间思考一下,还有没有其他好的解决方案丰富自己。
好了,祝大家新年快乐,开年第一天的摸鱼……还有什么可以做的呢,容我想想,哈哈哈!

Android知识点-圆角相关推荐

  1. Android 圆形/圆角图片的方法

    Android 圆形/圆角图片的方法 眼下网上有非常多圆角图片的实例,Github上也有一些成熟的项目.之前做项目,为了稳定高效都是选用Github上的项目直接用.但这样的结束也是Android开发必 ...

  2. Android的圆角按钮和按钮颜色

    1. android 设置圆角按钮后,按下按钮后,还能改变按钮的颜色 <span style="font-size:18px;"><?xml version=&q ...

  3. android倒角按钮,Android实现圆角Button按钮

    本文实例讲述了Android开发圆角Button按钮实现过程,分享给大家供大家参考,具体内容如下 需求及效果图: 实现思路: 1.shape实现圆角 在drawable新建两个xml 文件, 这两个 ...

  4. android 简单实现圆角,Android 实现圆角图片的简单实例

    Android 实现圆角图片的简单实例 实现效果图: 本来想在网上找个圆角的例子看一看,不尽人意啊,基本都是官方的Demo的那张原理图,稍后会贴出.于是自己自定义了个View,实现图片的圆角以及圆形效 ...

  5. Android知识点汇总以及常见面试题

    Android知识点汇总以及常见面试题 1. 链表和数组的区别 2. List Hash 数组的区别 3. 用过哪些三方SDK 4. Android四大组件 5. 堆和栈的区别 6. Activity ...

  6. Android知识点 200 —— framework/base/cmds 常见的am命令,input,pm命令

    文章原文:http://www.360doc.com/content/11/0510/00/4154133_115595135.shtml 返回知识列表:Android知识点list /framewo ...

  7. Android 知识点——Method put in org.json.JSONObject not mocked

    先扯两句 老头子我没有什么别的优点,就剩下为了作死而作死了.总想玩的新鲜的东西,也就导致了新的问题,这篇存在的原因就是作死的报应啊! 下面给大家展示个神器,叫Android知识点--目录,好了,闲言少 ...

  8. android imageview 锯齿,[置顶] android 自定义圆角ImageView以及锯齿的处理

    看到很多人开发过程中要使用圆角图片时,解决方法有: 1.重新绘制一张图片 2.通过布局来配置 3.通过重写View来实现 其中1,2在这里就不讲了,重点讲讲方法三的实现. 实现一:通过截取画布一个圆形 ...

  9. android组件圆角,Android实现圆角控件

    Android实现圆角控件 在Android开发过程中,控件的使用是最常见.最基本的.但是我们都知道,在Android中的控件都是矩形的,而在实际项目中,我们的UI设计师经常会使用一些圆角的控件.那么 ...

最新文章

  1. [原] XAF How to Edit multiple objects in a ListViewAndDetailView
  2. 目的港无人提货的法律风险及风险承担
  3. 【转】iphone - ios app maximum memory budget
  4. 了解如何使用Vue.js CLI
  5. python中urframe函数的用法_python类中的内置函数
  6. 4.微服务设计 --- 集成
  7. 谈谈joomla1.5中个人遇见的古怪问题
  8. ICMP数据包-实战分析
  9. IPtable 工作原理
  10. 基于Python的BOSS直聘Python岗位数据分析
  11. c语言 sin1怎么写,c语言sin30怎么写
  12. 【bzoj4484】【jsoi2015】最小表示
  13. 爬取天眼查 的python 代码
  14. 《数据结构与抽象:Java语言描述(原书第4版)》一P.2.2 前置条件和后置条件...
  15. 跨模态行人重识别:RGB-Infrared Cross-Modality Person Re-Identification(2017 ICCV)
  16. mysql 字段包含横杠_mysql数据库创建删除带横杠的数据库名
  17. 试简述smtp通信的三个阶段的过程_通信原理简答题汇总
  18. 基于FTP网盘系统设计
  19. mysql中工资表,MySQL操作工资表,获取累计工资和月平均工资
  20. 怎样卸载deepin系统_Deepin深度系统系统卸载教程 - 安装卸载 - Deepin深度系统用户手册...

热门文章

  1. 系统架构设计师(截图+做题思路+目录)
  2. 迅为-IMX6UL开发板丨双网口丨双CAN总线丨4路USB HOST丨2路串口、6路插座引出,共8路串口丨1路RGB信号丨2路LVDS信号
  3. word 2016图表插入题注及交叉引用
  4. 制作Retropie系统树莓派掌机(三)
  5. 金蝶K3 ACTIVEX部件不能创建对象 金蝶K3一直装载进不去
  6. 共模电感 | 磁芯选型
  7. QML基础:锚anchors
  8. windows10 基于Spin的模型检测
  9. python 图片处理模块_(python)图片处理Pillow模块的使用
  10. JAVA 1058:求一元二次方程