美文网首页
自定义圆角ImageView

自定义圆角ImageView

作者: 陈旭阳 | 来源:发表于2020-03-03 16:28 被阅读0次

准备知识

@Override
public void onDraw(canvas){
  super.onDraw(canvas)
} 
@Override
public draw(canvas){
  super.draw(canvas);
}

系统绘制窗口并不是直接调用这两个函数来完成,只是用来提供接口让开发者能在绘制前修改canvas的方法,所以

@Override
public void onDraw(canvas){
  super.draw(new Canvas());
} 
@Override
public draw(canvas){
  super.onDraw(new Canvas());
}

所绘制的并不是新的Canvas,而是当前View在draw()之前的Canvas内容。

Xfermode版本(不推荐):

使用Paint.setXfermode(new PorterDuffXfermode (PorterDuff.Mode.DST_IN)),必须关闭硬件加速,图片数量众多时,卡顿明显,且实践发现在SDK28版本上无法利用DST剪裁SRC,这里提供的是改进版,思路是先绘制View底板形状,再绘制Bitmap。

核心代码如下:

@Override
public void draw(Canvas canvas) {
    //判断Drawable是否是Bitmap
    if (getDrawable ( ) instanceof BitmapDrawable) {
        //获取当前View尺寸建立Rect
        mRect.set (0, 0, getWidth ( ), getHeight ( ));
        //创建目标Bitmap
        Bitmap target = Bitmap.createBitmap (getWidth ( ), getHeight ( ), Bitmap.Config.ARGB_8888);
        //调用ImageView.draw(),再目标Bitmap上绘制缩放调整后的Bitmap
        super.draw (new Canvas (target));
        //清空原canvas, 这里要关闭硬件加速, 否则会绘制出黑色背景
        canvas.drawColor (Color.TRANSPARENT, PorterDuff.Mode.CLEAR);
        //绘制底板形状
        mPath.addRoundRect (mRect, mRadiusArray, Path.Direction.CCW);
        canvas.drawPath (mPath, mBackgroundPaint);
        //绘制目标Bitmap到Canvas
        canvas.drawBitmap (target, 0, 0, mContentPaint);
    } else {
        super.draw (canvas);
    }
}

完整圆角ImageView代码如下

package com.example.crxzy.centertainment.views;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.ImageDecoder;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.RectF;
import android.graphics.drawable.BitmapDrawable;
import android.support.annotation.Nullable;
import android.util.AttributeSet;
import android.view.View;

import com.example.crxzy.centertainment.R;

import java.util.Arrays;
import java.util.Objects;

public class RoundedImageView extends ImageView {
    private RectF mRect = new RectF ( );
    private float[] mRadiusArray = new float[8];
    private Path mPath = new Path ( );
    PorterDuffXfermode porterDuffXfermode = new PorterDuffXfermode (PorterDuff.Mode.SRC_IN);
    private Paint mBackgroundPaint;
    private Paint mContentPaint;

    public RoundedImageView(Context context) {
        super (context);
        initBackgroundPaint (context);
        initContentPaint ( );
        setLayerType (LAYER_TYPE_HARDWARE, null);
    }

    private void initContentPaint() {
        mContentPaint = new Paint (Paint.ANTI_ALIAS_FLAG);
        mContentPaint.setXfermode (porterDuffXfermode);
    }

    private void initBackgroundPaint(Context context) {
        mBackgroundPaint = new Paint (Paint.ANTI_ALIAS_FLAG);
        mBackgroundPaint.setStyle (Paint.Style.FILL);
        mBackgroundPaint.setColor (context.getColor (R.color.gray));
        mBackgroundPaint.setAntiAlias (true);//消除锯齿
    }

    @Override
    public void draw(Canvas canvas) {
        //判断Drawable是否是Bitmap
        if (getDrawable ( ) instanceof BitmapDrawable) {
            //获取当前View尺寸建立Rect
            mRect.set (0, 0, getWidth ( ), getHeight ( ));
            //创建目标Bitmap
            Bitmap target = Bitmap.createBitmap (getWidth ( ), getHeight ( ), Bitmap.Config.ARGB_8888);
            //调用ImageView.draw(),再目标Bitmap上绘制缩放调整后的Bitmap
            super.draw (new Canvas (target));
            //清空原canvas, 这里要关闭硬件加速, 否则会绘制出黑色背景
            canvas.drawColor (Color.TRANSPARENT, PorterDuff.Mode.CLEAR);
            //绘制底板形状
            mPath.addRoundRect (mRect, mRadiusArray, Path.Direction.CCW);
            canvas.drawPath (mPath, mBackgroundPaint);
            //绘制目标Bitmap到Canvas
            canvas.drawBitmap (target, 0, 0, mContentPaint);
        } else {
            super.draw (canvas);
        }
    }

    public RoundedImageView(Context context, @Nullable AttributeSet attrs) {
        super (context, attrs);

        TypedArray typedArray = context.obtainStyledAttributes (attrs, R.styleable.RoundedImageView);
        if (typedArray != null) {
            Arrays.fill (mRadiusArray, typedArray.getDimension (R.styleable.RoundedImageView_radius, 0));
            mRadiusArray[0] = mRadiusArray[1] = typedArray.getDimension (R.styleable.RoundedImageView_bottomLeftRadius, mRadiusArray[0]);
            mRadiusArray[2] = mRadiusArray[3] = typedArray.getDimension (R.styleable.RoundedImageView_bottomRightRadius, mRadiusArray[2]);
            mRadiusArray[4] = mRadiusArray[5] = typedArray.getDimension (R.styleable.RoundedImageView_topLeftRadius, mRadiusArray[4]);
            mRadiusArray[6] = mRadiusArray[7] = typedArray.getDimension (R.styleable.RoundedImageView_topRightRadius, mRadiusArray[6]);
        }
        Objects.requireNonNull (typedArray).recycle ( );
        initBackgroundPaint (context);
        initContentPaint ( );
        setLayerType (LAYER_TYPE_HARDWARE, null);
    }

