前言

这个迭代,UI在给了几张带阴影的图片,那种阴影范围很大,实际内容却只有一点的图片。

效果类似这样。

不知道这张图有没有表达清楚,就是那种图片之间阴影需要重叠才能使内容对其,阴影还有颜色的效果。

Android 5.0后才支持elevation属性,还不支持阴影颜色的设定。IOS同事笑了,他们说直接把阴影效果给他们,不要带阴影的图片,他们天然支持阴影,可以直接绘制。

于是,上网搜索,发现目前Andorid 平台实现阴影大概有这么几种方式

2、CardView 不支持阴影颜色

3、开源库ShadowLayout

4、模仿FloatingActionButton 实现阴影等等。

这些方式是可以实现阴影的显示,但是基本都是将阴影作为控件的一部分去实现的。这样,就需要给控件设置一些padding值,才能让阴影显示出来。这种方式使得布局很不方便对齐。

我的解决方案

先上效果看看

既然将阴影作为控件的一部分去实现不利于控件的布局和对其,那就咱就在ViewGroup里去实现阴影。绘制的时候根据子view的位置绘制出阴影,这样就不会影响控件的布局和对其了。

其实我觉得控件的阴影天然就应该在父布局去实现,就像现实中的阴影那样。

实现思路

1、继承ViewGoup

Android 中有FrameLayout、LinearLayout、RelativeLayout、ConstraintLayout等等,这些layout是为了进行子view布局而设计的,如果不进行背景色的设置,默认是不走ondraw方法的。

我们可以继承这些ViewGroup,设置setWillNotDraw(false)标志位强制进行绘制,这样我们就既拥有了布局的功能,也拥有了绘制的功能。然后就能在onDraw方法中,根据子view的位置绘制背景了。

2、复写onDraw方法绘制子view背景

这一步很简单,一个循环遍历子view就好了

如何绘制

1、绘制之前 需要设置 setLayerType(View.LAYER_TYPE_SOFTWARE, null)关闭硬件加速,因为一些高级绘制方法可能不支持硬件加速。

2、为paint设置 shadowLayer

paint.setShadowLayer(shadowLayoutParams.shadowRadius, shadowLayoutParams.xOffset

, shadowLayoutParams.yOffset, shadowLayoutParams.shadowColor);

复制代码

3、最后的代码

