自定义View实战六:实现圆形、圆角图片

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接: https://blog.csdn.net/songzi1228/article/details/102635699

目录

0、相关文章:

1、文章一

1.1、RoundImageView.java

1.2、RoundImageViewActivity.java

1.3、activity_round_image_view.xml

2、文章二:

2.1、RoundIVByXfermode.java

2.2、activity_round_i_by_xfer.xml

 


 

0、相关文章:

Android BitmapShader 实战 实现圆形、圆角图片(文章一:鸿洋,阅读量11w,70赞,该文的评论中说可能有性能方面的问题)

Android Xfermode 实战 实现圆形、圆角图片(文章二:鸿洋,阅读量5.4w,33赞,该文的评论中说可能有性能方面的问题,可能会导致oom)

Android 圆角圆形ImageView(超简单实现)(阅读量3w,12赞,也有一定问题)

Android - 实现图片圆角显示的几种方式(阅读量7k)

Android中图片圆形设置三种方法介绍(阅读量7k)

Android 正 N 边形圆角头像的实现(阅读量1.2k)

Android 圆角图形和圆角头像的完美实(阅读量389)

android实现圆形头像(阅读量200)

android开发学习 ------- 自定义View 圆 ,其点击事件 及 确定当前view的层级关系(自定义画两个圆,以及设置对应的点击事件)

1、文章一

参照文章一的实现代码:

效果如下:

1.1、RoundImageView.java

public class RoundImageView extends android.support.v7.widget.AppCompatImageView {

    //图片的类型,圆形or圆角
    private int mType;
    public static final int TYPE_CIRCLE = 0;
    public static final int TYPE_ROUND = 1;

    //圆角的大小
    private int mBorderRadius;

    //圆角大小的默认值
    private static final int DEFAULT_BORDER_RADIUS = 10;

    //圆角的半径
    private int mRadius;

    //画图的颜料:paint
    private Paint mBitmapPaint;

    //3*3矩阵 主要用于缩放大小
    private Matrix mMatrix;

    //渲染图像,使用图像为绘制图形着色
    private BitmapShader mBitmapShader;

    //view的宽度
    private int mWidth;

    private RectF mRoundRect;

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

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

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

        mMatrix = new Matrix();
        mBitmapPaint = new Paint();
        mBitmapPaint.setAntiAlias(true);

        mRoundRect = new RectF();

        TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.RoundImageView);

        mBorderRadius = typedArray.getDimensionPixelSize(R.styleable.RoundImageView_borderRadius,
                (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, DEFAULT_BORDER_RADIUS,
                        getResources().getDisplayMetrics()));//默认为10dp

        mType = typedArray.getInt(R.styleable.RoundImageView_type, TYPE_CIRCLE);//默认为circle

        typedArray.recycle();
    }

    /**
     * 我们复写了onMeasure方法,主要用于当设置类型为圆形时,我们强制让view的宽和高一致。
     */
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
//        LogUtils.e("onMeasure");

        //如果类型是圆形,则强制改变view的宽高度一致,以最小值为准
        if (mType == TYPE_CIRCLE) {
            mWidth = Math.min(getMeasuredWidth(), getMeasuredHeight());
            mRadius = mWidth / 2;
            setMeasuredDimension(mWidth, mWidth);
        }
    }

    @Override
    protected void onDraw(Canvas canvas) {

        if (getDrawable() == null) return;

        setUpShader();

        if (mType == TYPE_ROUND) {
            canvas.drawRoundRect(mRoundRect, mBorderRadius, mBorderRadius, mBitmapPaint);
        } else {
            canvas.drawCircle(mRadius, mRadius, mRadius, mBitmapPaint);
        }
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        //圆角图片的范围
        if (mType == TYPE_ROUND) {
            mRoundRect = new RectF(0, 0, getWidth(), getHeight());
        }
    }

    private static final String STATE_INSTANCE = "state_instance";
    private static final String STATE_TYPE = "state_type";
    private static final String STATE_BORDER_RADIUS = "state_border_radius";

    /**
     * 状态存储
     *
     * @return
     */
    @Nullable
    @Override
    protected Parcelable onSaveInstanceState() {
        Bundle bundle = new Bundle();
        bundle.putParcelable(STATE_INSTANCE, super.onSaveInstanceState());
        bundle.putInt(STATE_TYPE, mType);
        bundle.putInt(STATE_BORDER_RADIUS, mBorderRadius);
        return bundle;
    }

    /**
     * 状态恢复
     *
     * @param state
     */
    @Override
    protected void onRestoreInstanceState(Parcelable state) {
        if (state instanceof Bundle) {
            Bundle bundle = (Bundle) state;
            super.onRestoreInstanceState(bundle.getParcelable(STATE_INSTANCE));
            this.mType = bundle.getInt(STATE_TYPE);
            this.mBorderRadius = bundle.getInt(STATE_BORDER_RADIUS);
        } else {
            super.onRestoreInstanceState(state);
        }
    }

    /**
     * 对外公开的方法:动态修改圆角大小
     */
    public void setBorderRadius(int borderRadius) {
        int pxVal = dp2px(borderRadius);
        if (this.mBorderRadius != pxVal) {
            this.mBorderRadius = pxVal;
            invalidate();
        }
    }

    /**
     * 对外公开的方法:动态修改type
     */
    public void setType(int type) {
        if (this.mType != type) {
            this.mType = type;
            if (this.mType != TYPE_ROUND && this.mType != TYPE_CIRCLE) {
                this.mType = TYPE_CIRCLE;
            }
            requestLayout();
        }
    }

    /**
     * 对外公开的方法:改变type
     */
    public void changeType() {
        if (this.mType == TYPE_ROUND) {
            this.mType = TYPE_CIRCLE;
        } else if (this.mType == TYPE_CIRCLE) {
            this.mType = TYPE_ROUND;
        }
        requestLayout();

    }

    public int dp2px(int dpVal) {
        return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dpVal,
                getResources().getDisplayMetrics());
    }

    /**
     * 初始化BitmapShader
     */
    private void setUpShader() {
        Drawable drawable = getDrawable();
        if (drawable == null) return;

        Bitmap bitmap = drawableToBitmap(drawable);
        //将bitmap作为着色器,就是在指定区域绘制bitmap
        //Shader在三维软件中我们称之为着色器,其作用嘛就像它的名字一样是来给图像着色的或者更通俗的说法是上色
        mBitmapShader = new BitmapShader(bitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
        float scale = 1.0f;
        if (mType == TYPE_CIRCLE) {
            //拿到bitmap宽或高的最小值
            int bitmapSize = Math.min(bitmap.getWidth(), bitmap.getHeight());
            scale = mWidth * 1.0f / bitmapSize;

        } else if (mType == TYPE_ROUND) {
            //如果图片的宽或高与view的宽高不匹配,计算出需要缩放的比例;缩放后的图片的宽高,一定要大于我们
            // view的宽高,所以我们这里取大值
            scale = Math.max(getWidth() * 1.0f / bitmap.getWidth(), getHeight() * 1.0f / bitmap.getHeight());
        }
        //shader的变换矩阵,我们这里主要用于放大或缩小
        mMatrix.setScale(scale, scale);
        //设置变换矩阵
        mBitmapShader.setLocalMatrix(mMatrix);
        //设置shader
        mBitmapPaint.setShader(mBitmapShader);
    }

    /**
     * drawable转bitmap
     */
    private Bitmap drawableToBitmap(Drawable drawable) {
        if (drawable instanceof BitmapDrawable) {
            BitmapDrawable bitmapDrawable = (BitmapDrawable) drawable;
            return bitmapDrawable.getBitmap();
        }

        int width = drawable.getIntrinsicWidth();
        int height = drawable.getIntrinsicHeight();
        Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
        Canvas canvas = new Canvas(bitmap);
        drawable.setBounds(0, 0, width, height);
        drawable.draw(canvas);
        return bitmap;
    }


}

1.2、RoundImageViewActivity.java

public class RoundImageViewActivity extends AppCompatActivity {


