我们在EasyConstraintLayout中初始化paint,并且关闭硬件加速,然后在drawChild中实现阴影逻辑,最终代码如下。

public class EasyConstraintLayout extends ConstraintLayout {
private Paint shadowPaint;
private Paint clipPaint;

public EasyConstraintLayout(Context context, AttributeSet attrs) {
super(context, attrs);
shadowPaint = new Paint();
shadowPaint.setAntiAlias(true);
shadowPaint.setDither(true);
shadowPaint.setFilterBitmap(true);
shadowPaint.setStyle(Paint.Style.FILL);

clipPaint = new Paint();
clipPaint.setAntiAlias(true);
clipPaint.setDither(true);
clipPaint.setFilterBitmap(true);
clipPaint.setStyle(Paint.Style.FILL);
setLayerType(View.LAYER_TYPE_SOFTWARE, null);
}

@Override
public ConstraintLayout.LayoutParams generateLayoutParams(AttributeSet attrs) {
return new LayoutParams(getContext(), attrs);
}

@Override
protected boolean checkLayoutParams(ViewGroup.LayoutParams p) {
return p instanceof LayoutParams;
}

@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
for (int i = 0, size = getChildCount(); i < size; i++) {
View v = getChildAt(i);
ViewGroup.LayoutParams lp = v.getLayoutParams();
if (lp instanceof EasyLayoutParams) {
EasyLayoutParams elp = (EasyLayoutParams) lp;
elp.getData().initPaths(v);
}
}
}

@Override
protected boolean drawChild(Canvas canvas, View child, long drawingTime) {
ViewGroup.LayoutParams lp = child.getLayoutParams();
boolean ret = false;
if (lp instanceof EasyLayoutParams) {
EasyLayoutParams elp = (EasyLayoutParams) lp;
LayoutParamsData data = elp.getData();
if (isInEditMode()) {//预览模式采用裁剪
canvas.save();
canvas.clipPath(data.widgetPath);
ret = super.drawChild(canvas, child, drawingTime);
canvas.restore();
return ret;
}
if (!data.hasShadow && !data.needClip)
return super.drawChild(canvas, child, drawingTime);
//为解决锯齿问题,正式环境采用xfermode
if (data.hasShadow) {
int count = canvas.saveLayer(null, null, Canvas.ALL_SAVE_FLAG);
shadowPaint.setShadowLayer(data.shadowEvaluation, data.shadowDx, data.shadowDy, data.shadowColor);
shadowPaint.setColor(data.shadowColor);
canvas.drawPath(data.widgetPath, shadowPaint);
shadowPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT));
shadowPaint.setColor(Color.WHITE);
canvas.drawPath(data.widgetPath, shadowPaint);
shadowPaint.setXfermode(null);
canvas.restoreToCount(count);

}
if (data.needClip) {
int count = canvas.saveLayer(child.getLeft(), child.getTop(), child.getRight(), child.getBottom(), null, Canvas.ALL_SAVE_FLAG);
ret = super.drawChild(canvas, child, drawingTime);
clipPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
clipPaint.setColor(Color.WHITE);
canvas.drawPath(data.clipPath, clipPaint);
clipPaint.setXfermode(null);
canvas.restoreToCount(count);
}
}
return ret;
}

