三国杀武将|手游三国杀边锋版

android通過修改圖片像素實現CircleImageView

米米狗 2019-04-16 09:53:30 782
本文來自 開源中國 ,作者 米米狗

CircleImageView實現方法有很多種,各有優缺點,因此需要按照不同的場景使用。我們今天使用修改圖片像素的方法實現CircleImageView,主要知識點無非是勾股定理和點到圓形的距離。

素材圖片:

 

效果如下:

 

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, 00, 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(00, 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(00, 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(00, 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, 00null);
            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 / 22) + Math.pow(y - intrinsicHeight / 22)) <= 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==nullreturn  false;
        if(Build.VERSION.SDK_INT>=Build.VERSION_CODES.O) {
            return sourceBitmap.getConfig() == Bitmap.Config.HARDWARE;
        }
        return false;
    }

}
三国杀武将