ImageView personalizado con sombra

Bueno, he estado leyendo y buscando alrededor, y ahora estoy golpeando mi cabeza contra la pared tratando de averiguar 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án allí como temporales; De lo que entiendo necesitaré hacer un poco de matemáticas para determinar el tamaño que la sombra de gota agrega al lienzo, ¿verdad?

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, sigo recibiendo un ImageView normal cuando ejecuto el programa.

¿Alguna idea? Gracias.

EDIT: Así que hablé con RomainGuy algunos en el canal de IRC, y lo tengo trabajando ahora para imágenes rectangulares planas con el código a continuación. Aún así, no atraerá la sombra directamente a 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); } 

Bueno, no preveo más respuestas sobre este, así que lo que acabé por ir por ahora es sólo una solución para las imágenes rectangulares. He utilizado el siguiente NinePatch:

texto alternativo

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:

texto alternativo

No es ideal, pero lo hará.

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

 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 por encima de lo que necesita para invocar setLayerType(LAYER_TYPE_SOFTWARE, mShadow) , de lo contrario no verá su sombra! (@Dmitriy_Boichenko)
  2. SetShadowLayer no funciona con la aceleración de hardware por desgracia por lo que reduce en gran medida las prestaciones (desgaste @Matt) [1] [2]

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> 

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: Introduzca aquí la descripción de la imagen

Aquí estás. Establecer código fuente de ImageView de forma estática en xml o dinámicamente en código.

La sombra está aquí blanca.

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

Puedo aplicar gradiente de borde con 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 !

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

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); Sólo si el nivel API es> 10

He construido sobre la respuesta anterior – https://stackoverflow.com/a/11155031/2060486 – para crear una sombra alrededor de 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 el const como mejor le parezca.

  • ¿Debo llamar a super () al sustituir el constructor de AsyncTask?
  • OverridePendingTransition en el adaptador gridview
  • Error al invalidar el método toString
  • Android: ¿Por qué no puedo anular setFrame desde la vista?
  • Cómo reemplazar CursorAdapter bindView
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.