static class LayoutParams extends ConstraintLayout.LayoutParams implements EasyLayoutParams {

private LayoutParamsData data;

public LayoutParams(Context c, AttributeSet attrs) {
super(c, attrs);
data = new LayoutParamsData(c, attrs);
}

@Override
public LayoutParamsData getData() {
return data;
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
使用方法
<?xml version="1.0" encoding="utf-8"?>
<io.github.iamyours.easylayout.EasyConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">

<View
android:id="@+id/v_back"
android:layout_width="match_parent"
android:layout_height="150dp"
android:layout_margin="10dp"
android:background="#fff"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_radius="4dp"
app:layout_shadowColor="#3ccc"
app:layout_shadowEvaluation="15dp" />

<ImageView
android:id="@+id/iv_head"
android:layout_width="80dp"
android:layout_height="80dp"
android:layout_gravity="center_horizontal"
android:layout_marginLeft="10dp"
android:background="#eee"
app:layout_constraintBottom_toBottomOf="@id/v_back"
app:layout_constraintLeft_toLeftOf="@id/v_back"
app:layout_constraintTop_toTopOf="@id/v_back"
app:layout_radius="40dp"
app:layout_shadowColor="#5f00"
app:layout_shadowEvaluation="8dp" />

<View
android:layout_width="200dp"
android:layout_height="200dp"
android:layout_marginTop="30dp"
android:background="#ccc"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@id/v_back"
app:layout_radius="30dp"
app:layout_shadowColor="#8f0f"
app:layout_shadowDx="4dp"
app:layout_shadowDy="4dp"
app:layout_shadowEvaluation="10dp" />
</io.github.iamyours.easylayout.EasyConstraintLayout>
---------------------

drawChild中画阴影,裁剪出圆角的更多相关文章

  1. python—networkx:在一张图中画出多个子图

    通过plt.subplot能够在一张图中画出多个子图 #coding: utf-8 #!/usr/bin/env python """ Draw a graph with ...

  2. iOS高效裁剪图片圆角算法

    项目有个需求:裁剪图片,针对头像,下面是要求: 大家可以看到这张图片的圆角已经去除,下面说说我在项目利用了两种方式实现此裁剪以及查看技术文档发现更高效裁剪方式,下面一一讲解:看下来大约需要15-20分 ...

  3. 在ps中画两个同心圆并且把两个同心圆进行任意角度切割

    在工作中遇到要在ps中画如图两个同心圆,并且进行6等分.查找资料加自己摸索,可以通过以下方式实现: 1.新建一画布.并用通过标尺画出两条水平和垂直参考线,选择椭圆工具,并在选项设置中选择圆和从中心两个 ...

  4. Android Demo---如何敲出圆角的Button+圆角头像

    经常玩儿App的小伙伴都知道,APP上面有很多按钮都是圆角的,圆形给人感觉饱满,富有张力,不知道设计圆角按钮的小伙伴是不是和小编有着相同的想法`(*∩_∩*)′,听小编公司开发IOS的小伙伴说,他们里 ...

  5. css边框样式、边框配色、边框阴影、边框圆角、图片边框

     边框样式 点线式边框 破折线式边框 直线式边框 双线式边框 槽线式边框 脊线式边框 内嵌效果的边框 突起效果的边框 <div style="width: 300px; height: ...

  6. 如何在CorelDRAW中创建对象阴影

    阴影工具可以为对象创建光线映射的阴影效果,使对象产生较强的立体感.可以为大多数对象或群组对象添加阴影,其中包括美术字.段落文本和位图.创建对象阴影可以增加视觉层次,使图形更加逼真. CorelDRAW ...

  7. 用字体在网页中画Icon图标

    第一步,下载.IcoMoon网站选择字体图标并下载,解压后将fonts文件夹放在工程目录下.fonts文件夹内有四种格式的字体文件: 注:由于浏览器对每种字体的支持程度不一致,要想在所有浏览器中都显示 ...

  8. bootstrap中popover.js(弹出框)使用总结+案例

    bootstrap中popover.js(弹出框)使用总结+案例 *转载请注明出处: 作者:willingtolove: http://www.cnblogs.com/willingtolove/p/ ...

  9. 字体在网页中画ICON图标

    用字体在网页中画ICON图标有三种小技巧: 1.用CSS Sprite在网页中画小图标 实现方法: 首先将小图片整合到一张大的图片上 然后根据具体图标在大图上的位置,给背景定位.background- ...

随机推荐

  1. SpringBoot整合Lintener

    1.通过扫描完成Lintener组件的注册 1.1编写Listener /** * springboot整合Lintener 方式一 * 在web.xml中如何配置Listener * <lis ...

  2. pandas 入门(2)

    from pandas import Series, DataFrame, Index import numpy as np from numpy import nan as NA obj = Ser ...

  3. Spring IoC,IoC原理

    一.IoC概念及原理 IOC的别名:依赖注入(DI) 2004年,Martin Fowler探讨了同一个问题,既然IOC是控制反转,那么到底是“哪些方面的控制被反转了呢?”,经过详细地分析和论证后,他 ...

  4. Java包的使用

    好处 1.类似于文件系统的文件夹,可以实现分类管理类文件,方便查找2.解决了同一个项目中同名类的冲突问题 包的创建 命名规范: 建议小写字母,并且采用域名倒置的写法 域名倒置:com.baidu ww ...

  5. Eureka注册中心高可用及常用配置项

    一.前言 前面已经简单的介绍了 Eureka 注册中心的使用以及查看.下面将继续进行 Eureka 的说明以及应用. 二.Eureka 的高可用搭建 在实际生产项目中,为了保证服务的可用性,连续性,一 ...

  6. 利用 Python 进行批量更改文件后缀

    利用 Python 进行批量更改文件后缀 代码 import os files = os.listdir('.') for file_name in files: portion = os.path. ...

  7. Vue 实现文件的下载

    上次说了,实现文件的上传需要三步,那么实现文件的下载呢? 答:也是三步 第一步:获取文件的 fileId (或者别的什么的,总之应该是代表这个文件的东西),各家后台需要的都不一样 第二步:调用接口 t ...

  8. layui在当前页面弹出一个iframe层,并改变这个iframe层里的一些内容

    layer.open({ type: 2, title: "专家信息", area: ['100%', '100%'], content: '/ZhuanJiaKu/AddZhua ...

  9. xxPay搭建步骤

    随着电子商务的发展,移动支付也走进我们的日常生活,就像很多基础业务,如物流.云平台一样,我们现在做什么都离不开她.正因为如此,支付是当下最活跃最前沿的话题,很多流行的技术最早用来实现支付,很多新的业务 ...

  10. 编译安装github上的kafka_exporter项目

    本文介绍的kafka_exporter是prometheus监控系统中针对kafka的一款监控插件,要使用这个监控插件,kafka的版本需要满足 0.10.1.0 及以上. 项目的github地址:h ...