带投影的自定义ImageView

好吧,我一直在阅读,四处搜寻,现在正在把我的头撞在墙上试图弄清楚这一点。 以下是我到目前为止:

package com.pockdroid.sandbox; import android.content.Context; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.Rect; import android.widget.ImageView; public class ShadowImageView extends ImageView { private Rect mRect; private Paint mPaint; public ShadowImageView(Context context) { super(context); mRect = new Rect(); mPaint = new Paint(); mPaint.setAntiAlias(true); mPaint.setShadowLayer(2f, 1f, 1f, Color.BLACK); } @Override protected void onDraw(Canvas canvas) { Rect r = mRect; Paint paint = mPaint; canvas.drawRect(r, paint); super.onDraw(canvas); } @Override protected void onMeasure(int w, int h) { super.onMeasure(w,h); int mH, mW; mW = getSuggestedMinimumWidth() < getMeasuredWidth()? getMeasuredWidth() : getSuggestedMinimumWidth(); mH = getSuggestedMinimumHeight() < getMeasuredHeight()? getMeasuredHeight() : getSuggestedMinimumHeight(); setMeasuredDimension(mW + 5, mH + 5); } 

}

测量中的“+5”是暂时的; 根据我的理解,我需要做一些math来确定投影在canvas上的大小,对吧?

但是当我使用这个:

 public View getView(int position, View convertView, ViewGroup parent) { ShadowImageView sImageView; if (convertView == null) { sImageView = new ShadowImageView(mContext); GridView.LayoutParams lp = new GridView.LayoutParams(85, 85); sImageView.setLayoutParams(lp); sImageView.setScaleType(ImageView.ScaleType.CENTER); sImageView.setPadding(5,5,5,5); } else { sImageView = (ShadowImageView) convertView; } sImageView.setImageBitmap(bitmapList.get(position)); return sImageView; } 

在我的ImageView中,当我运行程序时,我仍然只是得到一个正常的ImageView。

有什么想法吗? 谢谢。

编辑:所以我谈到了一些在IRC频道的RomainGuy,我现在正在使用下面的代码纯色矩形图像工作。 尽pipe如此,它仍然不会直接影响我的位图的透明度,所以我仍然在努力。

 @Override protected void onDraw(Canvas canvas) { Bitmap bmp = BitmapFactory.decodeResource(getResources(), R.drawable.omen); Paint paint = new Paint(); paint.setAntiAlias(true); paint.setShadowLayer(5.5f, 6.0f, 6.0f, Color.BLACK); canvas.drawColor(Color.GRAY); canvas.drawRect(50, 50, 50 + bmp.getWidth(), 50 + bmp.getHeight(), paint); canvas.drawBitmap(bmp, 50, 50, null); } 

好的,我没有预测到这个问题会有更多的答案,所以现在我最终select的只是矩形图像的解决scheme。 我已经使用了以下NinePatch:

替代文字

以及XML中适当的填充:

 <ImageView android:id="@+id/image_test" android:background="@drawable/drop_shadow" android:layout_width="wrap_content" android:layout_height="wrap_content" android:paddingLeft="6px" android:paddingTop="4px" android:paddingRight="8px" android:paddingBottom="9px" android:src="@drawable/pic1" /> 

得到一个相当好的结果:

替代文字

不理想,但会做。

这是从Romain Guy在Devoxx上的演示文稿中取得的,pdf在这里find。

 Paint mShadow = new Paint(); // radius=10, y-offset=2, color=black mShadow.setShadowLayer(10.0f, 0.0f, 2.0f, 0xFF000000); // in onDraw(Canvas) canvas.drawBitmap(bitmap, 0.0f, 0.0f, mShadow); 

希望这可以帮助。

笔记

  1. 不要忘了蜂窝和以上你需要调用setLayerType(LAYER_TYPE_SOFTWARE, mShadow) ,否则你将不会看到你的影子! (@Dmitriy_Boichenko)
  2. SetShadowLayer不能使用硬件加速,所以大大降低了性能(@Matt Wear) [1] [2]

