Android自定义View

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

2019-06-04  本文已影响7人  Peakmain

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;
   }
}
上一篇下一篇

猜你喜欢

热点阅读