Android实现通用可控的控件阴影效果(附效果图)

本文介绍了如何解决Android原生CardView阴影颜色不可修改和位置不可控的问题,提出了一种自定义ShadowDrawable的解决方案。通过GitHub开源库,开发者可以实现阴影颜色、位置的自由控制,并提供了使用示例和实际效果展示。
摘要由CSDN通过智能技术生成

背景

android原生的阴影效果,一般都是用CardView来实现
CardView的不足:
1、阴影颜色无法修改
2、阴影显示的位置不可控

解决方案

根据CardView阴影实现{@link android.support.v7.widget.RoundRectDrawableWithShadow},在它的基础上实现自定义阴影Drawable,阴影颜色位置可控

GitHub开源库地址

使用方式
1、root build.gradle中添加仓库地址:

    allprojects {
	    repositories {
		    ...
		    maven { url 'https://jitpack.io' }
	    }
    }

2、app module build.gradle中添加依赖
    dependencies {
        implementation 'com.github.zhangjianliang110:color-shadow_drawable:v1.0.1
    }


3、Demo

public class MainActivity extends AppCompatActivity {

    private ImageView mIvTest;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mIvTest = findViewById(R.id.ivTest);
        ViewCompat.setBackground(mIvTest, getShadowBg(
                ShadowDrawable.ShadowCorner.ALL, ShadowDrawable.ShadowSide.ALL
        ));
    }

    private ShadowDrawable getShadowBg(int cornerType, int sideType) {
        Resources resources = getResources();
        ColorStateList backgroundColor = ColorStateList.valueOf(resources.getColor(android.R.color.white));//设置背景色
        ShadowDrawable shadowBg = new ShadowDrawable(resources, backgroundColor, dip2px(25), dip2px(3), dip2px(6));
        shadowBg.setShadowCorner(cornerType);
        shadowBg.setShadowSide(sideType);
        int startColor = resources.getColor(R.color.shadow_start_color);//阴影内侧颜色
        int endColor = resources.getColor(R.color.shadow_end_color);//阴影外侧颜色
        shadowBg.setShadowColor(startColor, endColor);
        return shadowBg;
    }

    private int dip2px(float dipValue) {
        if (dipValue == 0) {
            return 0;
        }
        final float scale = getResources().getDisplayMetrics().density;
        return (int) (dipValue * scale + 0.5f);
    }
}
ShadowDrawable 源码
 
package com.test.testapp.view;

import com.test.testapp.R;

import android.content.res.ColorStateList;
import android.content.res.Resources;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.ColorFilter;
import android.graphics.LinearGradient;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PixelFormat;
import android.graphics.RadialGradient;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.Shader;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.support.annotation.ColorInt;
import android.support.annotation.Nullable;

/**
 * 阴影图
 *
 * 该阴影的计算方式跟CardView阴影计算完全一致,这里只是把阴影绘制拆分成每个角、每条边,以及绘制起点、终点的控制,阴影颜色控制
 *
 * CardView阴影颜色不可选、不能控制只显示其中某一边不显示阴影,无法达到设计效果
 * {@link android.support.v7.widget.RoundRectDrawableWithShadow }
 *
 * Created by zhangjianliang on 2018/12/13
 *
 * 使用方式:
 * 

  View view = findViewById(R.id.xxx);
  Resources resources = getResources();
  ColorStateList backgroundColor = ColorStateList.valueOf(resources.getColor(R.color.white));//设置背景色

  ShadowDrawable shadow = new ShadowDrawable(resources, backgroundColor, CommonUtils.dip2px(2), CommonUtils.dip2px(5),
  CommonUtils.dip2px(5));
  shadow.setShadowColor(ColorUtils.getColor(R.color.common_color_fd5c59), ColorUtils.getColor(R.color.common_color_ffcfcf));

  shadow.setShadowCorner(ShadowDrawable.ShadowCorner.LEFT_TOP);
  shadow.setShadowSide(ShadowDrawable.ShadowSide.TOP);

  shadow.setBackgroundColor(ColorUtils.getColor(android.R.color.transparent));
  shadow.setShadowDistance(0, 0, 0, CommonUtils.dip2px(7));

  ViewUtil.setViewBackground(view, shadow);
 *
 * 
 */
