美文网首页我爱编程
Android自定义圆角图片

Android自定义圆角图片

作者: 香烟和白粥 | 来源:发表于2018-07-26 15:37 被阅读227次

    回顾一下,自定义view重写的关键方法有:

    measure 测量组件本身的大小
    layout 确定组件在视图中的位置
    draw 根据位置和大小,将组件画出来

    • float[] radii:必须传入8个数值,分四组,分别对应每个角所使用的椭圆的横轴半径和纵轴半径,如{x1,y1,x2,y2,x3,y3,x4,y4},其中,x1,y1对应第一个角的(左上角)用来产生圆角的椭圆的横轴半径和纵轴半径,其它类推……

    • 定义几种圆角模式

        /**
         * 圆形模式
         */
        private static final int MODE_CIRCLE = 1;
        /**
         * 普通模式
         */
        private static final int MODE_NONE = 0;
        /**
         * 圆角模式
         */
        private static final int MODE_ROUND = 2;
        /**
         * 上面的圆角模式
         */
        private static final int MODE_ROUND_TOP = 3;
    
        /**
         * 下方圆角模式
         */
        private static final int MODE_ROUND_BOTTOM = 4;
    
    • attr文件中定义
        <declare-styleable name="RoundImageview">
            <attr name="viewtype" format="enum">
                <enum name="circle" value="1"/>
                <enum name="round" value="2"/>
                <enum name="roundtop" value="3"/>
                <enum name="round_bottom" value="4"/>
            </attr>
            <attr name="radius" format="dimension"/>
        </declare-styleable>
    
    • 准备就绪(画笔,矩阵等对象,不要在ondraw的时候去new对象,因为ondraw会被调用多次,容易导致内存泄露)
      private static final int MODE_ROUND_BOTTOM = 4;
        private BitmapShader bitmapShader;
    
        private Paint mPaint;
        private int currMode = 0;
        private Path path = new Path();
        private RectF rectF = new RectF();
        private Matrix matrix = new Matrix();
        private Bitmap bitmap;
        // 圆角矩形路径
        private float[] radii = new float[8];
        /**
         * 圆角半径
         */
        private int currRound = dp2px(10);
    
        private int dp2px(float value) {
            return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, value, getResources().getDisplayMetrics());
        }
    
    • 重写三个构造函数 ,并在里面初始化数据
     public RoundImageview(Context context) {
            super(context);
            initViews();
        }
    
        public RoundImageview(Context context, AttributeSet attrs) {
            this(context, attrs, 0);
        }
    
        public RoundImageview(Context context, AttributeSet attrs, int defStyleAttr) {
            super(context, attrs, defStyleAttr);
            obtainStyledAttrs(context, attrs, defStyleAttr);
            initViews();
        }
    
    
        private void obtainStyledAttrs(Context context, AttributeSet attrs, int defStyleAttr) {
            TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.RoundImageview, defStyleAttr, 0);
            currMode = a.hasValue(R.styleable.RoundImageview_viewtype) ? a.getInt(R.styleable.RoundImageview_viewtype, MODE_NONE) : MODE_NONE;
            currRound = a.hasValue(R.styleable.RoundImageview_radius) ? a.getDimensionPixelSize(R.styleable.RoundImageview_radius, currRound) : currRound;
            //用完后记得回收
            a.recycle();
        }
    
        private void initViews() {
            mPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.DITHER_FLAG);
        }
    
    
    • 测量
    @Override
        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
            /*
             * 当模式为圆形模式的时候,我们强制让宽高一致
             */
            if (currMode == MODE_CIRCLE) {
                super.onMeasure(widthMeasureSpec, heightMeasureSpec);
                int result = Math.min(getMeasuredHeight(), getMeasuredWidth());
                setMeasuredDimension(result, result);
            } else {
                super.onMeasure(widthMeasureSpec, heightMeasureSpec);
            }
            path.reset();
            rectF.left = getPaddingLeft();
            rectF.top = getPaddingTop();
            rectF.right = getMeasuredWidth() - getPaddingRight();
            rectF.bottom = getMeasuredHeight() - getPaddingBottom();
            switch (currMode) {
                case MODE_ROUND_TOP:
                    fillRadii(currRound, currRound, currRound, currRound, 0, 0, 0, 0);
                    break;
                case MODE_ROUND_BOTTOM:
                    fillRadii(0, 0, 0, 0, currRound, currRound, currRound, currRound);
                    break;
                case MODE_ROUND:
                    fillRadii(currRound, currRound, currRound, currRound, currRound, currRound, currRound, currRound);
                    break;
                default:
                    fillRadii(0, 0, 0, 0, 0, 0, 0, 0);
                    break;
            }
            path.addRoundRect(rectF, radii, Path.Direction.CCW);
            if (bitmapShader != null && bitmap != null && getMeasuredHeight() > 0 && getMeasuredWidth() > 0) {
                matrix.reset();
                float sx = getMeasuredWidth() / (float)bitmap.getWidth();
                float sy = getMeasuredHeight() / (float)bitmap.getHeight();
                float scale = Math.max(sx,sy);
                matrix.postScale(scale, scale);
                bitmapShader.setLocalMatrix(matrix);
            }
    
        }
      private void fillRadii(float... radii) {
            System.arraycopy(radii, 0, this.radii, 0, 8);
        }
    
    • 开始画啦
    @Override
        protected void onDraw(Canvas canvas) {
            final int saveCount = canvas.getSaveCount();
            canvas.save();
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
                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());
            mPaint.reset();
            if (bitmapShader != null) {
                if (currMode == MODE_CIRCLE) {//当为圆形模式的时候
                    mPaint.setShader(bitmapShader);
                    canvas.drawCircle(getWidth() / 2, getHeight() / 2, getWidth() / 2, mPaint);
                } else if (currMode == MODE_ROUND) {//当为圆角模式的时候
                    mPaint.setShader(bitmapShader);
                    canvas.drawRoundRect(rectF,
                            currRound, currRound, mPaint);
                } else if (currMode == MODE_ROUND_TOP || currMode == MODE_ROUND_BOTTOM) {//当为上/下圆角模式的时候
                    mPaint.setShader(bitmapShader);
                    canvas.drawPath(path, mPaint);
                } else {
                    mPaint.setShader(bitmapShader);
                    canvas.drawPath(path, mPaint);
                }
            }
            canvas.restoreToCount(saveCount);
        }
    
    • 最后暴露一个方法来设置图片资源
        public void setImage(@Nullable Bitmap bitmap) {
            if (bitmap == null) return;
            bitmapShader = new BitmapShader(bitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
            this.bitmap = bitmap;
            requestLayout();
        }
    
    

    参考:https://blog.csdn.net/harvic880925/article/details/38926877

    相关文章

      网友评论

        本文标题:Android自定义圆角图片

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