我相信UIFuel的这个答案

 <?xml version="1.0" encoding="utf-8"?> <layer-list xmlns:android="http://schemas.android.com/apk/res/android"> <!-- Drop Shadow Stack --> <item> <shape> <padding android:top="1dp" android:right="1dp" android:bottom="1dp" android:left="1dp" /> <solid android:color="#00CCCCCC" /> </shape> </item> <item> <shape> <padding android:top="1dp" android:right="1dp" android:bottom="1dp" android:left="1dp" /> <solid android:color="#10CCCCCC" /> </shape> </item> <item> <shape> <padding android:top="1dp" android:right="1dp" android:bottom="1dp" android:left="1dp" /> <solid android:color="#20CCCCCC" /> </shape> </item> <item> <shape> <padding android:top="1dp" android:right="1dp" android:bottom="1dp" android:left="1dp" /> <solid android:color="#30CCCCCC" /> </shape> </item> <item> <shape> <padding android:top="1dp" android:right="1dp" android:bottom="1dp" android:left="1dp" /> <solid android:color="#50CCCCCC" /> </shape> </item> <!-- Background --> <item> <shape> <solid android:color="@color/white" /> <corners android:radius="3dp" /> </shape> </item> </layer-list> 

我肮脏的解决

 private static Bitmap getDropShadow3(Bitmap bitmap) { if (bitmap==null) return null; int think = 6; int w = bitmap.getWidth(); int h = bitmap.getHeight(); int newW = w - (think); int newH = h - (think); Bitmap.Config conf = Bitmap.Config.ARGB_8888; Bitmap bmp = Bitmap.createBitmap(w, h, conf); Bitmap sbmp = Bitmap.createScaledBitmap(bitmap, newW, newH, false); Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG); Canvas c = new Canvas(bmp); // Right Shader rshader = new LinearGradient(newW, 0, w, 0, Color.GRAY, Color.LTGRAY, Shader.TileMode.CLAMP); paint.setShader(rshader); c.drawRect(newW, think, w, newH, paint); // Bottom Shader bshader = new LinearGradient(0, newH, 0, h, Color.GRAY, Color.LTGRAY, Shader.TileMode.CLAMP); paint.setShader(bshader); c.drawRect(think, newH, newW , h, paint); //Corner Shader cchader = new LinearGradient(0, newH, 0, h, Color.LTGRAY, Color.LTGRAY, Shader.TileMode.CLAMP); paint.setShader(cchader); c.drawRect(newW, newH, w , h, paint); c.drawBitmap(sbmp, 0, 0, null); return bmp; } 

结果: 在这里输入图像描述

这个给你。 在xml中静态设置ImageView的源代码,或者在代码中dynamic设置。

阴影在这里是白色的。

 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="wrap_content" android:layout_height="wrap_content"> <View android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="@android:color/white" android:layout_alignLeft="@+id/image" android:layout_alignRight="@id/image" android:layout_alignTop="@id/image" android:layout_alignBottom="@id/image" android:layout_marginLeft="10dp" android:layout_marginBottom="10dp" /> <ImageView android:id="@id/image" android:layout_width="wrap_content" android:layout_height="wrap_content" android:src="..." android:padding="5dp" /> </RelativeLayout> 

