17

我目前通过绘制到画布在我的应用程序中创建图像的圆形版本。我想在图像周围画一个微弱的外阴影,但我不能完全正确。我有 2 个问题: 1. 如何绘制外阴影(我似乎只能绘制带有 ax 或 y 偏移的阴影) 2. 如何绘制阴影以使其没有附图中显示的伪影. 代码:

![public Bitmap getRoundedCornerBitmap(Bitmap bitmap, float cornerRadius) {
        Bitmap output = Bitmap.createBitmap(bitmap.getWidth()+6, bitmap.getHeight() +6, Config.ARGB_8888);
        Canvas canvas = new Canvas(output);

        final int color = 0xff424242;
        int shadowRadius = getDipsFromPixel(3);
        final Rect imageRect = new Rect(shadowRadius, shadowRadius, bitmap.getWidth(), bitmap.getHeight());
        final RectF rectF = new RectF(imageRect);

        // This does not achieve the desired effect
        Paint shadowPaint = new Paint();
        shadowPaint.setAntiAlias(true);
        shadowPaint.setColor(Color.BLACK);
        shadowPaint.setShadowLayer((float)shadowRadius, 2.0f, 2.0f,Color.BLACK);
        canvas.drawOval(rectF, shadowPaint);

        canvas.drawARGB(0, 0, 0, 0);
        final Paint paint = new Paint();
        paint.setAntiAlias(true);
        paint.setColor(color);

        canvas.drawRoundRect(rectF, cornerRadius, cornerRadius, paint);

        paint.setXfermode(new PorterDuffXfermode(Mode.SRC_IN));
        canvas.drawBitmap(bitmap, imageRect, imageRect, paint);

        return output;
    }][1]

http://i.stack.imgur.com/d7DV6.png

这是我试图达到的效果的一个例子: 在此处输入图像描述

4

5 回答 5

35

我想要类似的效果,但在 AppWidget 上,很遗憾我无法使用@EvelioTarazona 的解决方案。这就是我想出的,它应该适用于任何形状的位图。

    final Bitmap src = BitmapFactory.decodeResource(getResources(), R.drawable.ic_launcher);
    final Bitmap shadow = addShadow(src, src.getHeight(), src.getWidth(), Color.BLACK, 3, 1, 3);
    final ImageView iv = (ImageView)findViewById(R.id.image);
    iv.setImageBitmap(shadow);

参数 size=3, dx=1, dy=3, color=BLACK 的示例

 public Bitmap addShadow(final Bitmap bm, final int dstHeight, final int dstWidth, int color, int size, float dx, float dy) {
    final Bitmap mask = Bitmap.createBitmap(dstWidth, dstHeight, Config.ALPHA_8);

    final Matrix scaleToFit = new Matrix();
    final RectF src = new RectF(0, 0, bm.getWidth(), bm.getHeight());
    final RectF dst = new RectF(0, 0, dstWidth - dx, dstHeight - dy);
    scaleToFit.setRectToRect(src, dst, ScaleToFit.CENTER);

    final Matrix dropShadow = new Matrix(scaleToFit);
    dropShadow.postTranslate(dx, dy);

    final Canvas maskCanvas = new Canvas(mask);
    final Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
    maskCanvas.drawBitmap(bm, scaleToFit, paint);
    paint.setXfermode(new PorterDuffXfermode(Mode.SRC_OUT));
    maskCanvas.drawBitmap(bm, dropShadow, paint);

    final BlurMaskFilter filter = new BlurMaskFilter(size, Blur.NORMAL);
    paint.reset();
    paint.setAntiAlias(true);
    paint.setColor(color);
    paint.setMaskFilter(filter);
    paint.setFilterBitmap(true);

    final Bitmap ret = Bitmap.createBitmap(dstWidth, dstHeight, Config.ARGB_8888);
    final Canvas retCanvas = new Canvas(ret);
    retCanvas.drawBitmap(mask, 0,  0, paint);
    retCanvas.drawBitmap(bm, scaleToFit, null);
    mask.recycle();
    return ret;
}
于 2014-07-04T19:07:42.210 回答
16

开始了

http://i.imgur.com/cKi1ckX.png 是的,我还在挖掘 Nexus S

首先,请停止以这种方式屏蔽位图,您无需分配另一个即可完成此操作,请查看Bitmap这篇关于如何绘制圆形(实际上是任何形状)图像的博客文章

第二次使用它Drawable你可能可以弄清楚如何添加你的阴影,只要确保它不会被剪裁,在 18+ 上你可以使用ViewOverlays ,还请记住,硬件加速层有几个不受支持的绘图操作,即包括setShadowLayerand BlurMaskFilter,如果性能对您来说不是问题,您可以像往常一样禁用它:

