Material Components是Google官方对Material Deign的最佳实践,这个库试图在不同的Android版本中统一Material Design UI组件的外观和使用代码,当然也在不同的平台上统一这些组件(有针对iOS、web和Flutter的库的版本)。Material Components库还实现了新的Material Design规范中引入的功能。

官方的文档对Material Components有着非常详细的讲解,地址如下所示。

https://github.com/material-components/material-components-android/blob/master/docs/getting-started.md

这次要讲的就是Material Components中对于Shape的处理。

Shape

MaterialShapeDrawable类提供了非常有用的工具集,可以为我们的应用程序实现非常酷的效果。MaterialShapeDrawable类让我们可以通过指定最终形状的边缘和角落的样子来定义形状。这些基本的形状定义可以另外使用插值浮动属性来控制,以允许角和边缘的动画。

为了创建自定义的MaterialShapeDrawable,可以使用ShapeAppearanceModel构造函数。ShapeAppearanceModel使用EdgeTreatment和CornerTreatment两个类来存储形状的每个Edge和Corner的信息(总是有4个Edge和4个Corner,尽管你可以为它们定义几乎任何形状)。你可以为每个Edge和Corner设置不同的处理方式,也可以通过一次调用为所有Edge和Corner设置相同的处理方式。

在ShapePathModel中,也有一些预定义的现成的Edge和Corner处理,它们已经实现了Material Design规范中介绍的大部分形状效果。目前已经有了圆角处理(float radius)、切角处理(float size)或三角边缘处理(float size, boolean inside),它们都能像你期望的那样完美地工作。

关于Shape的处理,官方有详细的文档,地址如下。

https://github.com/material-components/material-components-android/blob/master/docs/theming/Shape.md

统观Material Design,Google设计的Material Components不仅仅是实现了Android的开发规范,实际上Flutter、Web,甚至是iOS,都统一了开发范式,所以了解过Material Components的开发者会发现不论是Android还是Flutter,它们上面都有着类似的影子,大家可以看看https://material.io/develop/android的文档。

最简单的使用

通过ShapeAppearanceModel的Builder函数可以很方便的控制边角的Shape,代码如下所示。

val shapePathModel = ShapeAppearanceModel.builder().setAllCorners(RoundedCornerTreatment()).setAllCornerSizes(10.dp()).build()
val backgroundDrawable = MaterialShapeDrawable(shapePathModel).apply {setTint(Color.parseColor("#bebebe"))paintStyle = Paint.Style.FILL
}
test1.background = backgroundDrawable

MaterialShapeDrawable实际上充当了一个Drawable的角色,用于创建一个指定Shape的背景。

除了上面这种设置setAllCorners和setAllCornerSizes来确定Corner的方式,还可以通过下面这种方式。

.setAllCorners(CornerFamily.ROUNDED, 8.dp())

展示如图所示。

image-20201010143256999

类似的,还可以指定Edge的效果。

val shapePathModel = ShapeAppearanceModel.builder().setAllCorners(RoundedCornerTreatment()).setAllCornerSizes(10.dp()).setAllEdges(TriangleEdgeTreatment(8.dp(), true)).build()
val backgroundDrawable = MaterialShapeDrawable(shapePathModel).apply {setTint(Color.parseColor("#bebebe"))paintStyle = Paint.Style.FILL_AND_STROKEstrokeWidth = 2.dp()
}
test1.background = backgroundDrawable

展示如图所示。

image-20201010144309479

MaterialShapeDrawable还可以对描边进行设置,如上图所示。

不过这里要注意的是View的布局边界问题,默认情况下,超出布局边界的内容是会被裁剪的,所以这里在使用TriangleEdgeTreatment(8.dp(), true),第二个参数isInside设置的是true,如果设置成false,就需要指定parent view的clipChildren属性为false了。

(test1.parent as? ViewGroup)?.clipChildren = false

这一点很重要,如果是封装的自定义View,通常可以在attachToWindow中进行设置。

在源码中,已经内置了很多不同种类的EdgeTreatment和CornerTreatment,这些基本的Edge和Corner的处理,可以满足大部分的使用场景。

image-20201010143539670

自定义CornerTreatment和EdgeTreatment

除了系统自定义的基本的Edge和Corner以外,还可以自定义Edge和Corner的样式。其实代码很简单,就是针对给定的ShapePath进行一些裁剪处理,下面就列举了一些处理的Demo,相信大家一看就能明白是如何处理的了。

