我应该如何在Android中为图像提供圆角?

时间:2009-11-10 02:10:11

标签: java android image

我想将我加载的图像更改为圆角。

您知道的任何提示,教程和最佳做法?

8 个答案:

答案 0 :(得分:43)

对于更受控制的方法,使用绘制的porter-duff Xfer模式绘制圆角矩形并将其蒙版到图像上。

首先设置Xfer绘图和圆角位图:

Bitmap myCoolBitmap = ... ; // <-- Your bitmap you want rounded    
int w = myCoolBitmap.getWidth(), h = myCoolBitmap.getHeight();

// We have to make sure our rounded corners have an alpha channel in most cases
Bitmap rounder = Bitmap.createBitmap(w,h,Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(rounder);    

// We're going to apply this paint eventually using a porter-duff xfer mode.
// This will allow us to only overwrite certain pixels. RED is arbitrary. This
// could be any color that was fully opaque (alpha = 255)
Paint xferPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
xferPaint.setColor(Color.RED);

// We're just reusing xferPaint to paint a normal looking rounded box, the 20.f
// is the amount we're rounding by.
canvas.drawRoundRect(new RectF(0,0,w,h), 20.0f, 20.0f, xferPaint);     

// Now we apply the 'magic sauce' to the paint  
xferPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN));

现在将此位图应用于图像的顶部:

Bitmap result = Bitmap.createBitmap(myCoolBitmap.getWidth(), myCoolBitmap.getHeight() ,Bitmap.Config.ARGB_8888);
Canvas resultCanvas = new Canvas(result)
resultCanvas.drawBitmap(myCoolBitmap, 0, 0, null);
resultCanvas.drawBitmap(rounder, 0, 0, xferPaint);

带圆角的位图现在位于结果中。

答案 1 :(得分:29)

为什么不使用clipPath?

protected void onDraw(Canvas canvas) {
    Path clipPath = new Path();
    float radius = 10.0f;
    float padding = radius / 2;
    int w = this.getWidth();
    int h = this.getHeight();
    clipPath.addRoundRect(new RectF(padding, padding, w - padding, h - padding), radius, radius, Path.Direction.CW);
    canvas.clipPath(clipPath);
    super.onDraw(canvas);
}

答案 2 :(得分:16)

Romain Guy自己在his blog写道:

  

为了生成圆形图像,我只需编写一个自定义Drawable   使用Canvas.drawRoundRect()绘制一个圆角矩形。诀窍是   使用带有BitmapShader的Paint来填充圆角矩形   纹理而不是简单的颜色。这是代码的样子:

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

示例应用程序更进一步,并假装一个小插图   通过将BitmapShader与RadialGradient相结合来实现效果。

答案 3 :(得分:7)

这是我发现用ImageView做的一种方式。我尝试了其他方法,包括这里的答案和类似的问题,但我发现它们对我来说效果不好,因为我需要将角应用于图像视图而不是直接应用于位图。如果你正在缩放/裁剪/平移该位图,直接应用于位图将无法工作,因为角也将被缩放/裁剪/平移。

public class RoundedCornersImageView extends ImageView {
    private final Paint restorePaint = new Paint();
    private final Paint maskXferPaint = new Paint();
    private final Paint canvasPaint = new Paint();

    private final Rect bounds = new Rect();
    private final RectF boundsf = new RectF();

    public RoundedCornersImageView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        init();
    }

    public RoundedCornersImageView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    public RoundedCornersImageView(Context context) {
        super(context);
        init();
    }

    private void init() {
        canvasPaint.setAntiAlias(true);
        canvasPaint.setColor(Color.argb(255, 255, 255, 255));
        restorePaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_ATOP));
        maskXferPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.MULTIPLY));
    }

    @Override
    protected void onDraw(Canvas canvas) {
        canvas.getClipBounds(bounds);
        boundsf.set(bounds);

        canvas.saveLayer(boundsf, restorePaint, Canvas.ALL_SAVE_FLAG);
        super.onDraw(canvas);

        canvas.saveLayer(boundsf, maskXferPaint, Canvas.ALL_SAVE_FLAG);
        canvas.drawARGB(0, 0, 0, 0);
        canvas.drawRoundRect(boundsf, 75, 75, canvasPaint);

        canvas.restore();
        canvas.restore();
    }
}

这是使用硬件层进行最终图层合成的替代方案:

public class RoundedCornersImageView extends ImageView {
    private final Paint restorePaint = new Paint();
    private final Paint maskXferPaint = new Paint();
    private final Paint canvasPaint = new Paint();

    private final Rect bounds = new Rect();
    private final RectF boundsf = new RectF();