if (SDK_INT >= HONEYCOMB) {
  view.setLayerType(View.LAYER_TYPE_SOFTWARE, null);
}

setShadowLayer按照您已经尝试的方式使用:

somePaint.setShadowLayer(shadowSize, deltaX, deltaY, shadowColor);

如需样品,请查看最后的链接。

如果您仍然想要硬件加速,您将不得不冒着过度绘制的风险来伪造它,您可以使用径向渐变或自己绘制另一个椭圆模糊(如前所述不能使用BlurMaskFilter)或使用预模糊Bitmap(更多掩蔽)。

对于这样一个微妙的阴影,如果需要性能,我宁愿平淡,完整的酱汁在香蕉架上

更新:从 L 开始,您可以使用真正的阴影

于 2013-07-29T01:53:47.557 回答
3

在此处输入图像描述

           ImageView imageView=findViewById(R.id.iv);
                    Bitmap icon = BitmapFactory.decodeResource(getResources(), R.drawable.images);
                    imageView.setImageBitmap(doHighlightImage(icon));   


           public static Bitmap doHighlightImage(Bitmap src) {
                    Bitmap bmOut = Bitmap.createBitmap(src.getWidth() + 96, src.getHeight() + 96, Bitmap.Config.ARGB_8888);
                    Canvas canvas = new Canvas(bmOut);
                    canvas.drawColor(0, Mode.CLEAR);
                    Paint ptBlur = new Paint();
                    ptBlur.setMaskFilter(new BlurMaskFilter(15, BlurMaskFilter.Blur.NORMAL));
                    int[] offsetXY = new int[2];
                    Bitmap bmAlpha = src.extractAlpha(ptBlur, offsetXY);
                    Paint ptAlphaColor = new Paint();
                    ptAlphaColor.setColor(Color.BLACK);
                    canvas.drawBitmap(bmAlpha, offsetXY[0], offsetXY[1], ptAlphaColor);
                    bmAlpha.recycle();
                    canvas.drawBitmap(src, 0, 0, null);
                    return bmOut;
                }
于 2018-01-27T05:23:33.950 回答
2

在 drawable 文件夹中创建一个名为 round_shape.xml 的 xml

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="oval">

    <stroke
        android:width="1dp"
        android:color="#bebebe" />
</shape>

将此round_shape设置为图像视图的背景,如下所示

<ImageView
     android:id="@+id/img_profile"
     android:layout_width="120dp"
     android:layout_height="120dp"
     android:padding="2dp"
     android:scaleType="fitXY"
     android:src="@drawable/camera" />

上面的代码在你圆了位图之后在图像视图周围创建了一个薄层,下面的函数会这样做

public Bitmap roundBit(Bitmap bm) {

        Bitmap circleBitmap = Bitmap.createBitmap(bm.getWidth(),
                bm.getHeight(), Bitmap.Config.ARGB_8888);

        BitmapShader shader = new BitmapShader(bm, TileMode.CLAMP,
                TileMode.CLAMP);
        Paint paint = new Paint();
        paint.setShader(shader);
        paint.setAntiAlias(true);
        Canvas c = new Canvas(circleBitmap);
        c.drawCircle(bm.getWidth() / 2, bm.getHeight() / 2, bm.getWidth() / 2,
                paint);

        return circleBitmap;
}
于 2014-11-14T07:55:35.783 回答
1

这是我对 sharmitha 答案的修改。它是 Kotlin,它使用 bmAlpha 的大小作为结果位图,这样阴影就不会被裁剪。

private val metrics: DisplayMetrics by lazy {
    val metrics = DisplayMetrics()
    val manager = context.getSystemService(Context.WINDOW_SERVICE) as WindowManager
    manager.defaultDisplay.getMetrics(metrics)
    metrics
}

private fun withDensity(value: Float): Float = metrics.density * value

private fun addShadow(src: Bitmap, blurRadius: Float, @ColorInt shadowColor: Int): Bitmap {
    val offsetXY = IntArray(2)
    val bmAlpha = src.extractAlpha(
            Paint().apply { maskFilter = BlurMaskFilter(withDensity(blurRadius), BlurMaskFilter.Blur.NORMAL) },
            offsetXY
    )

    val bmOut = Bitmap.createBitmap(bmAlpha.width, bmAlpha.height, Bitmap.Config.ARGB_8888)

    Canvas(bmOut).apply {
        drawColor(0, PorterDuff.Mode.CLEAR)
        drawBitmap(
                bmAlpha,
                0f,
                0f,
                Paint().apply { color = shadowColor })
        drawBitmap(
                src,
                0f - offsetXY[0].toFloat(),
                0f - offsetXY[1].toFloat(),
                null)
    }

    bmAlpha.recycle()

    return bmOut
}
于 2021-02-16T10:38:09.917 回答