class InnerCutCornerTreatment : CornerTreatment() {override fun getCornerPath(shapePath: ShapePath, angle: Float, f: Float, size: Float) {val radius = size * fshapePath.reset(0f, radius, 180f, 180 - angle)shapePath.lineTo(radius, radius)shapePath.lineTo(radius, 0f)}
}class InnerRoundCornerTreatment : CornerTreatment() {override fun getCornerPath(shapePath: ShapePath, angle: Float, f: Float, size: Float) {val radius = size * fshapePath.reset(0f, radius, 180f, 180 - angle)shapePath.addArc(-radius, -radius, radius, radius, angle, -90f)}
}class ExtraRoundCornerTreatment : CornerTreatment() {override fun getCornerPath(shapePath: ShapePath, angle: Float, f: Float, size: Float) {val radius = size * fshapePath.reset(0f, radius, 180f, 180 - angle)shapePath.addArc(-radius, -radius, radius, radius, angle, 270f)}
}class ArgEdgeTreatment(val size: Float, val inside: Boolean) : EdgeTreatment() {override fun getEdgePath(length: Float, center: Float, f: Float, shapePath: ShapePath) {val radius = size * fshapePath.lineTo(center - radius, 0f)shapePath.addArc(center - radius, -radius,center + radius, radius,180f,if (inside) -180f else 180f)shapePath.lineTo(length, 0f)}
}class QuadEdgeTreatment(val size: Float) : EdgeTreatment() {override fun getEdgePath(length: Float, center: Float, f: Float, shapePath: ShapePath) {shapePath.quadToPoint(center, size * f, length, 0f)}
}

针对单边、单角的处理

除了可以通过allXXX来统一设置四个角和边的属性,当然也是可以指定某个角或者边的,ShapeAppearanceModel的Builder同样提供了下面的这些方法来处理单边和单角。

image-20201010152336779

借助单边、单角的处理,可以完成一些常用的样式处理,例如,聊天界面边界的气泡效果,代码如下所示。

val shapePathModel = ShapeAppearanceModel.builder().setAllCorners(RoundedCornerTreatment()).setAllCornerSizes(16.dp()).setRightEdge(object : TriangleEdgeTreatment(8.dp(), false) {override fun getEdgePath(length: Float,center: Float,interpolation: Float,shapePath: ShapePath) {super.getEdgePath(length, 12.dp(), interpolation, shapePath)}}).build()
val backgroundDrawable = MaterialShapeDrawable(shapePathModel).apply {setTint(Color.parseColor("#bebebe"))paintStyle = Paint.Style.FILL
}
(test1.parent as? ViewGroup)?.clipChildren = false
test1.background = backgroundDrawable

展示效果如图所示。

image-20201010155158266

阴影的处理

虽然MD提供了setElevation来设置View的高程,但是国内的设计师普遍不认同这种设计理念,认为Elevation设置的阴影比较生硬不够自然,借助MaterialShapeDrawable,我们同样可以来处理阴影。

一般来说,处理阴影不外乎下面几种方式。

  • translationZ与elevation,国内设计师不喜欢

  • 使用9Patch阴影图,一般可以通过http://inloop.github.io/shadow4android/ 来创建,同时View需要预留阴影空间

  • 通过setShadowLayer来绘制,使用比较局限

就目前而言,比较成熟的就是使用MaterialShapeDrawable来实现阴影效果,代码如下所示。

val shapePathModel = ShapeAppearanceModel.builder().setAllCorners(RoundedCornerTreatment()).setAllCornerSizes(16.dp()).build()
val backgroundDrawable = MaterialShapeDrawable(shapePathModel).apply {setTint(Color.parseColor("#05bebebe"))paintStyle = Paint.Style.FILLshadowCompatibilityMode = MaterialShapeDrawable.SHADOW_COMPAT_MODE_ALWAYSinitializeElevationOverlay(this@MainActivity)shadowRadius = 16.dp().toInt()setShadowColor(Color.parseColor("#D2D2D2"))shadowVerticalOffset = 2.dp().toInt()
}
(test1.parent as? ViewGroup)?.clipChildren = false
test1.background = backgroundDrawable

首先,阴影处于布局边界之外,所以需要使用clipChildren属性,同时,设置自定义阴影的核心在于shadowCompatibilityMode参数,它由几个枚举(SHADOW_COMPAT_MODE_DEFAULT、SHADOW_COMPAT_MODE_NEVER、SHADOW_COMPAT_MODE_ALWAYS),其中SHADOW_COMPAT_MODE_DEFAULT表示是使用elevation的阴影绘制方式,还是fake shadow的绘制方式。

