如何使圆angular的ImageView?
在Android中,默认情况下ImageView是一个矩形。 我怎样才能使它在ImageView中的一个圆angular的矩形(剪切掉我的位图的所有四个angular落是圆angular矩形)?
这是相当晚的回应,但对于正在寻找这个的其他人,您可以执行以下代码手动四舍五入您的图像的angular落。
这不是我的代码,但我已经使用它,它的作品奇妙。 我用它作为一个ImageHelper类中的助手,并扩展它只是为了传递给定图像所需的羽化量。
最终的代码如下所示:
package com.company.app.utils; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Paint; import android.graphics.PorterDuffXfermode; import android.graphics.Rect; import android.graphics.RectF; import android.graphics.Bitmap.Config; import android.graphics.PorterDuff.Mode; public class ImageHelper { public static Bitmap getRoundedCornerBitmap(Bitmap bitmap, int pixels) { Bitmap output = Bitmap.createBitmap(bitmap.getWidth(), bitmap .getHeight(), Config.ARGB_8888); Canvas canvas = new Canvas(output); final int color = 0xff424242; final Paint paint = new Paint(); final Rect rect = new Rect(0, 0, bitmap.getWidth(), bitmap.getHeight()); final RectF rectF = new RectF(rect); final float roundPx = pixels; paint.setAntiAlias(true); canvas.drawARGB(0, 0, 0, 0); paint.setColor(color); canvas.drawRoundRect(rectF, roundPx, roundPx, paint); paint.setXfermode(new PorterDuffXfermode(Mode.SRC_IN)); canvas.drawBitmap(bitmap, rect, rect, paint); return output; } }
希望这可以帮助别人!
虽然上面的答案有效,但是Romain Guy(一个核心的Android开发者)在他的博客中展示了一个更好的方法 ,通过使用着色器而不是创build位图的副本来减less内存。 function的一般要点在这里:
BitmapShader shader; shader = new BitmapShader(bitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP); Paint paint = new Paint(); paint.setAntiAlias(true); paint.setShader(shader); RectF rect = new RectF(0.0f, 0.0f, width, height); // rect contains the bounds of the shape // radius is the radius in pixels of the rounded corners // paint contains the shader that will texture the shape canvas.drawRoundRect(rect, radius, radius, paint);
这与其他方法的优点是它:
- 不会创build一个单独的位图副本,它使用大量图像的内存[vs大多数其他答案]
- 支持反锯齿 [vs clipPath方法]
- 支持alpha [vs xfermode + porterduff方法]
- 支持硬件加速 [vs clipPath method]
- 只画一次到canvas [vs xfermode和clippath方法]
我创build了一个基于此代码的RoundedImageView ,将此逻辑封装到ImageView中,并添加了适当的ScaleType
支持和可选的圆angular边框。
在支持库的v21中现在有一个解决scheme:它被称为RoundedBitmapDrawable 。
它基本上就像一个普通的Drawable,除了你用下面的方法给它一个angular点半径:
setCornerRadius(float cornerRadius)
所以,从Bitmap src
和一个目标ImageView
,它看起来像这样:
RoundedBitmapDrawable dr = RoundedBitmapDrawableFactory.create(res, src); dr.setCornerRadius(cornerRadius); imageView.setImageDrawable(dr);
我发现这两种方法对于提出一个可行的解决scheme都非常有帮助。 这是我的复合版本,这是独立的像素,并允许你有一些方形的angular落,其余的angular落具有相同的半径(这是通常的用例)。 感谢上面的两个解决scheme:
public static Bitmap getRoundedCornerBitmap(Context context, Bitmap input, int pixels , int w , int h , boolean squareTL, boolean squareTR, boolean squareBL, boolean squareBR ) { Bitmap output = Bitmap.createBitmap(w, h, Config.ARGB_8888); Canvas canvas = new Canvas(output); final float densityMultiplier = context.getResources().getDisplayMetrics().density; final int color = 0xff424242; final Paint paint = new Paint(); final Rect rect = new Rect(0, 0, w, h); final RectF rectF = new RectF(rect); //make sure that our rounded corner is scaled appropriately final float roundPx = pixels*densityMultiplier; paint.setAntiAlias(true); canvas.drawARGB(0, 0, 0, 0); paint.setColor(color); canvas.drawRoundRect(rectF, roundPx, roundPx, paint); //draw rectangles over the corners we want to be square if (squareTL ){ canvas.drawRect(0, h/2, w/2, h, paint); } if (squareTR ){ canvas.drawRect(w/2, h/2, w, h, paint); } if (squareBL ){ canvas.drawRect(0, 0, w/2, h/2, paint); } if (squareBR ){ canvas.drawRect(w/2, 0, w, h/2, paint); } paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN)); canvas.drawBitmap(input, 0,0, paint); return output; }
此外,我否认ImageView把这个,所以我可以在XML中定义它。 您可能想要添加一些超级调用在这里创build的逻辑,但是我已经评论过,因为这对我来说没有帮助。
@Override protected void onDraw(Canvas canvas) { //super.onDraw(canvas); Drawable drawable = getDrawable(); Bitmap b = ((BitmapDrawable)drawable).getBitmap() ; Bitmap bitmap = b.copy(Bitmap.Config.ARGB_8888, true); int w = getWidth(), h = getHeight(); Bitmap roundBitmap = CropImageView.getRoundedCornerBitmap( getContext(), bitmap,10 , w, h , true, false,true, false); canvas.drawBitmap(roundBitmap, 0,0 , null); }
希望这可以帮助!
圆形图像在这里使用ImageLoader
创buildDisplayImageOptions
:
DisplayImageOptions options = new DisplayImageOptions.Builder() // this will make circle, pass the width of image .displayer(new RoundedBitmapDisplayer(getResources().getDimensionPixelSize(R.dimen.image_dimen_menu))) .cacheOnDisc(true) .build(); imageLoader.displayImage(url_for_image,ImageView,options);
或者你也可以从Square购买Picasso
图书馆。
Picasso.with(mContext) .load(com.app.utility.Constants.BASE_URL+b.image) .placeholder(R.drawable.profile) .error(R.drawable.profile) .transform(new RoundedTransformation(50, 4)) .resizeDimen(R.dimen.list_detail_image_size, R.dimen.list_detail_image_size) .centerCrop() .into(v.im_user);
你可以在这里下载RoundedTransformation文件
另一个简单的方法是使用angular点半径CardView和里面的ImageView:
<android.support.v7.widget.CardView android:layout_width="match_parent" android:layout_height="match_parent" app:cardCornerRadius="8dp" android:layout_margin="5dp" android:elevation="10dp"> <ImageView android:id="@+id/roundedImageView" android:layout_width="match_parent" android:layout_height="match_parent" android:src="@drawable/image" android:background="@color/white" android:scaleType="centerCrop" /> </android.support.v7.widget.CardView>
剪切成圆形的形状被添加到API 21的View
类中。
只要这样做:
- 创build一个可绘制的圆形形状,如下所示:
RES /抽拉/ round_outline.xml
<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle"> <corners android:radius="10dp" /> ... </shape>
- 将drawable设置为ImageView的背景:
android:background="@drawable/round_outline"
- 根据这个文档 ,所有你需要做的就是添加
android:clipToOutline="true"
不幸的是,有一个错误 ,并且XML属性不被识别。 幸运的是,我们仍然可以在Java中设置裁剪:
- 在您的活动或片段中:
ImageView.setClipToOutline(true)
以下是它的样子:
注意:
此方法适用于任何可绘制的形状(不只是圆形)。 它会将ImageView剪切成您在Drawable xml中定义的任何形状轮廓。
有关ImageViews的特别说明
setClipToOutline()
仅在视图的背景设置为可绘制的形状时才起作用。 如果此背景形状存在,则视图会将该形状的轮廓视为裁剪和阴影目的的边框。
这意味着,如果你想使用setClipToOutline()
在一个ImageView上四舍五入,你的图像必须使用android:src
而不是android:background
(因为背景必须设置为圆形)。 如果您必须使用背景设置您的图像而不是src,则可以使用以下解决方法:
- 创build一个布局,并将其背景设置为可绘制的形状
- 将这种布局包裹在ImageView中(没有填充)
- ImageView(包括布局中的任何其他内容)现在将以圆形布局形状显示。
我已经完成自定义ImageView:
public class RoundRectCornerImageView extends ImageView { private float radius = 18.0f; private Path path; private RectF rect; public RoundRectCornerImageView(Context context) { super(context); init(); } public RoundRectCornerImageView(Context context, AttributeSet attrs) { super(context, attrs); init(); } public RoundRectCornerImageView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); init(); } private void init() { path = new Path(); } @Override protected void onDraw(Canvas canvas) { rect = new RectF(0, 0, this.getWidth(), this.getHeight()); path.addRoundRect(rect, radius, radius, Path.Direction.CW); canvas.clipPath(path); super.onDraw(canvas); } }
如何使用:
<com.mypackage.RoundRectCornerImageView android:id="@+id/imageView" android:layout_width="match_parent" android:layout_height="match_parent" android:scaleType="fitXY" />
输出:
希望这会帮助你。
由于所有的答案对于我来说似乎都太复杂了,所以我想到了另外一个我认为值得分享的解决scheme,就是用XML来解决这个问题:
用这样的透明内容创build一个有边框的形状:
<?xml version="1.0" encoding="utf-8"?> <shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle"> <corners android:radius="30dp" /> <stroke android:color="#ffffffff" android:width="10dp" /> </shape>
然后在一个RelativeLayout中,您可以先放置您的图像,然后在另一个ImageView的形状上方的同一位置。 封面形状的大小应该大于边框的宽度。 当外半径被定义时,小心采取更大的圆angular半径,但内半径是涵盖图像的内容。
希望它也能帮助别人。
根据CQM请求编辑相关布局示例:
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" > <ImageView android:id="@+id/imageToShow" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignBottom="@+id/imgCorners" android:layout_alignLeft="@+id/imgCorners" android:layout_alignRight="@+id/imgCorners" android:layout_alignTop="@+id/imgCorners" android:background="#ffffff" android:contentDescription="@string/desc" android:padding="5dp" android:scaleType="centerCrop" /> <ImageView android:id="@+id/imgCorners" android:layout_width="wrap_content" android:layout_height="wrap_content" android:adjustViewBounds="true" android:contentDescription="@string/desc" android:src="@drawable/corners_white" /> </RelativeLayout>
我的ImageView的圆angular小部件的实现,(下调||上)尺寸图像到所需的尺寸。 它利用代码formsCaspNZ。
public class ImageViewRounded extends ImageView { public ImageViewRounded(Context context) { super(context); } public ImageViewRounded(Context context, AttributeSet attrs) { super(context, attrs); } public ImageViewRounded(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); } @Override protected void onDraw(Canvas canvas) { BitmapDrawable drawable = (BitmapDrawable) getDrawable(); if (drawable == null) { return; } if (getWidth() == 0 || getHeight() == 0) { return; } Bitmap fullSizeBitmap = drawable.getBitmap(); int scaledWidth = getMeasuredWidth(); int scaledHeight = getMeasuredHeight(); Bitmap mScaledBitmap; if (scaledWidth == fullSizeBitmap.getWidth() && scaledHeight == fullSizeBitmap.getHeight()) { mScaledBitmap = fullSizeBitmap; } else { mScaledBitmap = Bitmap.createScaledBitmap(fullSizeBitmap, scaledWidth, scaledHeight, true /* filter */); } Bitmap roundBitmap = ImageUtilities.getRoundedCornerBitmap(getContext(), mScaledBitmap, 5, scaledWidth, scaledHeight, false, false, false, false); canvas.drawBitmap(roundBitmap, 0, 0, null); } }
你应该扩展ImageView
并绘制你自己的圆angular矩形。
如果您想在图像周围放置一个框架,您还可以在布局中的图像视图顶部添加圆angular框。
例如,通过使用FrameLayout
,将框架叠加到原始图像上。 FrameLayout
的第一个元素将是你想要展开的图像。 然后添加另一个ImageView
与框架。 第二个ImageView
将显示在原始ImageView
顶部,因此Android会将其内容绘制在原始ImageView
上方。
以下内容将创build一个圆angular矩形布局对象,该对象将围绕放置在其中的任何子对象绘制一个圆angular矩形。 它还演示如何以编程方式创build视图和布局,而不使用布局xml文件。
package android.example; import android.app.Activity; import android.graphics.Color; import android.os.Bundle; import android.util.DisplayMetrics; import android.util.TypedValue; import android.view.ViewGroup.LayoutParams; import android.widget.LinearLayout; import android.widget.TextView; public class MessageScreen extends Activity { /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); int mainBackgroundColor = Color.parseColor("#2E8B57"); int labelTextColor = Color.parseColor("#FF4500"); int messageBackgroundColor = Color.parseColor("#3300FF"); int messageTextColor = Color.parseColor("#FFFF00"); DisplayMetrics metrics = new DisplayMetrics(); getWindowManager().getDefaultDisplay().getMetrics(metrics); float density = metrics.density; int minMarginSize = Math.round(density * 8); int paddingSize = minMarginSize * 2; int maxMarginSize = minMarginSize * 4; TextView label = new TextView(this); /* * The LayoutParams are instructions to the Layout that will contain the * View for laying out the View, so you need to use the LayoutParams of * the Layout that will contain the View. */ LinearLayout.LayoutParams labelLayoutParams = new LinearLayout.LayoutParams( LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT); label.setLayoutParams(labelLayoutParams); label.setTextSize(TypedValue.COMPLEX_UNIT_SP, 18); label.setPadding(paddingSize, paddingSize, paddingSize, paddingSize); label.setText(R.string.title); label.setTextColor(labelTextColor); TextView message = new TextView(this); RoundedRectangle.LayoutParams messageLayoutParams = new RoundedRectangle.LayoutParams( LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT); /* * This is one of the calls must made to force a ViewGroup to call its * draw method instead of just calling the draw method of its children. * This tells the RoundedRectangle to put some extra space around the * View. */ messageLayoutParams.setMargins(minMarginSize, paddingSize, minMarginSize, maxMarginSize); message.setLayoutParams(messageLayoutParams); message.setTextSize(TypedValue.COMPLEX_UNIT_SP, paddingSize); message.setText(R.string.message); message.setTextColor(messageTextColor); message.setBackgroundColor(messageBackgroundColor); RoundedRectangle messageContainer = new RoundedRectangle(this); LinearLayout.LayoutParams messageContainerLayoutParams = new LinearLayout.LayoutParams( LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT); messageContainerLayoutParams.setMargins(paddingSize, 0, paddingSize, 0); messageContainer.setLayoutParams(messageContainerLayoutParams); messageContainer.setOrientation(LinearLayout.VERTICAL); /* * This is one of the calls must made to force a ViewGroup to call its * draw method instead of just calling the draw method of its children. * This tells the RoundedRectangle to color the the exta space that was * put around the View as well as the View. This is exterior color of * the RoundedRectangle. */ messageContainer.setBackgroundColor(mainBackgroundColor); /* * This is one of the calls must made to force a ViewGroup to call its * draw method instead of just calling the draw method of its children. * This is the interior color of the RoundedRectangle. It must be * different than the exterior color of the RoundedRectangle or the * RoundedRectangle will not call its draw method. */ messageContainer.setInteriorColor(messageBackgroundColor); // Add the message to the RoundedRectangle. messageContainer.addView(message); // LinearLayout main = new LinearLayout(this); LinearLayout.LayoutParams mainLayoutParams = new LinearLayout.LayoutParams( LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT); main.setLayoutParams(mainLayoutParams); main.setOrientation(LinearLayout.VERTICAL); main.setBackgroundColor(mainBackgroundColor); main.addView(label); main.addView(messageContainer); setContentView(main); } }
RoundedRectangle布局对象的类如下定义:
/** * A LinearLayout that draws a rounded rectangle around the child View that was added to it. */ package android.example; import android.app.Activity; import android.content.Context; import android.graphics.Canvas; import android.graphics.Paint; import android.graphics.Rect; import android.graphics.RectF; import android.util.AttributeSet; import android.util.DisplayMetrics; import android.widget.LinearLayout; /** * A LinearLayout that has rounded corners instead of square corners. * * @author Danny Remington * * @see LinearLayout * */ public class RoundedRectangle extends LinearLayout { private int mInteriorColor; public RoundedRectangle(Context p_context) { super(p_context); } public RoundedRectangle(Context p_context, AttributeSet attributeSet) { super(p_context, attributeSet); } // Listener for the onDraw event that occurs when the Layout is drawn. protected void onDraw(Canvas canvas) { Rect rect = new Rect(0, 0, getWidth(), getHeight()); RectF rectF = new RectF(rect); DisplayMetrics metrics = new DisplayMetrics(); Activity activity = (Activity) getContext(); activity.getWindowManager().getDefaultDisplay().getMetrics(metrics); float density = metrics.density; int arcSize = Math.round(density * 10); Paint paint = new Paint(); paint.setColor(mInteriorColor); canvas.drawRoundRect(rectF, arcSize, arcSize, paint); } /** * Set the background color to use inside the RoundedRectangle. * * @param Primitive int - The color inside the rounded rectangle. */ public void setInteriorColor(int interiorColor) { mInteriorColor = interiorColor; } /** * Get the background color used inside the RoundedRectangle. * * @return Primitive int - The color inside the rounded rectangle. */ public int getInteriorColor() { return mInteriorColor; } }
道具上面的乔治·沃尔特斯二世,我只是拿出他的答案,并扩大了一点,以支持四舍五入各个angular落。 这可以进一步优化(一些目标rects重叠),但不是很多。
我知道这个线程有点老,但它是在Google上查询如何在Android上对ImageView进行四舍五入的最佳结果之一。
/** * Use this method to scale a bitmap and give it specific rounded corners. * @param context Context object used to ascertain display density. * @param bitmap The original bitmap that will be scaled and have rounded corners applied to it. * @param upperLeft Corner radius for upper left. * @param upperRight Corner radius for upper right. * @param lowerRight Corner radius for lower right. * @param lowerLeft Corner radius for lower left. * @param endWidth Width to which to scale original bitmap. * @param endHeight Height to which to scale original bitmap. * @return Scaled bitmap with rounded corners. */ public static Bitmap getRoundedCornerBitmap(Context context, Bitmap bitmap, float upperLeft, float upperRight, float lowerRight, float lowerLeft, int endWidth, int endHeight) { float densityMultiplier = context.getResources().getDisplayMetrics().density; // scale incoming bitmap to appropriate px size given arguments and display dpi bitmap = Bitmap.createScaledBitmap(bitmap, Math.round(endWidth * densityMultiplier), Math.round(endHeight * densityMultiplier), true); // create empty bitmap for drawing Bitmap output = Bitmap.createBitmap( Math.round(endWidth * densityMultiplier), Math.round(endHeight * densityMultiplier), Config.ARGB_8888); // get canvas for empty bitmap Canvas canvas = new Canvas(output); int width = canvas.getWidth(); int height = canvas.getHeight(); // scale the rounded corners appropriately given dpi upperLeft *= densityMultiplier; upperRight *= densityMultiplier; lowerRight *= densityMultiplier; lowerLeft *= densityMultiplier; Paint paint = new Paint(); paint.setAntiAlias(true); paint.setColor(Color.WHITE); // fill the canvas with transparency canvas.drawARGB(0, 0, 0, 0); // draw the rounded corners around the image rect. clockwise, starting in upper left. canvas.drawCircle(upperLeft, upperLeft, upperLeft, paint); canvas.drawCircle(width - upperRight, upperRight, upperRight, paint); canvas.drawCircle(width - lowerRight, height - lowerRight, lowerRight, paint); canvas.drawCircle(lowerLeft, height - lowerLeft, lowerLeft, paint); // fill in all the gaps between circles. clockwise, starting at top. RectF rectT = new RectF(upperLeft, 0, width - upperRight, height / 2); RectF rectR = new RectF(width / 2, upperRight, width, height - lowerRight); RectF rectB = new RectF(lowerLeft, height / 2, width - lowerRight, height); RectF rectL = new RectF(0, upperLeft, width / 2, height - lowerLeft); canvas.drawRect(rectT, paint); canvas.drawRect(rectR, paint); canvas.drawRect(rectB, paint); canvas.drawRect(rectL, paint); // set up the rect for the image Rect imageRect = new Rect(0, 0, width, height); // set up paint object such that it only paints on Color.WHITE paint.setXfermode(new AvoidXfermode(Color.WHITE, 255, AvoidXfermode.Mode.TARGET)); // draw resized bitmap onto imageRect in canvas, using paint as configured above canvas.drawBitmap(bitmap, imageRect, imageRect, paint); return output; }
罗曼·盖伊是在哪里。
缩小版本如下。
Bitmap bitmap = ((BitmapDrawable) getResources().getDrawable(R.drawable.image)).getBitmap(); Bitmap bitmapRounded = Bitmap.createBitmap(bitmap.getWidth(), bitmap.getHeight(), bitmap.getConfig()); Canvas canvas = new Canvas(bitmapRounded); Paint paint = new Paint(); paint.setAntiAlias(true); paint.setShader(new BitmapShader(bitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP)); canvas.drawRoundRect((new RectF(0.0f, 0.0f, bitmap.getWidth(), bitmap.getHeight())), 10, 10, paint); imageView.setImageBitmap(bitmapRounded);
非常感谢首先回答。 这里是修改版本,将矩形图像转换为方形图像(圆angular),填充颜色作为parameter passing。
public static Bitmap getRoundedBitmap(Bitmap bitmap, int pixels, int color) { Bitmap inpBitmap = bitmap; int width = 0; int height = 0; width = inpBitmap.getWidth(); height = inpBitmap.getHeight(); if (width <= height) { height = width; } else { width = height; } Bitmap output = Bitmap.createBitmap(width, height, Config.ARGB_8888); Canvas canvas = new Canvas(output); final Paint paint = new Paint(); final Rect rect = new Rect(0, 0, width, height); final RectF rectF = new RectF(rect); final float roundPx = pixels; paint.setAntiAlias(true); canvas.drawARGB(0, 0, 0, 0); paint.setColor(color); canvas.drawRoundRect(rectF, roundPx, roundPx, paint); paint.setXfermode(new PorterDuffXfermode(Mode.SRC_IN)); canvas.drawBitmap(inpBitmap, rect, rect, paint); return output; }
为什么不在draw()中剪裁?
这是我的解决scheme:
- 用裁剪扩展RelativeLayout
- 把ImageView(或其他视图)放到布局中:
码:
public class RoundRelativeLayout extends RelativeLayout { private final float radius; public RoundRelativeLayout(Context context, AttributeSet attrs) { super(context, attrs); TypedArray attrArray = context.obtainStyledAttributes(attrs, R.styleable.RoundRelativeLayout); radius = attrArray.getDimension( R.styleable.RoundRelativeLayout_radius, 0); } private boolean isPathValid; private final Path path = new Path(); private Path getRoundRectPath() { if (isPathValid) { return path; } path.reset(); int width = getWidth(); int height = getHeight(); RectF bounds = new RectF(0, 0, width, height); path.addRoundRect(bounds, radius, radius, Direction.CCW); isPathValid = true; return path; } @Override protected void dispatchDraw(Canvas canvas) { canvas.clipPath(getRoundRectPath()); super.dispatchDraw(canvas); } @Override public void draw(Canvas canvas) { canvas.clipPath(getRoundRectPath()); super.draw(canvas); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { int oldWidth = getMeasuredWidth(); int oldHeight = getMeasuredHeight(); super.onMeasure(widthMeasureSpec, heightMeasureSpec); int newWidth = getMeasuredWidth(); int newHeight = getMeasuredHeight(); if (newWidth != oldWidth || newHeight != oldHeight) { isPathValid = false; } } }
Apply a shape to your imageView
as below:
<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle" > <solid android:color="#faf5e6" /> <stroke android:width="1dp" android:color="#808080" /> <corners android:radius="15dp" /> <padding android:bottom="5dp" android:left="5dp" android:right="5dp" android:top="5dp" /> </shape>
it may be helpful to you friend.
This pure xml solution was good enough in my case. http://www.techrepublic.com/article/pro-tip-round-corners-on-an-android-imageview-with-this-hack/
编辑
Here's the answer in a nutshell:
In the /res/drawable folder, create a frame.xml file. In it, we define a simple rectangle with rounded corners and a transparent center.
<?xml version="1.0" encoding="utf-8"?> <shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle"> <solid android:color="#00ffffff" /> <padding android:left="6dp" android:top="6dp" android:right="6dp" android:bottom="6dp" /> <corners android:radius="12dp" /> <stroke android:width="6dp" android:color="#ffffffff" /> </shape>
In your layout file you add a LinearLayout that contains a standard ImageView, as well as a nested FrameLayout. The FrameLayout uses padding and the custom drawable to give the illusion of rounded corners.
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" android:layout_gravity="center" android:gravity="center" android:background="#ffffffff"> <ImageView android:layout_width="wrap_content" android:layout_height="wrap_content" android:padding="6dp" android:src="@drawable/tr"/> <FrameLayout android:layout_width="wrap_content" android:layout_height="wrap_content"> <ImageView android:layout_width="match_parent" android:layout_height="match_parent" android:padding="6dp" android:src="@drawable/tr"/> <ImageView android:src="@drawable/frame" android:layout_width="match_parent" android:layout_height="match_parent" /> </FrameLayout> </LinearLayout>
Here is a simple example overriding imageView, you can then also use it in layout designer to preview.
public class RoundedImageView extends ImageView { public RoundedImageView(Context context) { super(context); } public RoundedImageView(Context context, AttributeSet attrs) { super(context, attrs); } public RoundedImageView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); } @TargetApi(Build.VERSION_CODES.LOLLIPOP) public RoundedImageView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { super(context, attrs, defStyleAttr, defStyleRes); } @Override public void setImageDrawable(Drawable drawable) { float radius = 0.1f; Bitmap bitmap = ((BitmapDrawable) drawable).getBitmap(); RoundedBitmapDrawable rid = RoundedBitmapDrawableFactory.create(getResources(), bitmap); rid.setCornerRadius(bitmap.getWidth() * radius); super.setImageDrawable(rid); }
}
This is for fast solution. Radius is used on all corners and is based of percentage of bitmap width.
I just overrided setImageDrawable
and used support v4 method for rounded bitmap drawable.
用法:
<com.example.widgets.RoundedImageView android:layout_width="39dp" android:layout_height="39dp" android:src="@drawable/your_drawable" />
Preview with imageView and custom imageView:
With the help of glide library and RoundedBitmapDrawableFactory class it's easy to achieve. You may need to create circular placeholder image.
Glide.with(context) .load(imgUrl) .asBitmap() .placeholder(R.drawable.placeholder) .error(R.drawable.placeholder) .into(new BitmapImageViewTarget(imgProfilePicture) { @Override protected void setResource(Bitmap resource) { RoundedBitmapDrawable drawable = RoundedBitmapDrawableFactory.create(context.getResources(), Bitmap.createScaledBitmap(resource, 50, 50, false)); drawable.setCornerRadius(10); //drawable.setCircular(true); imgProfilePicture.setImageDrawable(drawable); } });
if your image is on internet the best way is using glide and RoundedBitmapDrawableFactory
(from API 21 – but available in support library) like so:
Glide.with(ctx).load(url).asBitmap().centerCrop().into(new BitmapImageViewTarget(imageView) { @Override protected void setResource(Bitmap res) { RoundedBitmapDrawable bitmapDrawable = RoundedBitmapDrawableFactory.create(ctx.getResources(), res); bitmapDrawable.setCircular(true);//comment this line and uncomment the next line if you dont want it fully cricular //circularBitmapDrawable.setCornerRadius(cornerRadius); imageView.setImageDrawable(bitmapDrawable); } });
You can try this library – RoundedImageView
它是:
A fast ImageView that supports rounded corners, ovals, and circles. A full superset of CircleImageView.
I've used it in my project, and it is very easy.
If any of you are facing this problem
Most probably , you are using Android Studio . Due to image re-size and all in Android Studio ,you may encounter this problem. An easy fix to this problem is to decrease the radius of circle in drawCircle()
. In my case i use this fix
Using canvas.drawCircle(100, 100, 90, paint);
instead of canvas.drawCircle(100, 100, 100, paint);
this will definitely solve your problem.
Here is finally edited code:-
public class Profile extends ActionBarActivity { TextView username; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.profile); username= (TextView) findViewById(R.id.txt); String recievedusername=getIntent().getExtras().getString("toname"); username.setText(recievedusername); Bitmap bm = BitmapFactory.decodeResource(getResources(), R.mipmap.gomez); Bitmap resizedBitmap = Bitmap.createScaledBitmap(bm, 200,200, false); Bitmap conv_bm=getCircleBitmap(resizedBitmap,100); // set circle bitmap ImageView mImage = (ImageView) findViewById(R.id.profile_image); mImage.setImageBitmap(conv_bm); // TODO Auto-generated method stub } private Bitmap getCircleBitmap(Bitmap bitmap , int pixels) { final Bitmap output = Bitmap.createBitmap(bitmap.getWidth(), bitmap.getHeight(), Bitmap.Config.ARGB_8888); final Canvas canvas = new Canvas(output); final int color = 0xff424242; final Paint paint = new Paint(); final Rect rect = new Rect(0, 0, bitmap.getWidth(),bitmap.getHeight()); final RectF rectF = new RectF(rect); paint.setAntiAlias(true); canvas.drawARGB(0, 0, 0, 0); paint.setColor(color); canvas.drawCircle(100,100, 90, paint); paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN)); canvas.drawBitmap(bitmap, rect, rect, paint); bitmap.recycle(); return output; } @Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; this adds items to the action bar if it is present. MenuInflater inflater = getMenuInflater(); inflater.inflate(R.menu.menu_apploud, menu); return super.onCreateOptionsMenu(menu); } @Override public boolean onOptionsItemSelected(MenuItem item) { // Handle action bar item clicks here. The action bar will // automatically handle clicks on the Home/Up button, so long // as you specify a parent activity in AndroidManifest.xml. int id = item.getItemId(); //noinspection SimplifiableIfStatement if (id == R.id.action_addnew) { Intent i; i=new Intent(Profile.this,ApplaudSomeone.class); startActivity(i); return true; } return super.onOptionsItemSelected(item); } }
Use this to get circular image with border-
public static Bitmap getCircularBitmapWithBorder(Bitmap bitmap, int bordercolor) { if (bitmap == null || bitmap.isRecycled()) { return null; } int borderWidth=(int)(bitmap.getWidth()/40); final int width = bitmap.getWidth() + borderWidth; final int height = bitmap.getHeight() + borderWidth; Bitmap canvasBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); BitmapShader shader = new BitmapShader(bitmap, TileMode.CLAMP, TileMode.CLAMP); Paint paint = new Paint(); paint.setAntiAlias(true); paint.setShader(shader); Canvas canvas = new Canvas(canvasBitmap); float radius = width > height ? ((float) height) / 2f : ((float) width) / 2f; canvas.drawCircle(width / 2, height / 2, radius, paint); paint.setShader(null); paint.setStyle(Paint.Style.STROKE); paint.setColor(bordercolor); paint.setStrokeWidth(borderWidth); canvas.drawCircle(width / 2, height / 2, radius - borderWidth / 2, paint); return canvasBitmap; }
Answer for the question that is redirected here: "How to create a circular ImageView in Android?"
public static Bitmap getRoundBitmap(Bitmap bitmap) { int min = Math.min(bitmap.getWidth(), bitmap.getHeight()); Bitmap bitmapRounded = Bitmap.createBitmap(min, min, bitmap.getConfig()); Canvas canvas = new Canvas(bitmapRounded); Paint paint = new Paint(); paint.setAntiAlias(true); paint.setShader(new BitmapShader(bitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP)); canvas.drawRoundRect((new RectF(0.0f, 0.0f, min, min)), min/2, min/2, paint); return bitmapRounded; }
If you're looking for a fast but dirty solution you can use this lib by Vincent Mi.
I'm using a custom view that I layout on top of the other ones and that just draws the 4 small inverted corners in the same color as the background.
优点:
- Does not allocate a bitmap.
- Works whatever the View you want to apply the rounded corners.
- Works for all API levels 😉
码:
public class RoundedCornersView extends View { private float mRadius; private int mColor = Color.WHITE; private Paint mPaint; private Path mPath; public RoundedCornersView(Context context) { super(context); init(); } public RoundedCornersView(Context context, AttributeSet attrs) { super(context, attrs); init(); TypedArray a = context.getTheme().obtainStyledAttributes( attrs, R.styleable.RoundedCornersView, 0, 0); try { setRadius(a.getDimension(R.styleable.RoundedCornersView_radius, 0)); setColor(a.getColor(R.styleable.RoundedCornersView_cornersColor, Color.WHITE)); } finally { a.recycle(); } } private void init() { setColor(mColor); setRadius(mRadius); } private void setColor(int color) { mColor = color; mPaint = new Paint(); mPaint.setColor(mColor); mPaint.setStyle(Paint.Style.FILL); mPaint.setAntiAlias(true); invalidate(); } private void setRadius(float radius) { mRadius = radius; RectF r = new RectF(0, 0, 2 * mRadius, 2 * mRadius); mPath = new Path(); mPath.moveTo(0,0); mPath.lineTo(0, mRadius); mPath.arcTo(r, 180, 90); mPath.lineTo(0,0); invalidate(); } @Override protected void onDraw(Canvas canvas) { /*This just draws 4 little inverted corners */ int w = getWidth(); int h = getHeight(); canvas.drawPath(mPath, mPaint); canvas.save(); canvas.translate(w, 0); canvas.rotate(90); canvas.drawPath(mPath, mPaint); canvas.restore(); canvas.save(); canvas.translate(w, h); canvas.rotate(180); canvas.drawPath(mPath, mPaint); canvas.restore(); canvas.translate(0, h); canvas.rotate(270); canvas.drawPath(mPath, mPaint); } }
This isn't exactly the answer, but it's a solution that is similar. It may help people who were in the same boat as I was.
My image, an application logo, had a transparent background, and I was applying an XML gradient as the image background. I added the necessary padding/margins to the imageView in XML, then added this as my background:
<?xml version="1.0" encoding="utf-8"?>
<item> <shape> <gradient android:type="linear" android:startColor="@color/app_color_light_background" android:endColor="@color/app_color_disabled" android:angle="90" /> <!-- Round the top corners. --> <corners android:topLeftRadius="@dimen/radius_small" android:topRightRadius="@dimen/radius_small" /> </shape> </item>
Quite a lot of answers!
I followed this example which a few people have kinda suggested too: http://www.techrepublic.com/article/pro-tip-round-corners-on-an-android-imageview-with-this-hack/
However, what I needed was a coloured circle, behind a transparent image. For anyone who is interested in doing the same…
1) Set the FrameLayout to the width and height – in my case the size of the image (50dp).
2) Place the ImageView that has the src = "@drawable/…", above the ImageView that has the image. Give it an id, in my case I called it iconShape
3) Drawable mask.xml should have a solid colour of #ffffffff 4) If you want to dynamically change the circle colour in your code, do
ImageView iv2 = (ImageView) v.findViewById(R.id.iconShape); Drawable shape = getResources().getDrawable(R.drawable.mask); shape.setColorFilter(Color.BLUE, Mode.MULTIPLY); iv2.setImageDrawable(shape);
**In Layout** Make your ImageView like <com.example..CircularImageView android:id="@+id/profile_image_round_corner" android:layout_width="80dp" android:layout_height="80dp" android:scaleType="fitCenter" android:padding="2dp" android:background="@null" android:adjustViewBounds="true" android:layout_centerInParent="true" android:src="@drawable/dummy" /> **And Create a Class** package com.example; import java.util.Formatter.BigDecimalLayoutForm; import android.content.Context; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.PorterDuff.Mode; import android.graphics.PorterDuffXfermode; import android.graphics.Rect; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; import android.util.AttributeSet; import android.widget.ImageView; 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); int w = getWidth(), h = getHeight(); Bitmap roundBitmap = getRoundBitmap(bitmap, w); canvas.drawBitmap(roundBitmap, 0, 0, null); } public static Bitmap getRoundBitmap(Bitmap bmp, int radius) { Bitmap sBmp; if (bmp.getWidth() != radius || bmp.getHeight() != radius) { float smallest = Math.min(bmp.getWidth(), bmp.getHeight()); float factor = smallest / radius; sBmp = Bitmap.createScaledBitmap(bmp, (int)(bmp.getWidth() / factor), (int)(bmp.getHeight() / factor), false); } else { sbmp = bmp; } Bitmap output = Bitmap.createBitmap(radius, radius, Bitmap.Config.ARGB_8888); Canvas canvas = new Canvas(output); final int color = 0xffa19774; final Paint paint = new Paint(); final Rect rect = new Rect(0, 0, radius, radius); paint.setAntiAlias(true); paint.setFilterBitmap(true); paint.setDither(true); canvas.drawARGB(0, 0, 0, 0); paint.setColor(Color.parseColor("#BAB399")); canvas.drawCircle(radius / 2 + 0.7f, radius / 2 + 0.7f, radius / 2 + 0.1f, paint); paint.setXfermode(new PorterDuffXfermode(Mode.SRC_IN)); canvas.drawBitmap(sBmp, rect, rect, paint); return output; } }