ThinkChat2.0新版上线,更智能更精彩,支持会话、画图、阅读、搜索等,送10W Token,即刻开启你的AI之旅 广告
# 1. 前言 在Paint类中提供了setShadowLayer这个方法,用于给文本和图形设置阴影效果。 ~~~ public void setShadowLayer(float radius, float dx, float dy, @ColorInt int shadowColor) { setShadowLayer(radius, dx, dy, Color.pack(shadowColor)); } ~~~ * radius:模糊半径,radius 越大越模糊、越小越清晰。如果 radius 设置为 0,则阴 影消失不见。 * dx:阴影的横向偏移距离,正值向右偏移,负值向左偏移。 * dy:阴影的纵向偏移距离,正值向下偏移,负值向上偏移。 * color:绘制阴影的画笔颜色,即阴影的颜色。 # 2. 案例 自定义一个View,然后主要方法如下: ~~~ /** * 初始化方法 */ private fun init(){ // 初始化文字画笔 mTextPaint = Paint() mTextPaint.color = Color.BLACK mTextPaint.strokeWidth = 5f mTextPaint.isAntiAlias = true mTextPaint.isDither = true mTextPaint.textSize = Tool.dp2px(resources, 30f) // 需要禁用硬件加速后,绘制的圆和图片才有阴影效果 setLayerType(LAYER_TYPE_SOFTWARE, null) } override fun onDraw(canvas: Canvas?) { super.onDraw(canvas) canvas?.apply { val radius = Tool.dp2px(resources, 5f) // 模糊半径,radius 越大越模糊、越小越清晰。 val dx = Tool.dp2px(resources, 10f) // 阴影的横向偏移距离,正值向右偏移,负值向左偏移。 val dy = Tool.dp2px(resources, -5f) // 阴影的纵向偏移距离,正值向下偏移,负值向上偏移。 val color = Color.GRAY // 绘制阴影的画笔颜色,对图片阴影无效 mTextPaint.setShadowLayer(radius, dx, dy, color) // int start, int end, float x, float y drawText(mTextContent, 0, mTextContent.length, 50f, 200f, mTextPaint) // 绘制圆形 drawCircle(300f, 300f, 100f, mTextPaint) // 绘制图片 val bitmap = Tool.getBitmapFromResId(context, R.drawable.b) bitmap?.apply { drawBitmap(bitmap, null, RectF(300F, 500f, 300f + bitmap.width, 500f + bitmap.height), mTextPaint) } } } ~~~ 这里需要注意的是,setShadowLayer()函数只有文字绘制阴影支持硬件加速,其他都不支持硬件加速,也就是如果只是单独绘制文本,那么是不需要下面的代码的。 ~~~ // 需要禁用硬件加速后,绘制的圆和图片才有阴影效果 setLayerType(LAYER_TYPE_SOFTWARE, null) ~~~ 当然,对于Tool类,这里附上: ## 2.1 Tool ~~~ class Tool { companion object{ /** * dp转换为px * @param size 传入dp大小 */ fun dp2px(resources: Resources, size: Float): Float{ return resources.displayMetrics.density * size } /** * 将Drawable资源转为Bitmap * @param drawable Drawable资源 */ fun drawable2Bitmap(drawable: Drawable): Bitmap{ // 获取drawable的宽高 val width = drawable.intrinsicWidth val height = drawable.intrinsicHeight // 指定这个图片的绘制边界 drawable.setBounds(0, 0, width, height) // 创建一个空白的Bitmap var bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888) // 创建画布 val canvas = Canvas(bitmap) // 将drawable图片绘制到画布 drawable.draw(canvas) return bitmap } /** * 从资源ID获取到Bitmap对象 * @param context 上下文 * @param resId 资源ID */ fun getBitmapFromResId(context: Context, resId: Int):Bitmap?{ val vectorDrawbale = context.getDrawable(resId) vectorDrawbale?.apply { return drawable2Bitmap(vectorDrawbale) } return null } } } ~~~ ## 2.2 效果 ![](https://img.kancloud.cn/00/3f/003fd04af7188c4236f9d20fbab3fdc5_259x289.png) 但是值得注意的一点就是这里的图片阴影并没有保持和前面文本或者圆形的阴影一样的颜色,而是复制出这张图片,把复制出来的图片的边缘进行**高斯模糊**,作为阴影。那么,有些时候我们只需要一个灰度的阴影效果,就达不到要求了。 对应的解决方案在《Android自定义控件开发入门与实战》一书中做了介绍,也就是使用BlurMaskFilter发光效果来模拟。 # 3. BlurMaskFilter发光效果 可以通过Paint中的setMaskFilter(MaskFilter maskfilter)函数来进行设置,需要注意的是该函数不支持硬件加速的,必须关闭硬件加速才可以。对于BlurMaskFilter的构造函数: ``` public BlurMaskFilter(float radius, Blur style) ``` * radius:表示模糊半径; * style:表示发光样式,可选有四种,如下图; ![](https://img.kancloud.cn/62/4f/624fb16e49a511a5efec1ebdfe9b694d_863x264.png) 所以如果要给图片生成一个灰度的阴影效果,那么可通过如下的步骤实现: * 产生一个跟原型一样的灰色副本; * 对这个灰色副本应用 BlurMaskFilter, 使其内外发光; * 最后偏移一段距离,这样就形成了所谓的阴影; ## 3.1 生成灰色副本 ~~~ // 背景层——阴影效果 alphaBitmap.apply { // 设置发光样式 mPaint.setMaskFilter(maskFilter) // 绘制图片 drawBitmap(alphaBitmap, null, rect, mPaint) // 移动画布 translate(-10f, 10f) } ~~~ ## 3.2 绘制前景层 ~~~ // 前景层 bitmap?.apply { // 前景层这里不要高斯模糊效果,直接重置传入null即可 mPaint.setMaskFilter(null) drawBitmap(bitmap!!, null, rect, mPaint) } ~~~ ## 3.3 完整代码 ~~~ /** * 阴影效果学习 * @author 梦否 * 2022-3-17 */ class Shadow2Demo:View { constructor(context: Context?) : super(context) { init() } constructor(context: Context?, attrs: AttributeSet?) : super(context, attrs) { init() } constructor(context: Context?, attrs: AttributeSet?, defStyleAttr: Int) : super( context, attrs, defStyleAttr ) { init() } private lateinit var mPaint : Paint private lateinit var maskFilter: MaskFilter private lateinit var alphaBitmap: Bitmap private lateinit var rect: RectF private var bitmap: Bitmap? = null /** * 初始化方法 */ private fun init(){ // 初始化文字画笔 mPaint = Paint() mPaint.color = Color.GRAY mPaint.strokeWidth = 5f mPaint.isAntiAlias = true mPaint.isDither = true mPaint.textSize = Tool.dp2px(resources, 30f) // 需要禁用硬件加速后,绘制的圆和图片才有阴影效果 setLayerType(LAYER_TYPE_SOFTWARE, null) // 原始图片 bitmap = Tool.getBitmapFromResId(context, R.drawable.b) // extratAlpha // Returns a new bitmap that captures the alpha values of the original. bitmap.apply { alphaBitmap = bitmap!!.extractAlpha() rect = RectF(300F, 500f, 300f + bitmap!!.width, 500f + bitmap!!.height) } // 设置内发光 maskFilter = BlurMaskFilter(5f, BlurMaskFilter.Blur.NORMAL) } override fun onDraw(canvas: Canvas?) { super.onDraw(canvas) canvas?.apply { // 背景层——阴影效果 alphaBitmap.apply { // 设置发光样式 mPaint.setMaskFilter(maskFilter) // 绘制图片 drawBitmap(alphaBitmap, null, rect, mPaint) // 移动画布 translate(-10f, 10f) } // 前景层 bitmap?.apply { // 前景层这里不要高斯模糊效果,直接重置传入null即可 mPaint.setMaskFilter(null) drawBitmap(bitmap!!, null, rect, mPaint) } } } } ~~~ ## 3.4 效果 ![](https://img.kancloud.cn/b6/e3/b6e36e33718a69d965b098143dcac2e5_199x132.png)