    public RoundedCornersImageView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        init();
    }

    public RoundedCornersImageView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    public RoundedCornersImageView(Context context) {
        super(context);
        init();
    }

    private void init() {
        canvasPaint.setAntiAlias(true);
        canvasPaint.setColor(Color.argb(255, 255, 255, 255));
        restorePaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_ATOP));
        maskXferPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.MULTIPLY));

        setLayerType(View.LAYER_TYPE_HARDWARE, restorePaint);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        canvas.getClipBounds(bounds);
        boundsf.set(bounds);

        super.onDraw(canvas);

        canvas.saveLayer(boundsf, maskXferPaint, Canvas.ALL_SAVE_FLAG);
        canvas.drawARGB(0, 0, 0, 0);
        canvas.drawRoundRect(boundsf, 75, 75, canvasPaint);

        canvas.restore();
    }
}

起初我无法使用这种方法,因为我的角落变黑了;我后来才意识到在阅读这个问题后问题是什么:Android how to apply mask on ImageView?。事实证明,修改画布中的alpha实际上是&#34;抓住它&#34;直接在屏幕上,并打孔到下面的黑色窗口。这就是为什么需要两个图层的原因:一个用于应用蒙版,另一个用于将合成图像应用到屏幕。

答案 4 :(得分:5)

如何创建一个只有圆角且具有透明体的NinePatchDrawable图像。使用适当重新调整大小的NinePatchDrawable版本覆盖您的图像。

答案 5 :(得分:4)

package com.pkg;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;

import android.app.Activity;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
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;
import android.os.Bundle;
import android.os.Environment;
import android.widget.ImageView;

public class RoundedImage extends Activity {
    /** Called when the activity is first created. */
    ImageView imag;
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        imag=(ImageView)findViewById(R.id.image);

        //ImageView img1=(ImageView)findViewById(R.id.imageView1);
        BitmapFactory.Options bitopt=new BitmapFactory.Options();
        bitopt.inSampleSize=1;
        // String img=Environment.getExternalStorageDirectory().toString();
        // String filepath =Environment.getExternalStorageDirectory().toString();
        String filepath ="/mnt/sdcard/LOST.DIR";
        File imagefile = new File(filepath + "/logo.jpg");
        FileInputStream fis = null;
        try 
        {
        fis = new FileInputStream(imagefile);
        }  
        catch (FileNotFoundException e1)
        {
        // TODO Auto-generated catch block
        e1.printStackTrace();
        }
        Bitmap bi = BitmapFactory.decodeStream(fis);
        if(bi!=null){
            imag.setImageBitmap(getRoundedCornerBitmap(bi));
        }

    }

    public static Bitmap getRoundedCornerBitmap(Bitmap bitmap) {
    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 = 12;

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

答案 6 :(得分:0)

这是另一个使用ImageView的四舍五入Path实现。性能很好,但是在某些情况下,由于硬件图纸,模拟器上可能会出现一些错误。

public class RoundImageView extends ImageView {

    private Path mPath;
    private RectF mRect;
    private Paint mPaint;

    private int mCornerRadius;
    private float mImageAlpha;
    private boolean mIsCircular;

    public RoundImageView(Context context) {
        this(context, null);
    }

    public RoundImageView(Context context, AttributeSet attrs) {
        this(context, attrs, R.attr.roundImageViewStyle);
    }

    public RoundImageView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);

        TypedArray a = context.obtainStyledAttributes(
                attrs, R.styleable.RoundImageView, defStyle, 0);

        mCornerRadius = a.getDimensionPixelSize(R.styleable.RoundImageView_cornerRadius, 0);
        mIsCircular = a.getBoolean(R.styleable.RoundImageView_isCircular, false);
        mImageAlpha = a.getFloat(R.styleable.RoundImageView_imageAlpha, 1);

        a.recycle();

        setAlpha((int) (mImageAlpha * 255));

        // Avoid expensive off-screen drawing
        setLayerType(LAYER_TYPE_HARDWARE, null);

        mPath = new Path();

        mRect = new RectF();

        mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN));
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);

        mPath.reset();

        if (mIsCircular) {
            float halfWidth = canvas.getWidth() / 2;
            float halfHeight = canvas.getHeight() / 2;
            float radius = Math.max(halfWidth, halfHeight);

            mPath.addCircle(halfWidth, halfHeight, radius, Path.Direction.CW);
        } else {
            mRect.right = canvas.getWidth();
            mRect.bottom = canvas.getHeight();

            mPath.addRoundRect(mRect, mCornerRadius, mCornerRadius, Path.Direction.CW);
        }

        canvas.drawPath(mPath, mPaint);
    }
}

P.S。 Learn OpenGL ES提供了最佳解决方案。它非常平滑,并且也可以在模拟器上运行。

答案 7 :(得分:0)

我找到的最佳解决方案->

1)创建可绘制的圆角。并设置为imageview作为背景。

<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle" >
<corners
    android:radius="10dp" /></shape>

2)然后在Java代码中设置setClipToOutline(true)的图像视图对象属性。

imageview.setClipToOutline(true);

就像魅力一样