D'accord, j'ai lu et cherché partout, et je me cogne maintenant la tête contre le mur pour essayer de comprendre. Voici ce que j'ai jusqu'à présent:
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);
}
}
Les "+5" dans les mesures sont là comme temporaires; D'après ce que j'ai compris, il faudrait que je fasse des calculs pour déterminer la taille que l'ombre portée ajoute à la toile, n'est-ce pas?
Mais quand j'utilise ceci:
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;
}
dans mon ImageView, je n'ai toujours qu'un ImageView normal lorsque je lance le programme.
Des pensées? Merci.
EDIT: J'ai donc parlé à RomainGuy, certains dans le canal IRC, et je le fais maintenant fonctionner pour les images rectangulaires simples avec le code ci-dessous. Cependant, cela ne permet pas de dessiner directement l'ombre sur la transparence de mon bitmap, donc je travaille toujours là-dessus.
@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);
}
D'accord, je ne prévois plus de réponses à ce sujet, alors ce que j'ai fini par aller pour le moment n'est qu'une solution pour les images rectangulaires. J'ai utilisé le NinePatch suivant:
avec le remplissage approprié 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"
/>
pour obtenir un assez bon résultat:
Pas idéal, mais ça ira.
Ceci est tiré de la présentation de Romain Guy à Devoxx, pdf found 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);
J'espère que cela t'aides.
REMARQUES
Je crois que cette réponse 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>
Ma solution sale:
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;
}
résultat:
Vous voilà. Définissez la source de ImageView de manière statique en xml ou de manière dynamique en code.
L'ombre est ici blanche.
<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>
Je parviens à appliquer une bordure dégradée à l'aide de ce code.
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;
}
j'espère que cela t'aides !
Cela fonctionne pour moi ...
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;
} ... }
Voici la mise en œuvre de Paul Burke s réponse:
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: Exécuter setLayerType(LAYER_TYPE_SOFTWARE, mShadow);
uniquement si le niveau de l'API est> 10
Utilisez cette classe pour dessiner une ombre sur des 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;
}
}
J'ai mis à profit la réponse ci-dessus - https://stackoverflow.com/a/11155031/2060486 - pour créer une ombre autour de TOUS les côtés.
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;
}
Changer la couleur dans le const comme bon vous semble.