【自定义控件】Android仿刮刮乐|刮刮卡|橡皮擦效果

背景:需要实线一个类似刮刮乐的擦一擦效果,要求是在图片上覆盖半透明蒙层,蒙层支持手势擦除(类似橡皮擦)。

思路:使用自定义View在onDraw时进行绘制,绘制模式选择混合模式(叠加变透明)。

示例:

 

代码:

package com.xiazy.test;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Bitmap.Config;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PorterDuff.Mode;
import android.graphics.PorterDuffXfermode;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;

/**
 * @version V1.0
 * @Author Xiazy
 * @Date 2022/9/10 23:59:59
 * @Description: 自定义擦一擦类型动画效果-类似刮刮乐
 */
public class WipeView extends View {

  // 擦一擦画笔
  private Paint paint;
  // 源图像-背景色
  private Bitmap decodeResourceSRC;
  // 目标图像-手指擦除的位置
  private Bitmap createBitmapDST;
  // 手指路径,使用贝塞尔路线
  private Path path;
  // 按下的坐标X
  private float perX;
  // 按下的坐标Y
  private float perY;

  public WipeView(Context context, AttributeSet attrs) {
    super(context, attrs);
  }

  /**
   * 设置可擦除范围的擦一擦参数
   *
   * @param width    宽度
   * @param height   高度
   * @param callBack 擦一擦事件回调
   */
  public void setWipeData(int width, int height) {
    setWipeData(width, height, 0xC8000000, 45);
  }

  /**
   * 设置可擦除范围的擦一擦参数
   *
   * @param width       宽度
   * @param height      高度
   * @param bgColor     默认背景颜色
   * @param strokeWidth 手指滑动的擦除线的宽度
   */
  private void setWipeData(int width, int height, int bgColor, int strokeWidth) {
    // java.lang.IllegalArgumentException: width and height must be > 0
    if (width <= 0 || height <= 0) {
      return;
    }
    // 设置禁用硬件设置
    setLayerType(View.LAYER_TYPE_SOFTWARE, null);

    // 设置手指画笔
    paint = new Paint();
    paint.setAntiAlias(true);
    paint.setStyle(Paint.Style.STROKE);
    paint.setStrokeWidth(strokeWidth);

    // 生成图像手指源目标
    // 源--灰色背景区域
    decodeResourceSRC = Bitmap.createBitmap(width, height, Config.ARGB_8888);
    decodeResourceSRC.eraseColor(bgColor);

    // 目标--每次绘制的区域
    createBitmapDST = Bitmap.createBitmap(width, height, Config.ARGB_8888);

    // 手指滑动的路径
    path = new Path();
  }

  /**
   * 绘制擦一擦的擦除效果
   */
  @Override
  protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);
    if (paint == null || path == null || createBitmapDST == null) {
      return;
    }
    // 分层绘制
    int saveLayer = canvas.saveLayer(0, 0, getWidth(), getHeight(), null, Canvas.ALL_SAVE_FLAG);

    // 把手指轨迹画到目标图层上
    Canvas canvas2 = new Canvas(createBitmapDST);
    canvas2.drawPath(path, paint);

    // 把目标图像画到画布上
    canvas.drawBitmap(createBitmapDST, 0, 0, paint);

    // 设置混合模式(当目标图层不透明时,计算结果将是透明的),绘制源图像区域
    paint.setXfermode(new PorterDuffXfermode(Mode.SRC_OUT));
    canvas.drawBitmap(decodeResourceSRC, 0, 0, paint);
    // 清空混合模式
    paint.setXfermode(null);
    canvas.restoreToCount(saveLayer);
  }

  // 使用贝塞尔曲线,使折线过度圆滑
  @Override
  public boolean onTouchEvent(MotionEvent event) {
    switch (event.getAction()) {
      // 记录手指触摸的初始化位置
      case MotionEvent.ACTION_DOWN:
        if (path != null) {
          path.moveTo(event.getX(), event.getY());
          perX = event.getX();
          perY = event.getY();
        }
        break;
      // 记录手指移动的位置
      case MotionEvent.ACTION_MOVE:
        if (path != null) {
          float endX = (perX + event.getX()) / 2;
          float endY = (perY + event.getY()) / 2;
          path.quadTo(perX, perY, endX, endY);
          perX = event.getX();
          perY = event.getY();
          // 刷新视图
          postInvalidate();
        }
        break;
      //手指抬起
      case MotionEvent.ACTION_UP:
        break;
      default:
        break;
    }

    return true;
  }
}

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值