如何在圆形imageView android上添加阴影和边框?
Posted
技术标签:
【中文标题】如何在圆形imageView android上添加阴影和边框?【英文标题】:How to add a shadow and a border on circular imageView android? 【发布时间】:2013-07-13 09:04:14 【问题描述】:我用这个问题创建了一个 CircularImageView:Create circular image view in android
在GitHub上下载项目
1) 这是 CircularImageView 类:
public class CircularImageView extends ImageView
public CircularImageView(Context context)
super(context);
public CircularImageView(Context context, AttributeSet attrs)
super(context, attrs);
public CircularImageView(Context context, AttributeSet attrs, int defStyle)
super(context, attrs, defStyle);
@Override
protected void onDraw(Canvas canvas)
Drawable drawable = getDrawable();
if (drawable == null)
return;
if (getWidth() == 0 || getHeight() == 0)
return;
Bitmap b = ((BitmapDrawable)drawable).getBitmap() ;
Bitmap bitmap = b.copy(Bitmap.Config.ARGB_8888, true);
Bitmap roundBitmap = getCroppedBitmap(bitmap, getWidth());
canvas.drawBitmap(roundBitmap, 0, 0, null);
public static Bitmap getCroppedBitmap(Bitmap bmp, int radius)
Bitmap sbmp;
if(bmp.getWidth() != radius || bmp.getHeight() != radius)
sbmp = Bitmap.createScaledBitmap(bmp, radius, radius, false);
else
sbmp = bmp;
Bitmap output = Bitmap.createBitmap(sbmp.getWidth(), sbmp.getHeight(), Bitmap.Config.ARGB_8888);
final Rect rect = new Rect(0, 0, sbmp.getWidth(), sbmp.getHeight());
Paint paint = new Paint();
paint.setAntiAlias(true);
paint.setFilterBitmap(true);
paint.setDither(true);
paint.setColor(Color.parseColor("#BAB399"));
Canvas c = new Canvas(output);
c.drawARGB(0, 0, 0, 0);
c.drawCircle(sbmp.getWidth() / 2+0.7f, sbmp.getHeight() / 2+0.7f, sbmp.getWidth() / 2+0.1f, paint);
paint.setXfermode(new PorterDuffXfermode(Mode.SRC_IN));
c.drawBitmap(sbmp, rect, rect, paint);
return output;
2) 我在我的布局中这样使用:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_
android:layout_
android:background="#cccccc"
android:gravity="center"
android:orientation="vertical"
android:padding="10dp" >
<com.mikhaellopez.circularimageview.CircularImageView
android:id="@+id/imageViewCircular"
android:layout_
android:layout_
android:layout_gravity="center"
android:background="@drawable/border"
android:src="@drawable/image" />
</LinearLayout>
3) 图片中的当前结果:
如何更改此代码以在我的 imageView 周围添加阴影和圆形边框?
Objectif 结果:
2015 年 10 月 15 日编辑:
您可以通过 gradle 依赖项 使用或下载我的 GitHub 库 CircularImageView 以及所有修复:
compile 'com.mikhaellopez:circularimageview:2.0.1'
【问题讨论】:
我不知道你在做什么样的应用,但它看起来很棒 @lopez.mikhael 您的代码有效,而且非常棒!但是可以在宽度和高度上使用 wrap_content 吗?当我尝试时它崩溃了。 @DanielNazareth 你说得对,目前无法在宽度和高度上使用 wrap_content。我还没来得及改变它。麻烦来自我使用图像的尺寸来绘制圆圈。使用 wrap_content 我会丢失此信息。该问题将得到解决,我会警告你。 @lopez.mikhael 你能在这个库上修复内存湖吗?我认为这个问题适用于 android 6 【参考方案1】:在绘制实际图像之前,只需使用具有更多宽度和高度的 drawCircle() 方法。根据您的意愿增加该新方法调用中的宽度和高度,并在油漆上设置一些您想要的其他颜色
【讨论】:
我用我的边框颜色做了第一个圆圈。然后我创建了第二个较小的圆圈,它将包含我的图像,它可以工作。但是,我的第二个较小的圆圈并不以我的第一个为中心。我该怎么做? 写这两个圆的中心和半径,它们的中心点应该相同 阴影可以使用paint.setShadowLayer(float radius, float dx, float dy, int color)【参考方案2】:-
添加
canvas.drawCircle(getWidth() / 2, getWidth() / 2, getWidth() / 2, paint);
前
canvas.drawBitmap(roundBitmap, 0, 0, null);
改变
c.drawCircle(sbmp.getWidth() / 2, sbmp.getHeight() / 2, sbmp.getWidth() / 2, paint);
到
c.drawCircle(sbmp.getWidth() / 2, sbmp.getHeight() / 2, sbmp.getWidth() / 2 - "the border with you prefer", paint);
希望对你有帮助。
也许是更好的解决方案here。
【讨论】:
很好,边界工作。它缺少阴影效果,你有什么想法吗?【参考方案3】:创建一个自定义可绘制对象,并使用它来定义 ImageView 的背景属性。您可以使用 LayeredDrawable,为组件创建任意数量的不同组件。
查看这个答案,它会创建一个自定义的 Rectangle(但与 Oval\Circle 完全相同):How to create Google + cards UI in a list view?
【讨论】:
【参考方案4】:我修改了CircularImageView found here 来实现你想要的。
要在边框周围创建阴影,我只使用了以下两条线:
this.setLayerType(LAYER_TYPE_SOFTWARE, paintBorder);
paintBorder.setShadowLayer(4.0f, 0.0f, 2.0f, Color.BLACK);
由于 HoneyComb 及更高版本的硬件加速,您需要 setLayerType
。当我尝试它时,它没有它是行不通的。
这里是完整的代码:
import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapShader;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Shader;
import android.graphics.drawable.BitmapDrawable;
import android.util.AttributeSet;
import android.widget.ImageView;
public class CircularImageView extends ImageView
private int borderWidth = 4;
private int viewWidth;
private int viewHeight;
private Bitmap image;
private Paint paint;
private Paint paintBorder;
private BitmapShader shader;
public CircularImageView(Context context)
super(context);
setup();
public CircularImageView(Context context, AttributeSet attrs)
super(context, attrs);
setup();
public CircularImageView(Context context, AttributeSet attrs, int defStyle)
super(context, attrs, defStyle);
setup();
private void setup()
// init paint
paint = new Paint();
paint.setAntiAlias(true);
paintBorder = new Paint();
setBorderColor(Color.WHITE);
paintBorder.setAntiAlias(true);
this.setLayerType(LAYER_TYPE_SOFTWARE, paintBorder);
paintBorder.setShadowLayer(4.0f, 0.0f, 2.0f, Color.BLACK);
public void setBorderWidth(int borderWidth)
this.borderWidth = borderWidth;
this.invalidate();
public void setBorderColor(int borderColor)
if (paintBorder != null)
paintBorder.setColor(borderColor);
this.invalidate();
private void loadBitmap()
BitmapDrawable bitmapDrawable = (BitmapDrawable) this.getDrawable();
if (bitmapDrawable != null)
image = bitmapDrawable.getBitmap();
@SuppressLint("DrawAllocation")
@Override
public void onDraw(Canvas canvas)
// load the bitmap
loadBitmap();
// init shader
if (image != null)
shader = new BitmapShader(Bitmap.createScaledBitmap(image, canvas.getWidth(), canvas.getHeight(), false), Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
paint.setShader(shader);
int circleCenter = viewWidth / 2;
// circleCenter is the x or y of the view's center
// radius is the radius in pixels of the cirle to be drawn
// paint contains the shader that will texture the shape
canvas.drawCircle(circleCenter + borderWidth, circleCenter + borderWidth, circleCenter + borderWidth - 4.0f, paintBorder);
canvas.drawCircle(circleCenter + borderWidth, circleCenter + borderWidth, circleCenter - 4.0f, paint);
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
int width = measureWidth(widthMeasureSpec);
int height = measureHeight(heightMeasureSpec, widthMeasureSpec);
viewWidth = width - (borderWidth * 2);
viewHeight = height - (borderWidth * 2);
setMeasuredDimension(width, height);
private int measureWidth(int measureSpec)
int result = 0;
int specMode = MeasureSpec.getMode(measureSpec);
int specSize = MeasureSpec.getSize(measureSpec);
if (specMode == MeasureSpec.EXACTLY)
// We were told how big to be
result = specSize;
else
// Measure the text
result = viewWidth;
return result;
private int measureHeight(int measureSpecHeight, int measureSpecWidth)
int result = 0;
int specMode = MeasureSpec.getMode(measureSpecHeight);
int specSize = MeasureSpec.getSize(measureSpecHeight);
if (specMode == MeasureSpec.EXACTLY)
// We were told how big to be
result = specSize;
else
// Measure the text (beware: ascent is a negative number)
result = viewHeight;
return (result + 2);
希望对你有帮助!
.
编辑
我分叉了您的 CircularImageView 并添加了对选择器覆盖的支持。我还显着提高了绘图性能...
https://github.com/Pkmmte/CircularImageView
【讨论】:
有没有办法将阴影添加到 RoundedImageView github.com/vinc3m1/RoundedImageView ? 伟大的解决方案 - 实现梦想。不过,它似乎并没有保持矩形图像的纵横比。 你能帮我给多边形、星星等不同的形状添加阴影吗? 影子的api让我很困惑。它是真还是假,但是如何设置宽度、位置等? (设置为 true 不会为我绘制任何阴影) 如果我不希望我的图像的角落因为这个圆形背景而被裁剪【参考方案5】:通过将ImageView
制作成圆形来添加边框,我做了一个简单的事情,我使用这个类将我的图像制作成圆形
package com.fidenz.fexceller.fexceller;
/**
* Created by Chathu Hettiarachchi on 5/18/2015.
*/
import android.graphics.Bitmap;
import android.graphics.BitmapShader;
import android.graphics.Canvas;
import android.graphics.ColorFilter;
import android.graphics.Paint;
import android.graphics.PixelFormat;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.Shader;
import android.graphics.drawable.Drawable;
public class RoundedImg extends Drawable
private final Bitmap mBitmap;
private final Paint mPaint;
private final RectF mRectF;
private final int mBitmapWidth;
private final int mBitmapHeight;
public RoundedImg(Bitmap bitmap)
mBitmap = bitmap;
mRectF = new RectF();
mPaint = new Paint();
mPaint.setAntiAlias(true);
mPaint.setDither(true);
final BitmapShader shader = new BitmapShader(bitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
mPaint.setShader(shader);
mBitmapWidth = mBitmap.getWidth();
mBitmapHeight = mBitmap.getHeight();
@Override
public void draw(Canvas canvas)
canvas.drawOval(mRectF, mPaint);
@Override
protected void onBoundsChange(Rect bounds)
super.onBoundsChange(bounds);
mRectF.set(bounds);
@Override
public void setAlpha(int alpha)
if (mPaint.getAlpha() != alpha)
mPaint.setAlpha(alpha);
invalidateSelf();
@Override
public void setColorFilter(ColorFilter cf)
mPaint.setColorFilter(cf);
@Override
public int getOpacity()
return PixelFormat.TRANSLUCENT;
@Override
public int getIntrinsicWidth()
return mBitmapWidth;
@Override
public int getIntrinsicHeight()
return mBitmapHeight;
public void setAntiAlias(boolean aa)
mPaint.setAntiAlias(aa);
invalidateSelf();
@Override
public void setFilterBitmap(boolean filter)
mPaint.setFilterBitmap(filter);
invalidateSelf();
@Override
public void setDither(boolean dither)
mPaint.setDither(dither);
invalidateSelf();
public Bitmap getBitmap()
return mBitmap;
通过在onCreate
上使用它,我调用了图像进行设置,
profilePic = (ImageView)findViewById(R.id.img_home_profile_pic);
Bitmap bm = BitmapFactory.decodeResource(getResources(), R.drawable.no_image);
roundedImage = new RoundedImg(bm);
profilePic.setImageDrawable(roundedImage);
为了添加边框,我创建了一个像这样的圆形 XML,
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="oval" >
<gradient android:startColor="@color/ring_color" android:endColor="@color/ring_color"
android:angle="270"/>
</shape>
然后使用布局我添加了一个RelativeLayout
和ImageView
在里面,通过使用填充和背景可绘制wrap_content
我设置我的RelativeLayout
像这样
<RelativeLayout
android:layout_
android:layout_
android:id="@+id/lay_rel_img"
android:layout_gravity="center"
android:padding="5dp"
android:background="@drawable/circle">
<ImageView
android:layout_
android:layout_
android:layout_gravity="center"
android:id="@+id/img_home_profile_pic"
android:src="@drawable/no_image"
android:layout_centerHorizontal="true"/>
</RelativeLayout>
现在是这样的,我不知道加阴影,也很抱歉
【讨论】:
这是一个很好的解决方案,谢谢,我会试试的。 相对布局中的 dat 填充令人大开眼界【参考方案6】:我找到了一个完全按照您的意愿工作的库,对我来说工作得很好。 看看这个。 https://android-arsenal.com/details/1/932
【讨论】:
【参考方案7】:这个类是带有阴影、描边、饱和度的自定义圆形图像视图,使用这个自定义圆形图像视图,您可以使您的图像具有半径的圆形形状。圆形阴影ImageView的家伙不需要Github这个类就足够了。
将 CircularImageView 添加到您的布局中
// 位图 myimage=BitmapFactory.decodeResource(getResources(),R.drawable.pic); CircularImageView c=new CircularImageView(this,screen width,screen height,Bitmap myimage); yourLayout.addView(c);**
public class CircularImageView extends android.support.v7.widget.AppCompatImageView
private final Context context;
private final int width, height;
private final Paint paint;
private final Paint paintBorder,imagePaint;
private final Bitmap bitmap2;
private final Paint paint3;
private Bitmap bitmap;
private BitmapShader shader;
private float radius = 4.0f;
float x = 0.0f;
float y = 8.0f;
private float stroke;
private float strokeWidth = 0.0f;
private Bitmap bitmap3;
private int corner_radius=50;
public CircularImageView(Context context, int width, int height, Bitmap bitmap)
super(context);
this.context = context;
this.width = width;
this.height = height;
//here "bitmap" is the square shape(width* width) scaled bitmap ..
this.bitmap = bitmap;
paint = new Paint(Paint.ANTI_ALIAS_FLAG);
paint.setAntiAlias(true);
paint.setFilterBitmap(true);
paint.setDither(true);
paint3=new Paint();
paint3.setStyle(Paint.Style.STROKE);
paint3.setColor(Color.WHITE);
paint3.setAntiAlias(true);
paintBorder = new Paint();
imagePaint= new Paint();
paintBorder.setColor(Color.WHITE);
paintBorder.setAntiAlias(true);
this.setLayerType(LAYER_TYPE_SOFTWARE, paintBorder);
this.bitmap2 = Bitmap.createScaledBitmap(bitmap, (bitmap.getWidth() - 40), (bitmap.getHeight() - 40), true);
imagePaint.setAntiAlias(true);
invalidate();
@Override
protected void onDraw(Canvas canvas)
super.onDraw(canvas);
Shader b;
if (bitmap3 != null)
b = new BitmapShader(bitmap3, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
else
b = new BitmapShader(bitmap2, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
imagePaint.setShader(b);
canvas.drawBitmap(maskedBitmap(), 20, 20, null);
private Bitmap maskedBitmap()
Bitmap l1 = Bitmap.createBitmap(width,width, Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(l1);
paintBorder.setShadowLayer(radius, x, y, Color.parseColor("#454645"));
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
final RectF rect = new RectF();
rect.set(20, 20, bitmap2.getWidth(), bitmap2.getHeight());
canvas.drawRoundRect(rect, corner_radius, corner_radius, paintBorder);
canvas.drawRoundRect(rect, corner_radius, corner_radius, imagePaint);
if (strokeWidth!=0.0f)
paint3.setStrokeWidth(strokeWidth);
canvas.drawRoundRect(rect, corner_radius, corner_radius, paint3);
paint.setXfermode(null);
return l1;
// use seekbar here, here you have to pass "0 -- 250" here corner radius will change
public void setCornerRadius(int corner_radius)
this.corner_radius = corner_radius;
invalidate();
-------->use seekbar here, here you have to pass "0 -- 10.0f" here shadow radius will change
public void setShadow(float radius)
this.radius = radius;
invalidate();
// use seekbar here, here you have to pass "0 -- 10.0f" here stroke size will change
public void setStroke(float stroke)
this.strokeWidth = stroke;
invalidate();
private Bitmap updateSat(Bitmap src, float settingSat)
int w = src.getWidth();
int h = src.getHeight();
Bitmap bitmapResult =
Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
Canvas canvasResult = new Canvas(bitmapResult);
Paint paint = new Paint();
ColorMatrix colorMatrix = new ColorMatrix();
colorMatrix.setSaturation(settingSat);
ColorMatrixColorFilter filter = new ColorMatrixColorFilter(colorMatrix);
paint.setColorFilter(filter);
canvasResult.drawBitmap(src, 0, 0, paint);
return bitmapResult;
// use seekbar here, here you have to pass "0 -- 2.0f" here saturation will change
public void setSaturation(float sat)
System.out.println("qqqqqqqqqq "+sat);
bitmap3=updateSat(bitmap2, sat);
invalidate();
// Seekbar to change radius
radius_seekbar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener()
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser)
text_radius.setText(""+progress);
circularImageView.setCornerRadius(progress);
@Override
public void onStartTrackingTouch(SeekBar seekBar)
@Override
public void onStopTrackingTouch(SeekBar seekBar)
);
// Seekbar to change shadow
shadow_seekbar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener()
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser)
float f= 4+progress/10.0f;
text_shadow.setText(""+progress);
circularImageView.setShadow(f);
@Override
public void onStartTrackingTouch(SeekBar seekBar)
@Override
public void onStopTrackingTouch(SeekBar seekBar)
);
// Seekbar to change saturation
saturation_seekbar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener()
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser)
int progressSat = saturation_seekbar.getProgress();
float sat = (float) ((progressSat*4 / 100.0f)-1.0f);
circularImageView.setSaturation(sat);
text_saturation.setText(""+progressSat);
@Override
public void onStartTrackingTouch(SeekBar seekBar)
@Override
public void onStopTrackingTouch(SeekBar seekBar)
);
// Seekbar to change stroke
stroke_seekbar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener()
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser)
if (progress==0)
float f=(progress*10.0f/100.0f);
circularImageView.setStroke(f);
else
float f=(progress*10.0f/100.0f);
circularImageView.setStroke(f);
text_stroke.setText(""+progress);
@Override
public void onStartTrackingTouch(SeekBar seekBar)
@Override
public void onStopTrackingTouch(SeekBar seekBar)
);
//radius seekbar in xml file
<SeekBar
android:layout_
android:layout_gravity="center"
android:progress="50"
android:max="250"
android:id="@+id/radius_seekbar"
android:layout_ />
//saturation seekbar in xml file
<SeekBar
android:layout_
android:layout_gravity="center"
android:progress="50"
android:max="100"
android:id="@+id/saturation_seekbar"
android:layout_ />
//shadow seekbar in xml file
<SeekBar
android:layout_
android:layout_gravity="center"
android:progress="0"
android:max="100"
android:id="@+id/shadow_seekbar"
android:layout_ />
//stroke seekbar in xml file
<SeekBar
android:layout_
android:layout_gravity="center"
android:progress="0"
android:max="100"
android:id="@+id/stroke _seekbar"
android:layout_ />
【讨论】:
以上是关于如何在圆形imageView android上添加阴影和边框?的主要内容,如果未能解决你的问题,请参考以下文章
如何在 Android 中创建圆形 ImageView? [复制]