public class ShadowConstraintLayout extends ConstraintLayout {

Paint paint;

RectF rectF = new RectF();

public ShadowConstraintLayout(Context context) {

this(context, null);

}

public ShadowConstraintLayout(Context context, AttributeSet attrs) {

this(context, attrs, 0);

}

public ShadowConstraintLayout(Context context, AttributeSet attrs, int defStyleAttr) {

super(context, attrs, defStyleAttr);

// 关键点,使ViewGroup调用onDraw方法

setWillNotDraw(false);

paint = new Paint();

paint.setStyle(Paint.Style.FILL);

paint.setAntiAlias(true);

this.setLayerType(View.LAYER_TYPE_SOFTWARE, null);

}

@Override

protected void onDraw(Canvas canvas) {

super.onDraw(canvas);

int childCount = getChildCount();

// 根据参数在父布局绘制背景

for (int i = 0; i < childCount; i++) {

View child = getChildAt(i);

ViewGroup.LayoutParams layoutParams = child.getLayoutParams();

if (layoutParams instanceof ShadowConstraintLayout.LayoutParams) {

ShadowConstraintLayout.LayoutParams shadowLayoutParams = (LayoutParams) layoutParams;

if (shadowLayoutParams.shadowRadius > 0 && shadowLayoutParams.shadowColor != Color.TRANSPARENT) {

rectF.left = child.getLeft();

rectF.right = child.getRight();

rectF.top = child.getTop();

rectF.bottom = child.getBottom();

paint.setStyle(Paint.Style.FILL);

paint.setShadowLayer(shadowLayoutParams.shadowRadius, shadowLayoutParams.xOffset

, shadowLayoutParams.yOffset, shadowLayoutParams.shadowColor);

paint.setColor(shadowLayoutParams.shadowColor);

canvas.drawRoundRect(rectF, shadowLayoutParams.shadowRoundRadius, shadowLayoutParams.shadowRoundRadius, paint);

}

}

}

}

public static class LayoutParams extends ConstraintLayout.LayoutParams {

private float xOffset;

private float yOffset;

// 阴影颜色

private int shadowColor;

// 阴影大小

private float shadowRadius;

// 阴影圆角大小

private float shadowRoundRadius;

public LayoutParams(int width, int height) {

super(width, height);

}

public LayoutParams(ShadowConstraintLayout.LayoutParams source) {

super(source);

xOffset = source.getXOffset();

yOffset = source.getYOffset();

shadowColor = source.getShadowColor();

shadowRadius = source.getShadowRadius();

shadowRoundRadius = source.getShadowRoundRadius();

}

public LayoutParams(Context c, AttributeSet attrs) {

super(c, attrs);

TypedArray attributes = c.obtainStyledAttributes(attrs, R.styleable.ShadowConstraintLayout_Layout);

xOffset = attributes.getDimension(R.styleable.ShadowConstraintLayout_Layout_layout_xOffset, 0);

yOffset = attributes.getDimension(R.styleable.ShadowConstraintLayout_Layout_layout_yOffset, 0);

shadowRadius = attributes.getDimension(R.styleable.ShadowConstraintLayout_Layout_layout_shadowRadius, 0);

shadowColor = attributes.getColor(R.styleable.ShadowConstraintLayout_Layout_layout_shadowColor, 0);

shadowRoundRadius = attributes.getDimension(R.styleable.ShadowConstraintLayout_Layout_layout_shadowRoundRadius, 0);

attributes.recycle();

}

public LayoutParams(ViewGroup.LayoutParams source) {

super(source);

}

public float getXOffset() {

return xOffset;

}

public void setXOffset(float xOffset) {

this.xOffset = xOffset;

}

public float getYOffset() {

return yOffset;

}

public void setYOffset(float yOffset) {

this.yOffset = yOffset;

}

public int getShadowColor() {

return shadowColor;

}

public void setShadowColor(int shadowColor) {

this.shadowColor = shadowColor;

}

public float getShadowRadius() {

return shadowRadius;

}

public void setShadowRadius(float shadowRadius) {

this.shadowRadius = shadowRadius;

}

public float getShadowRoundRadius() {

return shadowRoundRadius;

}

public void setShadowRoundRadius(float shadowRoundRadius) {

this.shadowRoundRadius = shadowRoundRadius;

}

}

public ShadowConstraintLayout.LayoutParams generateLayoutParams(AttributeSet attrs) {

return new ShadowConstraintLayout.LayoutParams(this.getContext(), attrs);

}

protected ShadowConstraintLayout.LayoutParams generateDefaultLayoutParams() {

return new ShadowConstraintLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT);

}

protected ViewGroup.LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) {

return new ShadowConstraintLayout.LayoutParams(p);

}

protected boolean checkLayoutParams(ViewGroup.LayoutParams p) {

return p instanceof ShadowConstraintLayout.LayoutParams;

}

}

复制代码

使用起来大概像这样。

android:layout_width="match_parent"

android:layout_height="match_parent"

xmlns:app="http://schemas.android.com/apk/res-auto">

app:layout_constraintStart_toStartOf="parent"

app:layout_constraintTop_toTopOf="parent"

app:layout_constraintEnd_toEndOf="parent"

app:layout_constraintBottom_toBottomOf="parent"

android:layout_width="100dp"

android:layout_height="100dp"

android:layout_centerHorizontal="true"

android:background="@drawable/blue_round_bg"

app:layout_shadowColor="#805468A5"

app:layout_shadowRadius="8dp"

app:layout_shadowRoundRadius="5dp"

app:layout_yOffset="2dp" />

复制代码

目前已实现 FrameLayout、LinearLayout、RelativeLayout、ConstraintLayout等等

添加依赖 implementation 'com.github.ZhangHao555:AndroidGroupShadow:v1.0'

