android 通过修改图片像素实现CircleImageView

CircleImageView实现方法有很多种,各有优缺点,因此需要按照不同的场景使用。我们今天使用修改图片像素的方法实现CircleImageView,主要知识点无非是勾股定理和点到圆形的距离。

素材图片android 通过修改图片像素实现CircleImageView_第1张图片android 通过修改图片像素实现CircleImageView_第2张图片

效果如下:
android 通过修改图片像素实现CircleImageView_第3张图片

**

1、clipPath裁剪画布

**

该方法支持的最小版本是Android 4.3(API Level 18),方便快捷,但是不支持硬件加,此外也存在Path既有的缺点,不支持抗锯齿。

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

    Paint paint = new Paint();

    mBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.pic);
    mPath = new Path();

    mPath.addCircle(mBitmap.getWidth() / 2, mBitmap.getHeight() / 2, mBitmap.getWidth() / 2, Path.Direction.CCW);
    canvas.clipPath(mPath);
    canvas.drawBitmap(mBitmap, 0, 0, paint);
}

2、使用PorterDuffXfermode

PorterDuffXfermode是Android主流的图片合成工具,支持模式多,稳定性强,效果好,质量高,支持抗锯齿备受广大开发者喜爱,可以说是很多应用开发的首选。缺点是难度学习有些高,另外比较占内存。

/**
* 绘制圆形图片
*
*/
@Override
protected void onDraw(Canvas canvas) {

    Drawable drawable = getDrawable();  
    if (null != drawable) {  
        Bitmap bitmap = ((BitmapDrawable) drawable).getBitmap();  
        Bitmap b = getCircleBitmap(bitmap);  
        final Rect rectSrc = new Rect(0, 0, b.getWidth(), b.getHeight());  
        final Rect rectDest = new Rect(0,0,getWidth(),getHeight());
        paint.reset();  
        canvas.drawBitmap(b, rectSrc, rectDest, paint);  

    } else {  
        super.onDraw(canvas);  
    }  
}  

/**
 * 获取圆形图片方法
 * @param bitmap
 * @param pixels
 * @return Bitmap
 */
private Bitmap getCircleBitmap(Bitmap bitmap) {  
    Bitmap output = Bitmap.createBitmap(bitmap.getWidth(),  
            bitmap.getHeight(), Config.ARGB_8888);  
    Canvas canvas = new Canvas(output);  
      
    final int color = 0xff424242;
   
    final Rect rect = new Rect(0, 0, bitmap.getWidth(), bitmap.getHeight());  
    paint.setAntiAlias(true);  
    canvas.drawColor(Color.TRANSPARENT);  
    paint.setColor(color);  
    int x = bitmap.getWidth(); 
    
    canvas.drawCircle(x / 2, x / 2, x / 2, paint);  
    paint.setXfermode(new PorterDuffXfermode(Mode.SRC_IN));  
    canvas.drawBitmap(bitmap, rect, rect, paint);  
    return output;  
    
    
}  

3、设置画笔Paint的Shader,然后用该画笔绘制圆形图片

该方法是Glide和picasso使用的方法,用法简单便捷,占内占有率处于中等水平。

@Override  
protected void onDraw(Canvas canvas) {  

    Drawable drawable = getDrawable();  
    if (null != drawable) {  
        Bitmap bitmap = ((BitmapDrawable) drawable).getBitmap();  
        Bitmap b = transform(bitmap);  
        final Rect rectSrc = new Rect(0, 0, b.getWidth(), b.getHeight());  
        final Rect rectDest = new Rect(0,0,getWidth(),getHeight());
        paint.reset();  
        canvas.drawBitmap(b, rectSrc, rectDest, paint);  

    } else {  
        super.onDraw(canvas);  
    }  
} 

public Bitmap transform(Bitmap source) {
int size = Math.min(source.getWidth(), source.getHeight());

        int x = (source.getWidth() - size) / 2;
        int y = (source.getHeight() - size) / 2;

        Bitmap squaredBitmap = Bitmap.createBitmap(source, x, y, size, size);
        if (squaredBitmap != source) {
            source.recycle();
        }

        Bitmap bitmap = Bitmap.createBitmap(size, size, source.getConfig());

        Canvas canvas = new Canvas(bitmap);
        Paint paint = new Paint();
        BitmapShader shader = new BitmapShader(squaredBitmap,
                BitmapShader.TileMode.CLAMP, BitmapShader.TileMode.CLAMP);

      float mScale = (mRadius * 2.0f) / Math.min(bitmap.getHeight(), bitmap.getWidth());

      Matrix matrix = new Matrix();
      matrix.setScale(mScale, mScale);
      bitmapShader.setLocalMatrix(matrix);


        paint.setShader(shader);
        paint.setAntiAlias(true);

        float r = size / 2f;
        canvas.drawCircle(r, r, r, paint);

        squaredBitmap.recycle();
        return bitmap;
    }