    @BindView(R.id.round_image_view01)
    RoundImageView roundImageView01;
    @BindView(R.id.round_image_view02)
    RoundImageView roundImageView02;
    @BindView(R.id.round_image_view03)
    RoundImageView roundImageView03;
    @BindView(R.id.round_image_view04)
    RoundImageView roundImageView04;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_round_image_view);
        ButterKnife.bind(this);

    }

    @OnClick({R.id.round_image_view01, R.id.round_image_view02, R.id.round_image_view03, R.id.round_image_view04})
    public void onViewClicked(View view) {
        switch (view.getId()) {
            case R.id.round_image_view01:
                roundImageView01.changeType();
                break;
            case R.id.round_image_view02:
                roundImageView02.setType(RoundImageView.TYPE_CIRCLE);
                break;
            case R.id.round_image_view03:

                break;
            case R.id.round_image_view04:
                roundImageView04.setBorderRadius(90);
                break;
        }
    }
}

1.3、activity_round_image_view.xml

<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:background="@color/light_blue_2e"
    >

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical">

        <com.gs.common3.aView.customView.roundIV.RoundImageView
            android:id="@+id/round_image_view01"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:src="@mipmap/keji01"/>

        <com.gs.common3.aView.customView.roundIV.RoundImageView
            android:id="@+id/round_image_view02"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginTop="10dp"
            android:src="@mipmap/keji01"
            app:borderRadius="60dp"
            app:type="round"/>


        <com.gs.common3.aView.customView.roundIV.RoundImageView
            android:id="@+id/round_image_view03"
            android:layout_width="200dp"
            android:layout_height="200dp"
            android:layout_margin="10dp"
            android:src="@mipmap/keji02"/>

        <com.gs.common3.aView.customView.roundIV.RoundImageView
            android:id="@+id/round_image_view04"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_margin="10dp"
            android:src="@mipmap/keji02"
            app:borderRadius="20dp"
            app:type="round"/>


    </LinearLayout>


</ScrollView>

2、文章二:

按照文章二编码:

效果如下:有问题。

2.1、RoundIVByXfermode.java

public class RoundIVByXfermode extends AppCompatImageView {

    private Paint mPaint;
    private Xfermode mXfermode;
    private Bitmap mMaskBitmap;
    private WeakReference<Bitmap> mWeakBitmap;

    //图片的类型,圆形or圆角
    private int type;
    public static final int TYPE_CIRCLE = 0;
    public static final int TYPE_ROUND = 1;

    //圆角大小的默认值
    private static final int BORDER_RADIUS_DEFAULT = 10;

    //圆角的大小
    private int mBorderRadius;

    public RoundIVByXfermode(Context context) {
        this(context, null);

        mPaint = new Paint();
        mPaint.setAntiAlias(true);
    }

    public RoundIVByXfermode(Context context, AttributeSet attrs) {
        super(context, attrs);

        mPaint = new Paint();
        mPaint.setAntiAlias(true);

        TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.RoundIVByXfermode);
        mBorderRadius = (int) typedArray.getDimension(R.styleable.RoundIVByXfermode_borderRadius,
                TypedValue.applyDimension(
                        TypedValue.COMPLEX_UNIT_DIP, BORDER_RADIUS_DEFAULT,
                        getResources().getDisplayMetrics()));//默认为10dp
        type = typedArray.getInt(R.styleable.RoundIVByXfermode_type, TYPE_CIRCLE);//默认为circle