打包android阴影不见,Android无pading超简单超实用阴影解决方案相关推荐

  1. Android:实现QQ聊天(超简单)

    前言 1. 简单定义Msg类 package com.bytedance.sjtu.msgclass Msg(val msg: String, val msgType: Int) {companion ...

  2. 三星android 截图,三星手机怎么截图 三星手机超简单截屏教程

    三星手机怎么截图 三星手机超简单截屏教程 来源:www.18183.com作者:皮卡时间:2015-04-13 这里的方法对三星智能手机几乎都适用.那就是使用快捷组合键.同时按住手机中间的home键+ ...

  3. ASP.NET中一种超简单的Ajax解决方案

    为什么是Ajax2? 因为之前有一个blqw.Ajax,并且已经在项目中投入使用了,但是没有这个方便,这个是后来才弄的,为了纪念第一版的blqw.Ajax,所以这个就2了... 话说看了评论才发现,原 ...

  4. 如何在pc上开发Android程序,电脑上运行Android应用(APK软件)超简单方法

    android是一个广阔.有活力的应用生态系统.根据统计,google play商店当中的应用数量已经超过1500万,其中当然也包含着众多高品质的热门应用. 但你是否想过,要是能在计算机上运行这些应用 ...

  5. Android 文字数字换行后对不齐?超简单硬核解决方案!

    在安卓开发中,经常遇到这种界面的显示          像我一样懒的人都会像到用两个textview,控制他们的行高一致来进行换行显示,既方便又快捷 但经常会遇到这种情况,预览图显示一点毛病都没有,但 ...

  6. 如何绘画Q版古风人物,超简单超实用,一学就会!

    相信很多同学在追剧的时候,都很想要一个喜欢人物的q版画像.与其满世界寻找,不如自己动手试试看,超级简单,超级可爱哦~ 以下图为例:下图是一个古装人物,如何绘画其Q版呢? 按照以下步骤: 1.选出自己认 ...

  7. 超简单超实用MySQL修改密码方法来喽

    使用SET PASSWORD命令 1:首先使用原密码登录MySQL 2:输入命令 格式:mysql>set password for 用户名@localhost=password('新密码'); ...

  8. android app报错log,Android studio 解决logcat无过滤工具栏的操作

    在logcat标题栏右键先windows mode,这时多数能恢复过滤工具栏,要恢复之前的停靠样式再同样点右键去掉windows mode的勾即可 补充知识:Android studio底部Logca ...

  9. android 多渠道上线,Android打包之多版本、多环境、多渠道

    在平时的Android开发中,我们经常会遇到在不同网络环境(比如:开发环境.测试环境)之间的切换.一次打多个渠道包等需求,如何优雅的管理网络环境的配置?如何快速的打出多个渠道包?这是一个值得研究的问题 ...

最新文章

  1. 记住这53个要点提高PHP编程效率
  2. 使用Python在Selenium WebDriver中获取WebElement的HTML源代码
  3. 全卷积神经网路【U-net项目实战】LUNA 2016 数据集详解
  4. SQL2005以上版本派生表更新
  5. js jquery 函数回调
  6. Redis实战(五):Redis的持久化RDB、fork、copyonwrite、AOF、RDBAOF混合使用
  7. 【深搜】骑士游历(二)
  8. pythonencode和decode_Python3的decode()与encode()
  9. 安徽省级办公室高级应用计算机二级,2019年9月安徽省计算机等级二级考试教程:二级MSOffice高级应用上机指导...
  10. NOIP 2016 普及组 Solution (T1-T3)
  11. 射极跟随器实验报告数据处理_电压跟随器秘笈:运放构成电压跟随器的稳定性问题探讨...
  12. webstorm破解版
  13. “Bluetooth keeps stopping“
  14. 使用Windows 10自带工具 校验MD5 SHA1 SHA256类型文件
  15. 中考考不上好高中怎么办?
  16. 运用matlab求解梁的变形例题,matlab与结构力学
  17. 真正实现网络下载,文件不落地.解决XmlHttp对象、winnet.dll、URLDownloadToFile生成的ie缓存(Hook_CreateFileW阻止缓存生成)
  18. arduino数字端口输出电压可驱动多大继电器呢_单片机实例分享,自制数字示波器...
  19. 深入 javascript 之 原型和原型链!!!
  20. ecplise提示:“The selection cannot be launched, and there are no recent launches.”

热门文章

  1. Packet for query is too large (1166 1024). You can change this value
  2. Laravel的console使用方法
  3. Oracle自定义数据类型 1
  4. Html中元素的分类
  5. (三)页面之间的参数传递
  6. 【原创】FPGA (Verilog/NIOS II/Microblaze) 编程小提醒
  7. 2008-08-24
  8. V3S拍照上传又拍云bug排查过程
  9. Linux杂项设备驱动
  10. 可视化篇(二)———使用matplotlib绘制常用3D图形及案例