    public void setCornerSize(float cornerSize) {
        Arrays.fill (mRadiusArray, cornerSize);
    }
}

attr.xml 内容

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <!--属性集合-->
    <declare-styleable name="RoundedImageView">
        <attr name="bottomLeftRadius" format="dimension" />
        <attr name="topLeftRadius" format="dimension" />
        <attr name="bottomRightRadius" format="dimension" />
        <attr name="topRightRadius" format="dimension" />
        <attr name="radius" format="dimension" />
    </declare-styleable>
</resources>

BitmapShader版

Shader是Paint的着色器,提供Paint在当前位置上笔头的颜色信息,不理解的化参考一下PS的仿制图章。我们利用Shader和Path直接绘制一个圆角矩形。

核心代码如下

 @Override
    public void draw(Canvas canvas) {
        //判断Drawable是否是Bitmap
        if (getDrawable ( ) instanceof BitmapDrawable) {
            //获取当前View尺寸建立Rect
            mRect.set (0, 0, getWidth ( ), getHeight ( ));
            //创建目标Bitmap
            Bitmap target = Bitmap.createBitmap (getWidth ( ), getHeight ( ), Bitmap.Config.ARGB_8888);
            //使用View.draw方法得到经过拉升变换后的bitmap
            super.draw (new Canvas (target));
            //利用目标Bitmap创建设置着色器
            BitmapShader shader = new BitmapShader (target, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
            mPaint.setShader (shader);
            //绘制View形状
            mPath.addRoundRect (mRect, mRadiusArray, Path.Direction.CCW);
            canvas.drawPath (mPath, mPaint);
        } else {
            super.draw (canvas);
        }
    }

完整圆角ImageView代码如下

package com.example.crxzy.centertainment.views;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.BitmapShader;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.RectF;
import android.graphics.Shader;
import android.graphics.drawable.BitmapDrawable;
import android.support.annotation.Nullable;
import android.util.AttributeSet;

import com.example.crxzy.centertainment.R;

import java.util.Arrays;
import java.util.Objects;

public class RoundedImageView extends ImageView {
    private RectF mRect = new RectF ( );
    private Path mPath = new Path ( );
    private Paint mPaint;
    private float[] mRadiusArray = new float[8];

    PorterDuffXfermode porterDuffXfermode = new PorterDuffXfermode (PorterDuff.Mode.SRC_IN);

    public RoundedImageView(Context context) {
        super (context);
        initPaint (context);
        setLayerType (LAYER_TYPE_HARDWARE, null);
    }

    public RoundedImageView(Context context, @Nullable AttributeSet attrs) {
        super (context, attrs);

        TypedArray typedArray = context.obtainStyledAttributes (attrs, R.styleable.RoundedImageView);
        if (typedArray != null) {
            Arrays.fill (mRadiusArray, typedArray.getDimension (R.styleable.RoundedImageView_radius, 0));
            mRadiusArray[0] = mRadiusArray[1] = typedArray.getDimension (R.styleable.RoundedImageView_bottomLeftRadius, mRadiusArray[0]);
            mRadiusArray[2] = mRadiusArray[3] = typedArray.getDimension (R.styleable.RoundedImageView_bottomRightRadius, mRadiusArray[2]);
            mRadiusArray[4] = mRadiusArray[5] = typedArray.getDimension (R.styleable.RoundedImageView_topLeftRadius, mRadiusArray[4]);
            mRadiusArray[6] = mRadiusArray[7] = typedArray.getDimension (R.styleable.RoundedImageView_topRightRadius, mRadiusArray[6]);
        }
        Objects.requireNonNull (typedArray).recycle ( );
        initPaint (context);
        setLayerType (LAYER_TYPE_HARDWARE, null);
    }


    private void initPaint(Context context) {
        mPaint = new Paint (Paint.ANTI_ALIAS_FLAG);
        mPaint.setStyle (Paint.Style.FILL);
        mPaint.setAntiAlias (true);//消除锯齿
    }

    @Override
    public void draw(Canvas canvas) {
        //判断Drawable是否是Bitmap
        if (getDrawable ( ) instanceof BitmapDrawable) {
            //获取当前View尺寸建立Rect
            mRect.set (0, 0, getWidth ( ), getHeight ( ));
            //创建目标Bitmap
            Bitmap target = Bitmap.createBitmap (getWidth ( ), getHeight ( ), Bitmap.Config.ARGB_8888);
            //使用View.draw方法得到经过拉升变换后的bitmap
            super.draw (new Canvas (target));
            //利用目标Bitmap创建设置着色器
            BitmapShader shader = new BitmapShader (target, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
            mPaint.setShader (shader);
            //绘制View形状
            mPath.addRoundRect (mRect, mRadiusArray, Path.Direction.CCW);
            canvas.drawPath (mPath, mPaint);
        } else {
            super.draw (canvas);
        }
    }


    public void setCornerSize(float cornerSize) {
        Arrays.fill (mRadiusArray, cornerSize);
    }
}

attr.xml 内容

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <!--属性集合-->
    <declare-styleable name="RoundedImageView">
        <attr name="bottomLeftRadius" format="dimension" />
        <attr name="topLeftRadius" format="dimension" />
        <attr name="bottomRightRadius" format="dimension" />
        <attr name="topRightRadius" format="dimension" />
        <attr name="radius" format="dimension" />
    </declare-styleable>
</resources>

相关文章

网友评论

      本文标题:自定义圆角ImageView

      本文链接:https://www.haomeiwen.com/subject/jouhlhtx.html