android override imageview dropshadow

android - Custom ImageView con sombra paralela



override dropshadow (10)

Aquí estás. Establezca la fuente de ImageView estáticamente en xml o dinámicamente en el código.

Shadow está aquí blanco.

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

De acuerdo, he estado leyendo y buscando, y ahora estoy golpeando mi cabeza contra la pared tratando de resolver esto. Esto es lo que tengo hasta ahora:

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

}

El "+5" en las mediciones está allí como temporal; Por lo que entiendo, tendré que hacer algunos cálculos para determinar el tamaño que la sombra paralela agrega al lienzo, ¿no?

Pero cuando uso esto:

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

en mi ImageView, todavía obtengo solo un ImageView normal cuando ejecuto el programa.

¿Alguna idea? Gracias.

EDITAR: Así que hablé con RomainGuy en el canal de IRC, y lo tengo trabajando ahora para imágenes rectangulares con el siguiente código. Sin embargo, todavía no dibujará la sombra directamente en la transparencia de mi mapa de bits, así que todavía estoy trabajando en eso.

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


Aquí la implementación de la respuesta de 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: ejecuta setLayerType(LAYER_TYPE_SOFTWARE, mShadow); solo si el nivel API es> 10


Creo que esta respuesta de 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>


De acuerdo, no preveo más respuestas en este caso, por lo que terminé yendo por ahora es solo una solución para imágenes rectangulares. He usado el siguiente NinePatch:



junto con el relleno adecuado en 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" />

para obtener un resultado bastante bueno:



No es ideal, pero servirá.


Esto funciona para mí ...

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


Esto se toma de la presentación de Romain Guy en Devoxx, pdf que se encuentra here .

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

Espero que esto ayude.

NOTAS

  1. No te olvides de Honeycomb y superior, necesitas invocar setLayerType(LAYER_TYPE_SOFTWARE, mShadow) , de lo contrario no verás tu sombra. (@Dmitriy_Boichenko)
  2. SetShadowLayer no funciona desafortunadamente con la aceleración de hardware por lo que reduce enormemente el rendimiento (@Matt Wear) [1] [2]

Me he basado en la respuesta anterior - https://.com/a/11155031/2060486 - para crear una sombra en TODOS los lados ...

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

Cambie el color en la const como mejor le parezca.


Me las arreglé para aplicar un borde degradado usando este código.

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

espero que esto ayude !


Mi solución sucia:

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

resultado:


Usa esta clase para dibujar sombras en bitmaps

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