我设法使用此代码应用渐变边框..

 public static Bitmap drawShadow(Bitmap bitmap, int leftRightThk, int bottomThk, int padTop) { int w = bitmap.getWidth(); int h = bitmap.getHeight(); int newW = w - (leftRightThk * 2); int newH = h - (bottomThk + padTop); Bitmap.Config conf = Bitmap.Config.ARGB_8888; Bitmap bmp = Bitmap.createBitmap(w, h, conf); Bitmap sbmp = Bitmap.createScaledBitmap(bitmap, newW, newH, false); Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG); Canvas c = new Canvas(bmp); // Left int leftMargin = (leftRightThk + 7)/2; Shader lshader = new LinearGradient(0, 0, leftMargin, 0, Color.TRANSPARENT, Color.BLACK, TileMode.CLAMP); paint.setShader(lshader); c.drawRect(0, padTop, leftMargin, newH, paint); // Right Shader rshader = new LinearGradient(w - leftMargin, 0, w, 0, Color.BLACK, Color.TRANSPARENT, TileMode.CLAMP); paint.setShader(rshader); c.drawRect(newW, padTop, w, newH, paint); // Bottom Shader bshader = new LinearGradient(0, newH, 0, bitmap.getHeight(), Color.BLACK, Color.TRANSPARENT, TileMode.CLAMP); paint.setShader(bshader); c.drawRect(leftMargin -3, newH, newW + leftMargin + 3, bitmap.getHeight(), paint); c.drawBitmap(sbmp, leftRightThk, 0, null); return bmp; } 

希望这可以帮助 !

这适用于我…

 public class ShadowImage extends Drawable { Bitmap bm; @Override public void draw(Canvas canvas) { Paint mShadow = new Paint(); Rect rect = new Rect(0,0,bm.getWidth(), bm.getHeight()); mShadow.setAntiAlias(true); mShadow.setShadowLayer(5.5f, 4.0f, 4.0f, Color.BLACK); canvas.drawRect(rect, mShadow); canvas.drawBitmap(bm, 0.0f, 0.0f, null); } public ShadowImage(Bitmap bitmap) { super(); this.bm = bitmap; } ... } 

