美文网首页Android自定义View
自定义ImageView——支持ImageView的形状和倒角大

自定义ImageView——支持ImageView的形状和倒角大

作者: Peakmain | 来源:发表于2019-06-04 10:28 被阅读7次

    Github地址:https://github.com/Peakmain/extendUI

    效果图


    image.png

    首先需要自定义属性

      <declare-styleable name="ExtendImageView">
            <attr name="extend_border_color" format="color" />
            <attr name="extend_border_width" format="dimension" />
            <attr name="extend_press_alpha" format="integer" />
            <attr name="extend_press_color" format="color" />
            <attr name="extend_radius" format="dimension" />
            <attr name="extend_shape_type" format="enum">
                <enum name="none" value="0" />
                <enum name="round" value="1" />
                <enum name="rectangle" value="2" />
            </attr>
        </declare-styleable>
    

    初始化数据和解析自定义属性

    //当用户按下的时候paint
      private Paint pressPaint;
      private int width;
      private int height;
    
      //默认图片配置
      private static final Bitmap.Config BITMAP_CONFIG = Bitmap.Config.ARGB_8888;
    
      //宽度的颜色
      private int borderColor;
      //边框的宽度
      private int borderWidth;
      //按下的时候的透明度变化
      private int pressAlpha;
      //按下的时候的颜色
      private int pressColor;
      //半径
      private int radius;
      //类型:1、圆形 2、矩形
      private int shapeType;
    
      public ExtendImageView(Context context) {
          super(context);
          init(context, null);
      }
    
      public ExtendImageView(Context context, @Nullable AttributeSet attrs) {
          super(context, attrs);
          init(context, attrs);
      }
    
    
      public ExtendImageView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
          super(context, attrs, defStyleAttr);
          init(context, attrs);
      }
    
      private void init(Context context, AttributeSet attrs) {
          //初始化值
          borderWidth = 0;
          borderColor = 0xddffffff;
          pressAlpha = 0x42;
          pressColor = 0x4200000;
          radius = 16;
          shapeType = 0;
    
          //解析自定义属性
          if (attrs != null) {
              TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.ExtendImageView);
              borderColor = array.getColor(R.styleable.ExtendImageView_extend_border_color, borderColor);
              borderWidth = array.getDimensionPixelOffset(R.styleable.ExtendImageView_extend_border_width, borderWidth);
              pressAlpha = array.getInteger(R.styleable.ExtendImageView_extend_press_alpha, pressAlpha);
              pressColor = array.getColor(R.styleable.ExtendImageView_extend_press_color, pressColor);
              radius = array.getDimensionPixelOffset(R.styleable.ExtendImageView_extend_radius, radius);
              shapeType = array.getInteger(R.styleable.ExtendImageView_extend_shape_type, shapeType);
              array.recycle();
          }
          //按下的时候设置画笔
          pressPaint = new Paint();
          pressPaint.setAntiAlias(true);
          pressPaint.setStyle(Paint.Style.FILL);
          pressPaint.setColor(pressColor);
          pressPaint.setAlpha(0);
          pressPaint.setFlags(Paint.ANTI_ALIAS_FLAG);
    
          //保证我们可以重写onDraw方法
          setDrawingCacheEnabled(true);
          setWillNotDraw(false);
      }
    

    接下来就是绘制了,我们首先需要去获取到bitmap然后进行绘制

        @Override
        protected void onDraw(Canvas canvas) {
            //默认情况下就直接返回就可以了
            if (shapeType == 0) {
                super.onDraw(canvas);
                return;
            }
            Drawable drawable = getDrawable();
            if (drawable == null) {
                return;
            }
            //宽高为空也直接返回
            if (getWidth() == 0 || getHeight() == 0) {
                return;
            }
            //从drawable中获取bitmao
            Bitmap bitmap = getBitmapFromDrawable(drawable);
            drawDrawable(canvas, bitmap);
            if (isClickable()) {
                drawPress(canvas);
            }
            drawBorder(canvas);
        }
    

    从drawable中获取bitmap

       /**
         * 从drawable中获取bitmap
         *
         * @param drawable
         * @return
         */
        private Bitmap getBitmapFromDrawable(Drawable drawable) {
            if (drawable == null) {
                return null;
            }
            if (drawable instanceof BitmapDrawable) {
                return ((BitmapDrawable) drawable).getBitmap();
            }
            Bitmap bitmap;
            //返回图片的真实宽高
            int width = Math.max(drawable.getIntrinsicWidth(), 2);
            int height = Math.max(drawable.getIntrinsicHeight(), 2);
            //创建bitmap
            try {
                bitmap = Bitmap.createBitmap(width, height, BITMAP_CONFIG);
                Canvas canvas = new Canvas(bitmap);
                drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
                drawable.draw(canvas);
            } catch (Exception e) {
                e.printStackTrace();
                bitmap = null;
            }
            return bitmap;
        }
    

    绘制drawable

       /**
         * 绘制drawable
         *
         * @param canvas canvas
         * @param bitmap bitmap
         */
        private void drawDrawable(Canvas canvas, Bitmap bitmap) {
            Paint paint = new Paint();
            paint.setColor(0xffffffff);
            //设置抗锯齿
            paint.setAntiAlias(true);
            PorterDuffXfermode xfermode = new PorterDuffXfermode(PorterDuff.Mode.SRC_IN);
            //6.0之前需要通过反射执行
            if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
                // 设置 flags
                int saveFlags = CanvasSave.MATRIX_SAVE_FLAG
                        | CanvasSave.CLIP_SAVE_FLAG
                        | CanvasSave.HAS_ALPHA_LAYER_SAVE_FLAG
                        | CanvasSave.FULL_COLOR_LAYER_SAVE_FLAG
                        | CanvasSave.CLIP_TO_LAYER_SAVE_FLAG;
    
                CanvasSave.saveLayer(canvas, 0, 0, width, height, null, saveFlags);
    
            } else {
                canvas.saveLayer(0, 0, width, height, null);
            }
            if (shapeType == 1) {
                canvas.drawCircle(width / 2, height / 2, width / 2 - 1, paint);
            } else if (shapeType == 2) {
                RectF rectF = new RectF(1, 1, getWidth() - 1, getHeight() - 1);
                canvas.drawRoundRect(rectF, radius + 1, radius + 1, paint);
            }
            //设置图层样式
            paint.setXfermode(xfermode);
            float scaleWidth = ((float) getWidth()) / bitmap.getWidth();
            float scaleHeight = ((float) getHeight()) / bitmap.getHeight();
            Matrix matrix = new Matrix();
            matrix.postScale(scaleWidth, scaleHeight);
            bitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
            canvas.drawBitmap(bitmap, 0, 0, paint);
            canvas.restore();
        }
    

    绘制border和按下时的绘制

    
        /**
         * 当手指按下的时候
         *
         * @param canvas 画布
         */
        private void drawPress(Canvas canvas) {
            if (shapeType == 1) {
                //圆形
                int radius = width > height ? (width - borderWidth) / 2 : (height - borderWidth) / 2;
                canvas.drawCircle(width / 2, height / 2, radius, pressPaint);
            } else {
                RectF rectF = new RectF(1, 1, width - 1, height - 1);
                canvas.drawRoundRect(rectF, radius + 1, radius + 1, pressPaint);
            }
        }
    
        /**
         * 绘制自定义border
         */
    
        private void drawBorder(Canvas canvas) {
            if (borderWidth > 0) {
                Paint paint = new Paint();
                paint.setStrokeWidth(borderWidth);
                paint.setStyle(Paint.Style.STROKE);
                paint.setColor(borderColor);
                paint.setAntiAlias(true);
                //圆形
                if (shapeType == 1) {
                    int radius = width > height ? (width - borderWidth) / 2 : (height - borderWidth) / 2;
                    canvas.drawCircle(width / 2, height / 2, radius, paint);
                } else if (shapeType == 2) {
                    RectF rectf = new RectF(borderWidth / 2, borderWidth / 2, getWidth() - borderWidth / 2,
                            getHeight() - borderWidth / 2);
                    canvas.drawRoundRect(rectf, radius, radius, paint);
                }
            }
        }
    
        @Override
        protected void onSizeChanged(int w, int h, int oldw, int oldh) {
            super.onSizeChanged(w, h, oldw, oldh);
            width = w;
            height = h;
        }
    
        @Override
        public boolean onTouchEvent(MotionEvent event) {
            switch (event.getAction()) {
                case MotionEvent.ACTION_DOWN:
                    pressPaint.setAlpha(pressAlpha);
                    invalidate();
                    break;
                case MotionEvent.ACTION_UP:
                    pressPaint.setAlpha(0);
                    invalidate();
                    break;
                case MotionEvent.ACTION_MOVE:
                    break;
                default:
                    pressPaint.setAlpha(0);
                    invalidate();
                    break;
    
            }
            return super.onTouchEvent(event);
        }
    
        /**
         * 设置 border color
         */
        public void setBorderColor(int borderColor) {
            this.borderColor = borderColor;
            invalidate();
        }
    
        /**
         * 设置 border width
         *
         * @param borderWidth
         */
        public void setBorderWidth(int borderWidth) {
            this.borderWidth = borderWidth;
        }
    
        /**
         * 设置 press alpha
         */
        public void setPressAlpha(int pressAlpha) {
            this.pressAlpha = pressAlpha;
        }
    
        /**
         * 设置 pressColor
         */
        public void setPressColor(int pressColor) {
            this.pressColor = pressColor;
        }
    
        /**
         * 设置 radius
         */
        public void setRadius(int radius) {
            this.radius = radius;
        }
    
        /**
         * 设置shapeType
         */
        public void setShapeType(int shapeType) {
            this.shapeType = shapeType;
            invalidate();
        }
    

    CanvasSave类通过反射执行saveLayer

    class CanvasSave {
       static final int MATRIX_SAVE_FLAG;
       static final int CLIP_SAVE_FLAG;
       static final int HAS_ALPHA_LAYER_SAVE_FLAG;
       static final int FULL_COLOR_LAYER_SAVE_FLAG;
       static final int CLIP_TO_LAYER_SAVE_FLAG;
    
    
       private static final Method SAVE;
    
       static {
           try {
               MATRIX_SAVE_FLAG = (int) Canvas.class.getField("MATRIX_SAVE_FLAG").get(null);
               CLIP_SAVE_FLAG = (int) Canvas.class.getField("CLIP_SAVE_FLAG").get(null);
               HAS_ALPHA_LAYER_SAVE_FLAG = (int) Canvas.class.getField("HAS_ALPHA_LAYER_SAVE_FLAG").get(null);
               FULL_COLOR_LAYER_SAVE_FLAG = (int) Canvas.class.getField("FULL_COLOR_LAYER_SAVE_FLAG").get(null);
               CLIP_TO_LAYER_SAVE_FLAG = (int) Canvas.class.getField("CLIP_TO_LAYER_SAVE_FLAG").get(null);
    
               SAVE = Canvas.class.getMethod("saveLayer", float.class, float.class, float.class, float.class, Paint.class, int.class);
           } catch (Throwable e) {
               throw sneakyThrow(e);
           }
       }
    
       static void saveLayer(Canvas canvas, float left, float top, float right, float bottom, @Nullable Paint paint, int saveFlags) {
           try {
               SAVE.invoke(canvas, left, top, right, bottom, paint, saveFlags);
           } catch (Throwable e) {
               throw sneakyThrow(e);
           }
       }
    
       private static RuntimeException sneakyThrow(Throwable t) {
           if (t == null) throw new NullPointerException("t");
           return CanvasSave.sneakyThrow0(t);
       }
    
       @SuppressWarnings("unchecked")
       private static <T extends Throwable> T sneakyThrow0(Throwable t) throws T {
           throw (T) t;
       }
    }
    

    相关文章

      网友评论

        本文标题:自定义ImageView——支持ImageView的形状和倒角大

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