        typedArray.recycle();
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        //如果类型是圆形,则强制改变view的宽高一致,以最小值为准
        if (type == TYPE_CIRCLE) {
            int width = Math.min(getMeasuredWidth(), getMeasuredHeight());
            setMeasuredDimension(width, width);
        }
    }

    @SuppressLint("DrawAllocation")
    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        //在缓存中取出bitmap
        Bitmap bitmap = mWeakBitmap == null ? null : mWeakBitmap.get();

        if (bitmap == null || bitmap.isRecycled()) {
            //拿到drawable
            Drawable drawable = getDrawable();
            //获取drawable的宽和高
            int dWidth = drawable.getIntrinsicWidth();
            int dHeight = drawable.getIntrinsicHeight();

            if (drawable != null) {
                //创建bitmap
                bitmap = Bitmap.createBitmap(getWidth(), getHeight(), Bitmap.Config.ARGB_8888);
                float scale = 1.0f;

                //创建画布
                Canvas drawCanvas = new Canvas(bitmap);
                //按照bitmap的宽高,以及view的宽高,计算缩放比例;因为设置的src宽高比例可能和
                // imageview的宽高比例不同,这里我们不希望图片失真;
                if (type == TYPE_ROUND) {
                    // 如果图片的宽或者高与view的宽高不匹配,计算出需要缩放的比例;缩放后的图片的宽高,
                    // 一定要大于我们view的宽高;所以我们这里取大值;
                    scale = Math.max(getWidth() * 1.0f / dWidth, getHeight() * 1.0f / dHeight);
                } else {
                    scale = getWidth() * 1.0f / Math.min(dWidth, dHeight);
                }
                //根据缩放比例,设置bounds,相当于缩放图片了
                drawable.setBounds(0, 0, (int) scale * dWidth,
                        (int) scale * dHeight);
                drawable.draw(drawCanvas);
                if (mMaskBitmap == null || mMaskBitmap.isRecycled()) {
                    mMaskBitmap = getBitmap();
                }

                //draw bitmap
                mPaint.reset();
                mPaint.setFilterBitmap(false);
                mPaint.setXfermode(mXfermode);
                //绘制形状
                drawCanvas.drawBitmap(mMaskBitmap, 0, 0, mPaint);
                mPaint.setXfermode(null);
                //将准备好的bitmap绘制出来
                canvas.drawBitmap(bitmap, 0, 0, null);
                //bitmap缓存起来,避免每次调用onDraw,分配内存
                mWeakBitmap = new WeakReference<Bitmap>(bitmap);
            }
        }
        //如果bitmap还在,直接绘制即可
        if (bitmap != null) {
            mPaint.setXfermode(null);
            canvas.drawBitmap(bitmap, 0.0f, 0.0f, mPaint);
        }
    }

    /**
     * 主要是因为我们缓存了,当调用invalidate时,将缓存清除。
     */
    @Override
    public void invalidate() {
        mWeakBitmap = null;
        if (mMaskBitmap != null) {
            mMaskBitmap.recycle();
            mMaskBitmap = null;
        }
        super.invalidate();
    }

    /**
     * 绘制形状
     */
    private Bitmap getBitmap() {
        Bitmap bitmap = Bitmap.createBitmap(getWidth(), getHeight(), Bitmap.Config.ARGB_8888);
        Canvas canvas = new Canvas(bitmap);
        Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
        paint.setColor(Color.BLACK);

        if (type == TYPE_ROUND) {
            canvas.drawRoundRect(new RectF(0, 0, getWidth(), getHeight()),
                    mBorderRadius, mBorderRadius, paint);
        } else {
            canvas.drawCircle(getWidth() / 2, getWidth() / 2, getWidth() / 2, paint);
        }
        return bitmap;
    }
}

2.2、activity_round_i_by_xfer.xml

<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="wrap_content">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical">

        <com.gs.common3.aView.customView.roundIV.RoundIVByXfermode
            android:id="@+id/riv01"
            android:layout_width="130dp"
            android:layout_height="130dp"
            android:layout_margin="10dp"
            android:src="@mipmap/keji01" />

        <com.gs.common3.aView.customView.roundIV.RoundIVByXfermode
            android:id="@+id/riv02"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_margin="10dp"
            android:src="@mipmap/keji01"
            app:borderRadius="30dp" />

        <com.gs.common3.aView.customView.roundIV.RoundIVByXfermode
            android:id="@+id/riv03"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_margin="10dp"
            android:src="@mipmap/keji01"
            app:type="circle" />

        <com.gs.common3.aView.customView.roundIV.RoundIVByXfermode
            android:id="@+id/riv04"
            android:layout_width="40dp"
            android:layout_height="40dp"
            android:layout_margin="10dp"
            android:src="@mipmap/keji01"
            app:type="round" />

    </LinearLayout>


</ScrollView>

 

猜你喜欢

转载自blog.csdn.net/songzi1228/article/details/102635699