这里Paul Burke的实现答案是:

 public class ShadowImageView extends ImageView { public ShadowImageView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); } public ShadowImageView(Context context, AttributeSet attrs) { super(context, attrs); } public ShadowImageView(Context context) { super(context); } private Paint createShadow() { Paint mShadow = new Paint(); float radius = 10.0f; float xOffset = 0.0f; float yOffset = 2.0f; // color=black int color = 0xFF000000; mShadow.setShadowLayer(radius, xOffset, yOffset, color); return mShadow; } @Override protected void onDraw(Canvas canvas) { Paint mShadow = createShadow(); Drawable d = getDrawable(); if (d != null){ setLayerType(LAYER_TYPE_SOFTWARE, mShadow); Bitmap bitmap = ((BitmapDrawable) getDrawable()).getBitmap(); canvas.drawBitmap(bitmap, 0.0f, 0.0f, mShadow); } else { super.onDraw(canvas); } }; } 

TODO:执行setLayerType(LAYER_TYPE_SOFTWARE, mShadow); 只有当API级别> 10时

我已经build立在上面的答案 – https://stackoverflow.com/a/11155031/2060486 – 围绕所有方面创build一个阴影。

  private static final int GRAY_COLOR_FOR_SHADE = Color.argb(50, 79, 79, 79); // this method takes a bitmap and draws around it 4 rectangles with gradient to create a // shadow effect. public static Bitmap addShadowToBitmap(Bitmap origBitmap) { int shadowThickness = 13; // can be adjusted as needed int bmpOriginalWidth = origBitmap.getWidth(); int bmpOriginalHeight = origBitmap.getHeight(); int bigW = bmpOriginalWidth + shadowThickness * 2; // getting dimensions for a bigger bitmap with margins int bigH = bmpOriginalHeight + shadowThickness * 2; Bitmap containerBitmap = Bitmap.createBitmap(bigW, bigH, Bitmap.Config.ARGB_8888); Bitmap copyOfOrigBitmap = Bitmap.createScaledBitmap(origBitmap, bmpOriginalWidth, bmpOriginalHeight, false); Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG); Canvas canvas = new Canvas(containerBitmap); // drawing the shades on the bigger bitmap //right shade - direction of gradient is positive x (width) Shader rightShader = new LinearGradient(bmpOriginalWidth, 0, bigW, 0, GRAY_COLOR_FOR_SHADE, Color.TRANSPARENT, Shader.TileMode.CLAMP); paint.setShader(rightShader); canvas.drawRect(bigW - shadowThickness, shadowThickness, bigW, bigH - shadowThickness, paint); //bottom shade - direction is positive y (height) Shader bottomShader = new LinearGradient(0, bmpOriginalHeight, 0, bigH, GRAY_COLOR_FOR_SHADE, Color.TRANSPARENT, Shader.TileMode.CLAMP); paint.setShader(bottomShader); canvas.drawRect(shadowThickness, bigH - shadowThickness, bigW - shadowThickness, bigH, paint); //left shade - direction is negative x Shader leftShader = new LinearGradient(shadowThickness, 0, 0, 0, GRAY_COLOR_FOR_SHADE, Color.TRANSPARENT, Shader.TileMode.CLAMP); paint.setShader(leftShader); canvas.drawRect(0, shadowThickness, shadowThickness, bigH - shadowThickness, paint); //top shade - direction is negative y Shader topShader = new LinearGradient(0, shadowThickness, 0, 0, GRAY_COLOR_FOR_SHADE, Color.TRANSPARENT, Shader.TileMode.CLAMP); paint.setShader(topShader); canvas.drawRect(shadowThickness, 0, bigW - shadowThickness, shadowThickness, paint); // starting to draw bitmap not from 0,0 to get margins for shade rectangles canvas.drawBitmap(copyOfOrigBitmap, shadowThickness, shadowThickness, null); return containerBitmap; } 

按照您认为合适的方式更改常量中的颜色。

使用这个类来在位图上绘制阴影

 public class ShadowGenerator { // Percent of actual icon size private static final float HALF_DISTANCE = 0.5f; public static final float BLUR_FACTOR = 0.5f/48; // Percent of actual icon size private static final float KEY_SHADOW_DISTANCE = 1f/48; public static final int KEY_SHADOW_ALPHA = 61; public static final int AMBIENT_SHADOW_ALPHA = 30; private static final Object LOCK = new Object(); // Singleton object guarded by {@link #LOCK} private static ShadowGenerator sShadowGenerator; private int mIconSize; private final Canvas mCanvas; private final Paint mBlurPaint; private final Paint mDrawPaint; private final Context mContext; private ShadowGenerator(Context context) { mContext = context; mIconSize = Utils.convertDpToPixel(context,63); mCanvas = new Canvas(); mBlurPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG); mBlurPaint.setMaskFilter(new BlurMaskFilter(mIconSize * BLUR_FACTOR, Blur.NORMAL)); mDrawPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG); } public synchronized Bitmap recreateIcon(Bitmap icon) { mIconSize = Utils.convertDpToPixel(mContext,3)+icon.getWidth(); int[] offset = new int[2]; Bitmap shadow = icon.extractAlpha(mBlurPaint, offset); Bitmap result = Bitmap.createBitmap(mIconSize, mIconSize, Config.ARGB_8888); mCanvas.setBitmap(result); // Draw ambient shadow mDrawPaint.setAlpha(AMBIENT_SHADOW_ALPHA); mCanvas.drawBitmap(shadow, offset[0], offset[1], mDrawPaint); // Draw key shadow mDrawPaint.setAlpha(KEY_SHADOW_ALPHA); mCanvas.drawBitmap(shadow, offset[0], offset[1] + KEY_SHADOW_DISTANCE * mIconSize, mDrawPaint); // Draw the icon mDrawPaint.setAlpha(255); mCanvas.drawBitmap(icon, 0, 0, mDrawPaint); mCanvas.setBitmap(null); return result; } public static ShadowGenerator getInstance(Context context) { synchronized (LOCK) { if (sShadowGenerator == null) { sShadowGenerator = new ShadowGenerator(context); } } return sShadowGenerator; } }