这里需要设置为SHADOW_COMPAT_MODE_ALWAYS,表示始终使用fake shadow。它的几个参数shadowRadius、setShadowColor、shadowVerticalOffset分别代表了绘制阴影的三个参数,效果如图所示。

image-20201010154158942

综上,通过Material Components的MaterialShapeDrawable,基本上就可以实现Material Design的所有Shape处理。在现代化的Android开发中,Google已经对应用层的很多设计、开发方式进行了统一和梳理,利用这些先进的开发工具,可以让我们平时的开发更加方便。

修仙

对于Android和Flutter相关技术感兴趣的朋友,可以添加我的微信,拉你进Flutter修仙群和Android开发群,微信号 Tomcat_xu。

https://xuyisheng.top 是我的网站,欢迎大家访问,我会在这里分享Android、Kotlin和Flutter相关的开发经验,点击原文链接,一键直达。

Material Components——Shape的处理相关推荐

  1. Flutter (四) 基础 Widgets、Material Components Widget 全面介绍

    基础 Widgets 重要概念 一切皆组件.Flutter 所有的元素都是由组件组成.比如一个布局元素.一个动画.一个装饰效果等. 容器 Container 容器组件 Container 包含一个子 ...

  2. [译] MDC-101 Flutter:Material Components(MDC)基础(Flutter)

    原文地址:MDC-101 Flutter: Material Components (MDC) Basics (Flutter) 原文作者:codelabs.developers.google.com ...

  3. Android Material Components – MaterialAlertDialog

    Material Design 2.0 is out and we can't wait to get our hands on Dialogs. In this tutorial, we'll be ...

  4. Android ShapeableImageView使用详解,告别shape、三方库

    效果 前言 先来看一下ShapeableImageView是什么 由上图可以看到ShapeableImageView也没有什么神秘的,不过是ImageView的一个子类而已,但是从效果图来看,在不写s ...

  5. Android Material文本字段

    In this tutorial, we'll implement Text Fields using the new Material Design Components Library. We h ...

  6. PS Material 漫谈 六: Material Availability Check

    使用: Use this function to check whether material components in networks are available on the requirem ...

  7. Angular Material design设计

    官网: https://material.io/design/ https://meterial.io/components 优秀的Meterial design站点: http://material ...

  8. angular 居中_Angular Material design设计

    官网: 优秀的Meterial design站点: 并不是万能的,都有约束条件. 优点:兼容性好,可扩展性强,可测试性好,对主题的支持好. 缺点:组件不是特别丰富. 安装: //其它方式 $ sudo ...

  9. 打造 Material 颜色主题 | 设计篇

    作者 / Liam Spradlin, Material Design Advocate 颜色是设计中最清晰的表现形式之一,尤其是当您需要在人们的各种活动场合中传播您的品牌或产品形象时.应用的界面可容 ...

最新文章

  1. 分享个网盘,个人觉得很不错!
  2. 第一周(1.8-1.14)
  3. 手把手教渗透测试人员打造.NET可执行文件
  4. Win32 汇编要点总结
  5. linux下电池测试软件,你们要的App电量分析测试来了
  6. 微信小程序学习笔记(五)
  7. C++多态案例三-电脑组装
  8. SQLI DUMB SERIES-16
  9. MyBatis第1天
  10. python怎样画立体图-Python学习(一) —— matplotlib绘制三维轨迹图
  11. Windows给SVN配置中文语言包
  12. MySQL-JDBC
  13. 0基础学SQL-Task02 SQL基础查询与排序(共7节)
  14. 图像scale与相机参数_摄像头参数测试指导分析解析
  15. html如何将搜索图标放入搜索框中
  16. linux换页符号,关于换行符:什么是回车符,换行符和换页符?
  17. HQChart实战教程17 -K线沙盘推演
  18. C# Winform鼠标样式设置方法
  19. dispatch_once造成的死锁问题
  20. 如何升级MacOS到指定版本

热门文章

  1. 青软实训.Net学习笔记(3)--接口
  2. sql 查询重复数据大于2条以上的_「干货」关于SQL书写建议 索引优化的总结,你值得拥有...
  3. 2013上半年中国CRM市场分析报告
  4. Java微服务学习笔记(一):微服务架构的概念理解
  5. java 线程的说法_以下关于Java线程的说法,正确的是
  6. 这些Web API真的有用吗? 别问,问就是有用
  7. HTML5设计原理-------Jeremy Keith在 Fronteers 2010 上的主题演讲
  8. Android架构组件(二):LiveData
  9. 二级C语言VC++2010学习版安装
  10. 联想服务器查看报警信息,求教联想万全2000服务器总是报警