2013-07-15 148 views
55

我创建了一个CircularImageView这个问题:Create circular image view in android如何在圆形图像上添加阴影和边框androidView?

下载项目上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_width="match_parent" 
    android:layout_height="match_parent" 
    android:background="#cccccc" 
    android:gravity="center" 
    android:orientation="vertical" 
    android:padding="10dp" > 

    <com.mikhaellopez.circularimageview.CircularImageView 
     android:id="@+id/imageViewCircular" 
     android:layout_width="@dimen/image_view_size" 
     android:layout_height="@dimen/image_view_size" 
     android:layout_gravity="center" 
     android:background="@drawable/border" 
     android:src="@drawable/image" /> 

</LinearLayout> 

3)当前结果图片:

Current result

如何改变这种代码有一个影子在我的ImageView圆形边界?

的Objectif结果:

Objectif result


编辑2015年10月15日:

您可以使用或下载我的GitHub库CircularImageView所有修补程序通过使用gradle depend ency

compile 'com.mikhaellopez:circularimageview:2.0.1' 
+16

我不知道你在做什么样的应用程序,但它看起来很棒 – Jameo

+0

@ lopez.mikhael你的代码有效,它非常好!但是它有可能在宽度和高度上使用wrap_content?我尝试过时会崩溃。 –

+0

@DanielNazareth你说得对,目前无法在宽度和高度上使用wrap_content。我没有时间去改变它。麻烦来自我使用图像的尺寸绘制圆圈。使用wrap_content我会丢失这些信息。问题会解决的,我会提醒你。 –

回答

69

我修改了CircularImageView found here达到你想要的东西。

要创建的边框阴影,我只是用这两条线:

this.setLayerType(LAYER_TYPE_SOFTWARE, paintBorder); 
paintBorder.setShadowLayer(4.0f, 0.0f, 2.0f, Color.BLACK); 

您需要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

+0

有没有办法将阴影添加到RoundedImageView https://github.com/vinc3m1/RoundedImageView? – toobsco42

+0

伟大的解决方案 - 实现梦想。它似乎并没有保持矩形图像的宽高比。 –

+0

你能帮我把阴影给像多边形,星星等不同的形状吗? – Dig

1

绘制的实际图像之前刚刚使用画圆()方法,更宽度和高度。根据你的愿望在新的方法调用增加的宽度和高度,并设置一些其他颜色的,你想在油漆

+0

我做了我的边界的颜色的第一个圆。然后我创建了第二个包含我的图像的小圆圈,它可以工作。然而,我的第二个小圈子并不是集中在我的第一个圈子上。我怎样才能做到这一点? –

+0

写出这两个圆的中心和半径,它们的中心点应该相同 –

+0

您是否有第一个解决方案的示例代码? –

2
  1. 添加 canvas.drawCircle(getWidth()/2, getWidth()/2, getWidth()/2, paint);canvas.drawBitmap(roundBitmap, 0, 0, null);
  2. 变化 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

+0

伟大的边界工作。它缺乏阴影效果,你会有一个想法? –

2

创建一个自定义drawable,并使用它来定义您的ImageView的背景属性。您可以使用LayeredDrawable,根据需要为组件创建许多不同的组件。

结帐这个答案,它创建了一个自定义的矩形(但究竟是用椭圆\圈相同):How to create Google + cards UI in a list view?

6

通过使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); 

添加边框IC reated圆形状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> 

然后使用布局我加入其内部ImageView的一个RelativeLayout的,通过使用填充和背景绘制与wrapcontent设置我相对布局这样

<RelativeLayout 
      android:layout_width="wrap_content" 
      android:layout_height="wrap_content" 
      android:id="@+id/lay_rel_img" 
      android:layout_gravity="center" 
      android:padding="5dp" 
      android:background="@drawable/circle"> 

      <ImageView 
       android:layout_width="150dp" 
       android:layout_height="150dp" 
       android:layout_gravity="center" 
       android:id="@+id/img_home_profile_pic" 
       android:src="@drawable/no_image" 
       android:layout_centerHorizontal="true"/> 

     </RelativeLayout> 

现在它表明这个样子,我不知道添加阴影,为此后悔过

enter image description here

+0

这是一个很好的解决方案谢谢你,我会尝试。 –