You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android刮刮卡:实现单次刮擦及解决状态恢复问题

解决方案:持久化刮擦状态

要实现刮擦状态在页面跳转或应用重启后不恢复,核心是把刮擦的状态持久化存储,下面分两种场景给出具体实现方案:

1. 基础方案:记录刮擦完成状态

如果你的需求是用户刮完后就永久保持已刮开状态,用SharedPreferences来记录状态是最简单的方式:

修改ScratchImageView代码

  • 在初始化方法里添加状态读取逻辑,启动时检查是否已经完成刮擦,如果是则直接显示下方图片:
private void init() {
    // 原有的初始化代码(保留不动)
    mTouchPath = new Path();
    mErasePaint = new Paint();
    mErasePaint.setAntiAlias(true);
    mErasePaint.setDither(true);
    mErasePaint.setColor(0xFFFF0000);
    mErasePaint.setStyle(Paint.Style.STROKE);
    mErasePaint.setStrokeJoin(Paint.Join.BEVEL);
    mErasePaint.setStrokeCap(Paint.Cap.ROUND);
    setStrokeWidth(6);
    mGradientBgPaint = new Paint();
    mErasePath = new Path();
    mBitmapPaint = new Paint(Paint.DITHER_FLAG);
    Bitmap scratchBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.ic_scratch_pattern);
    mDrawable = new BitmapDrawable(getResources(), scratchBitmap);
    mDrawable.setTileModeXY(Shader.TileMode.REPEAT, Shader.TileMode.REPEAT);
    setEraserMode();

    // 新增:读取持久化的刮擦状态
    SharedPreferences sp = getContext().getSharedPreferences("ScratchCardStorage", Context.MODE_PRIVATE);
    boolean hasScratched = sp.getBoolean("scratched_" + getId(), false);
    if (hasScratched) {
        clear(); // 直接清除刮擦层,显示下方图片
    }
}
  • 在刮擦完成的回调里保存状态,确保完成后永久生效:
private void checkRevealed() {
    // 原有的检查逻辑(保留不动)
    if (mRevealPercent >= 1.0f && mRevealListener != null) {
        mRevealListener.onRevealed(this);
        // 新增:保存刮擦完成状态
        SharedPreferences sp = getContext().getSharedPreferences("ScratchCardStorage", Context.MODE_PRIVATE);
        sp.edit().putBoolean("scratched_" + getId(), true).apply();
    }
}

2. 进阶方案:精确恢复刮擦进度

如果需要恢复用户中途退出时的刮擦进度,可以把刮擦层的Bitmap保存到应用内部存储,启动时读取恢复:

添加Bitmap存储与读取方法

在ScratchImageView中新增两个工具方法:

// 保存刮擦层Bitmap到内部存储
private void saveScratchBitmap() {
    try {
        FileOutputStream fos = getContext().openFileOutput("scratch_bitmap_" + getId() + ".png", Context.MODE_PRIVATE);
        mScratchBitmap.compress(Bitmap.CompressFormat.PNG, 100, fos);
        fos.close();
    } catch (IOException e) {
        e.printStackTrace();
    }
}

// 从内部存储读取保存的刮擦层Bitmap
private Bitmap loadScratchBitmap() {
    try {
        FileInputStream fis = getContext().openFileInput("scratch_bitmap_" + getId() + ".png");
        return BitmapFactory.decodeStream(fis);
    } catch (IOException e) {
        e.printStackTrace();
        return null;
    }
}

修改初始化与绘制逻辑

  • 在组件尺寸变化时,优先读取已保存的Bitmap,没有的话再初始化新的:
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
    super.onSizeChanged(w, h, oldw, oldh);
    // 先尝试读取已保存的Bitmap
    Bitmap savedBitmap = loadScratchBitmap();
    if (savedBitmap != null && savedBitmap.getWidth() == w && savedBitmap.getHeight() == h) {
        mScratchBitmap = savedBitmap;
        mCanvas = new Canvas(mScratchBitmap); // 重新绑定画布
    } else {
        // 原有的初始化逻辑(保留不动)
        mScratchBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
        mCanvas = new Canvas(mScratchBitmap);
        Rect rect = new Rect(0, 0, mScratchBitmap.getWidth(), mScratchBitmap.getHeight());
        mDrawable.setBounds(rect);
        int startGradientColor = ContextCompat.getColor(getContext(), R.color.scratch_start_gradient);
        int endGradientColor = ContextCompat.getColor(getContext(), R.color.scratch_end_gradient);
        mGradientBgPaint.setShader(new LinearGradient(0, 0, 0, getHeight(), startGradientColor, endGradientColor, Shader.TileMode.MIRROR));
        mCanvas.drawRect(rect, mGradientBgPaint);
        mDrawable.draw(mCanvas);
    }
}
  • 在用户刮擦过程中保存状态,确保实时进度不丢失:
private void touch_move(float x, float y) {
    // 原有的触摸移动逻辑(保留不动)
    float dx = Math.abs(x - mX);
    float dy = Math.abs(y - mY);
    if (dx >= TOUCH_TOLERANCE || dy >= TOUCH_TOLERANCE) {
        mErasePath.quadTo(mX, mY, (x + mX)/2, (y + mY)/2);
        mX = x;
        mY = y;
        // 新增:每次刮擦移动后保存进度
        saveScratchBitmap();
    }
}

3. 注意事项

  • 用getId()作为状态标识的后缀,支持页面中多个ScratchImageView组件各自独立保存状态。
  • 应用内部存储的文件只有本应用可以访问,不需要额外申请权限。
  • 如果需要重置刮擦状态,可以通过清除对应SharedPreferences键值或删除内部文件实现。

内容的提问来源于stack exchange,提问作者Swapna

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.28 04:24:15