【问题标题】:Drawing an outer shadow when drawing an image绘制图像时绘制外阴影
【发布时间】:2013-07-22 09:00:28
【问题描述】:

我目前通过在画布上绘制来在我的应用程序中创建一个圆形版本的图像。我想在图像周围画一个微弱的外阴影,但我不能完全正确。我有两个问题: 1.如何绘制外阴影(我似乎只能绘制带有x或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]

这是我想要达到的效果的一个例子:

【问题讨论】:

  • @Leonidos 我现在附上了一个例子。您会注意到图像周围有一个微弱的外阴影。

标签: android android-canvas


【解决方案1】:

我想要类似的效果,但在 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);

 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;
}

【讨论】:

  • 感谢发布这样的答案,但阴影颜色不起作用。请给我建议。
  • @BalvinderSingh 如果您想就您的问题发布要点或其他内容,我很乐意为您提供帮助。如果您完全复制/粘贴我的代码,它应该可以正常工作...
  • 如果我在 Image 上应用 colorFilter 然后阴影出现在我应用到 image 的颜色中,但我想为阴影添加不同的颜色
  • @BalvinderSingh 您必须修改我的代码才能做到这一点,但应该可以。你看你现在可以传入阴影颜色了。像我一样先构建阴影层,然后在构建最终图像之前应用颜色过滤器。
  • 感谢您的回复,我试试看。
【解决方案2】:

我们来了

是的,我还在挖掘 Nexus S

首先,请停止以这种方式屏蔽位图,您无需分配另一个Bitmap,结帐this blog post about how to draw rounded (and actually any shape) images即可完成此操作。

第二次使用Drawable,您可能可以弄清楚如何添加阴影,只要确保它不会被剪裁,在 18 岁以上您可以使用 ViewOverlays,同时请记住 there are several unsupported drawing operations for hardware accelerated layers ,包括setShadowLayerBlurMaskFilter,如果性能对您来说不是问题,您可以像往常一样禁用它:

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

并使用setShadowLayer,就像你已经尝试过的那样:

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

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

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

对于这样一个微妙的阴影,如果需要性能,我宁愿平淡,the full sauce is in the banana stand

更新:Starting L you can use real shadows

【讨论】:

  • 您好,感谢您的回答和性能提示。不幸的是,我是 Android 新手,所以我发现外部阴影部分非常困难。如果可以请发布显示如何创建外阴影的代码(请参阅我附在问题中的图片)我将奖励您。
  • @RunLoop 我已经更新了我的答案,查看底部的链接
  • @EvelioTarazona 你能发布一个关于影子的样本吗?我知道你已经放了一个链接,但也请在这里放一些代码。
  • @androiddeveloper 是有道理的,我更喜欢使用 gist 作为 GitHub 的编辑器,即使是简单的编辑也比 SO 的要好得多,我已经更新了它,说明如何使用 setShadowLayer,希望对您有所帮助跨度>
  • @EvelioTarazona 嗨,我的代码有一些问题。当我调用 getBitMap 时,我仍然只是得到原始图像。是否可以在四舍五入后获得图像的位图。此外,阴影没有出现
【解决方案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;
                }

【讨论】:

  • 如何在顶部和左侧也添加阴影?
【解决方案4】:

在drawable文件夹中创建一个xml命名为round_shape.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>

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

<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;
}

【讨论】:

    【解决方案5】:

    这是我对 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
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-11-14
      • 2017-03-13
      • 2010-11-16
      • 2012-02-16
      • 1970-01-01
      • 1970-01-01
      • 2012-01-09
      • 1970-01-01
      相关资源
      最近更新 更多