package com.stupidbird.view;

import android.content.res.ColorStateList;
import android.content.res.Resources;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.ColorFilter;
import android.graphics.LinearGradient;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PixelFormat;
import android.graphics.RadialGradient;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.Shader;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.support.annotation.ColorInt;
import android.support.annotation.Nullable;

/**
 * 阴影图
 *
 * 该阴影的计算方式跟CardView阴影计算完全一致,这里只是把阴影绘制拆分成每个角、每条边,以及绘制起点、终点的控制,阴影颜色控制
 *
 * CardView阴影颜色不可选、不能控制只显示其中某一边不显示阴影,无法达到设计效果
 * {@link android.support.v7.widget.RoundRectDrawableWithShadow }
 *
 * Created by zhangjianliang on 2018/12/13
 *
 * 使用方式:
 * 

  View view = findViewById(R.id.xxx);
  Resources resources = getResources();
  ColorStateList backgroundColor = ColorStateList.valueOf(resources.getColor(R.color.white));//设置背景色

  ShadowDrawable shadow = new ShadowDrawable(resources, backgroundColor, CommonUtils.dip2px(2), CommonUtils.dip2px(5),
  CommonUtils.dip2px(5));
  shadow.setShadowColor(ColorUtils.getColor(R.color.common_color_fd5c59), ColorUtils.getColor(R.color.common_color_ffcfcf));

  shadow.setShadowCorner(ShadowDrawable.ShadowCorner.LEFT_TOP);
  shadow.setShadowSide(ShadowDrawable.ShadowSide.TOP);

  shadow.setBackgroundColor(ColorUtils.getColor(android.R.color.transparent));
  shadow.setShadowDistance(0, 0, 0, CommonUtils.dip2px(7));

  ViewUtil.setViewBackground(view, shadow);
 *
 * 
 */
public class ShadowDrawable extends Drawable {

    private static final float DEFAULT_SHADOW_MULTIPLIER = 1.5f;

    private final RectF mCornerRect = new RectF();

    // used to calculate content padding
    private static final double COS_45 = Math.cos(Math.toRadians(45));

    private float mShadowMultiplier = DEFAULT_SHADOW_MULTIPLIER;

    private final int mInsetShadow; // extra shadow to avoid gaps between card and shadow

    private Paint mPaint;

    private Paint mCornerShadowPaint;

    private Paint mEdgeShadowPaint;

    private final RectF mCardBounds;

    private float mCornerRadius;

    private Path mCornerShadowPath;

    // actual value set by developer
    private float mRawMaxShadowSize;

    // multiplied value to account for shadow offset
    private float mShadowSize;

    // actual value set by developer
    private float mRawShadowSize;

    private ColorStateList mBackground;

    private boolean mDirty = true;

    private int mShadowStartColor;

    private int mShadowEndColor;

    private boolean mAddPaddingForCorners = true;

    /**
     * If shadow size is set to a value above max shadow, we print a warning
     */
    private boolean mPrintedShadowClipWarning = false;

    private int mCornerType = ShadowCorner.ALL;//默认四个角都有阴影

    private int mSideType = ShadowSide.ALL;//默认四条边都有阴影

    /**用于某些情况下,阴影起点/终点需要缩进的情况*/
    private int mLeftShadowDistance;//阴影与左边的距离
    private int mTopShadowDistance;//阴影与上边的距离
    private int mRightShadowDistance;//阴影与右边的距离
    private int mBottomShadowDistance;//阴影与下边的距离

    /**
     * 创建阴影背景
     *
     * @param backgroundColor 背景色
     * @param radius          圆角
     * @param shadowSize      阴影宽度
     * @param maxShadowSize   阴影最大宽度
     */
    public ShadowDrawable(Resources resources, ColorStateList backgroundColor, float radius, float shadowSize,
            float maxShadowSize) {
        mShadowStartColor = resources.getColor(R.color.shadowview_shadow_start_color);
   
  • 3
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值