4、修改像素

该方法无法支持抗锯齿,并且不支持Bitmap.Config.HARDWARE格式的bitmap,但用法简单,内存占有率同样处于比较低。

public class CircleImageView extends AppCompatImageView {

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


public CircleImageView(Context context, AttributeSet attrs) {
    this(context, attrs,0);
}

public CircleImageView(Context context, AttributeSet attrs, int defStyleAttr) {
    super(context, attrs, defStyleAttr);
}


@Override
public void onDraw(Canvas canvas) {

    int width  = getWidth();
    int height = getHeight();


    int minSize = Math.min(width,height)/2;
    Drawable drawable = getDrawable();
    if(drawable!=null && minSize!=0) {

        if(Math.min(drawable.getIntrinsicWidth(),drawable.getIntrinsicHeight())==0) {
            return;
        }

        int intrinsicWidth = drawable.getIntrinsicWidth();
        int intrinsicHeight = drawable.getIntrinsicHeight();

        float R = Math.min(intrinsicWidth, intrinsicHeight) / 2;

        Bitmap bmp = transformBitmap(drawable, intrinsicWidth, intrinsicHeight, R);

        Matrix imageMatrix = getImageMatrix();

        if((imageMatrix==null || imageMatrix.isIdentity()) && getPaddingTop()==0 && getPaddingLeft()==0){
            drawCircleImage(canvas, bmp);

        }else {
            if (imageMatrix != null && !imageMatrix.isIdentity()) {
                canvas.concat(imageMatrix);
            }
            final int saveCount = canvas.getSaveCount();
            canvas.save();

            if (getCropToPadding()) {
                final int scrollX = getScrollX();
                final int scrollY = getScrollY();
                canvas.clipRect(scrollX + getPaddingLeft(), scrollY + getPaddingTop(),
                        scrollX + getRight() - getLeft() - getPaddingRight(),
                        scrollY + getBottom() - getTop() - getPaddingBottom());
            }

            canvas.translate(getPaddingLeft(), getPaddingTop());
            drawCircleImage(canvas, bmp);
            canvas.restoreToCount(saveCount);

        }
        if(bmp!=null && !bmp.isRecycled()) {
            bmp.recycle();
        }
    }else{
        super.onDraw(canvas);
    }
}

private void drawCircleImage(Canvas canvas, Bitmap bmp) {
    try {
        DrawFilter drawFilter = canvas.getDrawFilter();
        canvas.setDrawFilter(new PaintFlagsDrawFilter(0, Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG));
        canvas.drawBitmap(bmp, 0, 0, null);
        canvas.setDrawFilter(drawFilter);
    }catch (Exception e){
        e.printStackTrace();
        return;
    }
}

@NonNull
private Bitmap transformBitmap(Drawable drawable, int intrinsicWidth, int intrinsicHeight, float r) {
    Bitmap bmp = Bitmap.createBitmap(intrinsicWidth, intrinsicHeight, Bitmap.Config.ARGB_8888);
    Canvas targetCanvas = new Canvas(bmp);
    try {
        drawable.draw(targetCanvas);
        for (int y = 0; y < intrinsicHeight; y++) {
            for (int x = 0; x < intrinsicWidth; x++) {
                if ((Math.pow(x - intrinsicWidth / 2, 2) + Math.pow(y - intrinsicHeight / 2, 2)) <= Math.pow(r, 2)) {
                    continue;
                }
                bmp.setPixel(x, y, Color.TRANSPARENT);
            }
        }
    }catch (Exception e){
        NCFLog.e("transformBitmap","e="+e.getLocalizedMessage());
        e.printStackTrace();
    }
    return bmp;
}

public boolean isHardware(Bitmap sourceBitmap){
    if(sourceBitmap==null) return  false;
    if(Build.VERSION.SDK_INT>=Build.VERSION_CODES.O) {
        return sourceBitmap.getConfig() == Bitmap.Config.HARDWARE;
    }
    return false;
}

}

你可能感兴趣的:(android 通过修改图片像素实现CircleImageView)