如何在android中实现触摸平滑图像橡皮擦?

2024-06-20

我已经从 API 演示中看到了finturePaint.java。我想实现触摸平滑橡皮擦,通过在android中触摸移动来擦除部分图像。

FingerPaint 告诉我要实现这个

mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));

但这并不能消除图像。它正在努力擦除通过触摸绘制的东西。

public class SandboxView extends View implements OnTouchListener {
    public  final Bitmap bitmap;
    private final int width;
    private final int height;
    private Matrix transform = new Matrix();

    private Vector2D position = new Vector2D();
    private float scale = 1;
    private float angle = 0;
    public boolean isInitialized = false;
    private TouchManager touchManager = new TouchManager(2);
    final GestureDetector mGesDetect;


    // Debug helpers to draw lines between the two touch points
    private Vector2D vca = null;
    private Vector2D vcb = null;
    private Vector2D vpa = null;
    private Vector2D vpb = null;

    private float mX, mY;
    private static final float TOUCH_TOLERANCE = 4;
    private Path    mPath;
    private Canvas  mCanvas;
    private Paint       mPaint;
    private Paint   mBitmapPaint;
    public SandboxView(Context context, Bitmap bitmap) {
        super(context);

        this.bitmap = bitmap;
        this.width = bitmap.getWidth();
        this.height = bitmap.getHeight();
        this.mGesDetect = new GestureDetector(context, new DoubleTapGestureDetector());

        setOnTouchListener(this);
    }


    private  float getDegreesFromRadians(float angle) {
        return (float)(angle * 360.0 / Math.PI);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);

        if (!isInitialized) {
            Bitmap mBitmap = bitmap.createBitmap(320, 480, Bitmap.Config.ARGB_8888);
            mCanvas = new Canvas(mBitmap);
            mPaint = new Paint();
            mPath = new Path();
            mPaint.setAntiAlias(true);
            mPaint.setDither(true);
            mPaint.setColor(0xFFFF0000);
            mPaint.setStyle(Paint.Style.STROKE);
            mPaint.setStrokeJoin(Paint.Join.ROUND);
            mPaint.setStrokeCap(Paint.Cap.ROUND);
            mPaint.setStrokeWidth(12);
            mPaint.setAlpha(0);
            mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
            mPaint.setAntiAlias(true);

            mBitmapPaint = new Paint(Paint.DITHER_FLAG);


            int w = getWidth();
            int h = getHeight();
            position.set(w / 2, h / 2);
            isInitialized = true;
        }
        if(isEraser==1){
            canvas.drawColor(80000000);


            canvas.drawBitmap(bitmap, transform, mBitmapPaint);

            canvas.drawPath(mPath, mPaint);
        }
        else{


        Paint paint = new Paint();

        transform.reset();
        transform.postTranslate(-width / 2.0f, -height / 2.0f);
        transform.postRotate(getDegreesFromRadians(angle));
        transform.postScale(scale, scale);
        transform.postTranslate(position.getX(), position.getY());

        canvas.drawBitmap(bitmap, transform, paint);

        try {
            /*paint.setColor(0xFF007F00);
            canvas.drawCircle(vca.getX(), vca.getY(), 64, paint);
            paint.setColor(0xFF7F0000);
            canvas.drawCircle(vcb.getX(), vcb.getY(), 64, paint);

            paint.setColor(0xFFFF0000);
            canvas.drawLine(vpa.getX(), vpa.getY(), vpb.getX(), vpb.getY(), paint);
            paint.setColor(0xFF00FF00);
            canvas.drawLine(vca.getX(), vca.getY(), vcb.getX(), vcb.getY(), paint);*/




        }
        catch(NullPointerException e) {
            // Just being lazy here...
        }
        }
    }

    private void touch_start(float x, float y) {
        mPath.reset();
        mPath.moveTo(x, y);
        mX = x;
        mY = y;
    }
    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) {
            mPath.quadTo(mX, mY, (x + mX)/2, (y + mY)/2);
            mX = x;
            mY = y;
        }
    }
    private void touch_up() {
        mPath.lineTo(mX, mY);
        mCanvas.drawPath(mPath, mPaint);
        mPath.reset();
    }




    @Override
    public boolean onTouch(View v, MotionEvent event) {

        if(isEraser ==1){
            float x = event.getX();
            float y = event.getY();

            mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));


            switch (event.getAction()) {
                case MotionEvent.ACTION_DOWN:
                    touch_start(x, y);
                    invalidate();
                    break;
                case MotionEvent.ACTION_MOVE:
                    touch_move(x, y);
                    invalidate();
                    break;
                case MotionEvent.ACTION_UP:
                    touch_up();
                    invalidate();
                    break;
            }
            return true;
        }
        else{
        vca = null;
        vcb = null;
        vpa = null;
        vpb = null;
        mGesDetect.onTouchEvent(event);

        try {
            touchManager.update(event);

            if (touchManager.getPressCount() == 1) {
                vca = touchManager.getPoint(0);
                vpa = touchManager.getPreviousPoint(0);
                position.add(touchManager.moveDelta(0));
            }
            else {
                if (touchManager.getPressCount() == 2) {
                    vca = touchManager.getPoint(0);
                    vpa = touchManager.getPreviousPoint(0);
                    vcb = touchManager.getPoint(1);
                    vpb = touchManager.getPreviousPoint(1);

                    Vector2D current = touchManager.getVector(0, 1);
                    Vector2D previous = touchManager.getPreviousVector(0, 1);
                    float currentDistance = current.getLength();
                    float previousDistance = previous.getLength();

                    if (previousDistance != 0) {
                        scale *= currentDistance / previousDistance;
                    }

                    angle -= Vector2D.getSignedAngleBetween(current, previous);
                }
            }

            invalidate();
        }
        catch(Throwable t) {
            // So lazy...
        }
        return true;
        }
    }
    class DoubleTapGestureDetector extends GestureDetector.SimpleOnGestureListener {


        @Override
        public boolean onDoubleTap(MotionEvent e) {
            colorseekbar.setVisibility(View.INVISIBLE);
            opacityseekbar.setVisibility(View.INVISIBLE);
            return true;
        }
    }

}

所以请帮我通过触摸移动来擦除图像的部分。

提前致谢。


首先在构造函数中使用所有属性声明您的绘制。

将此代码写入您的onDraw() method

@Override
protected void onDraw(Canvas canvas) 
   {
    System.out.println("come in on draw......");
    canvas.drawColor(Color.TRANSPARENT);
    canvas.drawBitmap(mBitmap, 0, 0, mPaint);
            if(eraser==true)
               mPaint.setColor(Color.TRANSPARENT):
            else
               mPaint.setColor(Color.RED):
    canvas.drawPath(mPath, mPaint);

    super.dispatchDraw(canvas);
}

第二种解决方案:

在你的调用下面的方法触摸移动() method

mBitmap.setPixel(x, y, Color.TRANSPARENT);此方法将更改您必须传递的位图X、Y 和颜色

public void changeBitmap(int x, int y, Bitmap mBitmap)
{
 Bitmap tempBitmap = Bitmap.createBitmap(mBitmap); //Edited code
 tempBitmap.setPixel(x, y, Color.TRANSPARENT);
}



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) {
            mPath.quadTo(mX, mY, (x + mX)/2, (y + mY)/2);
            mX = x;
            mY = y;
            changeBitmap(x, y, your_bitmap)
        }
    }
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何在android中实现触摸平滑图像橡皮擦? 的相关文章

  • 即使我单击“运行”,Eclipse 也会运行调试模式

    Eclipse 总是在调试模式下启动我的应用程序 即使我单击常规的 运行 按钮 有任何想法吗 我发现我必须重新启动 Xoom 才能使其再次正常工作
  • Android Widget ID 是否持久

    在从桌面删除该 Widget 实例之前 您从操作系统收到的用户桌面上特定 Widget 实例的 Widget ID 是否一致 我找不到任何明确说明这一点的文档 但我假设这是因为文档说您可以使用小部件 id 来存储任何实例配置信息 我想将一些
  • 在 Android 市场中以编程方式检查我的应用程序版本

    目前 我正在启动时检查应用程序版本代码 并将其与我的服务器上的最新版本代码进行匹配 并根据此匹配 我发送用户从 Android 市场获取最新更新 它运行良好 但我的问题是我必须手动更改服务器上的最新版本代码 并且我不知道新版本何时发布APK
  • 如何从Slog中查看日志

    如何查看 Slog API 生成的日志 是否有任何选项可以查看系统缓冲区中的日志 我的意思是查看我们使用的无线电缓冲区的日志 adb logcat b 无线电 而这个日志是由Android的Log类生成的 Slog API 的输出在哪里 怎
  • 与通用地图相比,MapView 的分辨率较差

    我刚刚收到 HTC Desire 进行测试 我注意到 残留在小于整个屏幕的框架中的地图视图不如通用地图应用程序那么清晰 有什么办法解决这个问题吗 您应该使用 API 级别 4 或更高级别编译应用程序 然后在 AndroidManifest
  • Android 在 Windowmanager 中调整视图大小

    这是我的代码 menubuttonClosed li inflate R layout menu button null menubutton ImageButton menubuttonClosed findViewById R id m
  • 使用 RoboSpice 有没有办法从异常中获取 HTTP 错误代码?

    我正在编写一个使用 RoboSpice 的应用程序 在请求侦听器 onRequestFailure SpiceException arg0 中 有没有办法确定该错误是由于发生 401 HTTP 错误而导致的 我有一个后端服务 当令牌过期时
  • 使用 jQuery 的 .trigger('dragstart') 实现 HTML5 的拖放功能时如何 .setData/.getData

    当使用 jQuery 的 trigger dragstart 在具有 ondragstart drag event 属性的元素上触发函数时 如何使用 setData getData 实现 HTML5 在触摸设备上的拖放 流程示例 用户通过
  • 构建应用程序时出现 BufferOverflowException

    每次我想运行我的 Android 应用程序时 我都会收到错误 2013 11 02 13 05 36 Dex Loader Unable to execute dex java nio BufferOverflowException Che
  • Android - 使用 SAX 解析器解析大文件

    我正在尝试使用 SAX 解析器解析来自 webservice 的 xml 数据 当我尝试使用 URL 解析数据 大小 7 4MB 时 它工作正常 但是当我从 URL 复制 xml 数据并放置 xml 文件时 size 7 4MB 在raw文
  • 旋转 Google 地图中的两层标记图标

    在我的应用程序中 我向地图添加了一定数量的标记 如下所示 private fun addMarker googleMap GoogleMap location Location val options MarkerOptions optio
  • 添加 play-services-maps 依赖项自动添加 glEsVersion 2.0 要求

    我想融入Google Play Services Maps module 由于地图清单声明
  • 使用 Box2d(适用于 Android)进行碰撞检测?

    有人可以解释一下使用 box2d for android 进行碰撞检测的工作原理吗 我无法理解 BBContactListener 以什么方式工作 BBContactListener listener new BBContactListen
  • Android 5 Lollipop 阴影方向或 y 偏移

    是否有可能改变 Y 偏移的阴影方向 现在我有以下布局
  • Android 两个 Activity 之间的共享元素转换不起作用

    在我的应用程序中 我尝试使用新引入的活动之间共享的元素 如果共享元素具有固定位置 例如 android layout gravity top 但是当视图被锚定时问题就出现了 我的第一个活动如下所示
  • 如何获取Android中的所有主屏幕?

    我是安卓开发新手 我知道每个主屏幕都是启动器中的一个工作区 我想获取屏幕上所有应用程序图标的所有位置信息 那么有没有办法获取这些屏幕对象及其图标信息的列表 ADD 我更期待的是应用程序图标和屏幕之间的关系 例如 我想要某个应用程序图标的位置
  • onStart() 到底做了什么? - 安卓[重复]

    这个问题在这里已经有答案了 一段时间以来 我一直想知道 onStart 函数在 android 生命周期中的确切作用 网上的大多数资源只是说 它在您的活动在屏幕上可见之前被调用 但到目前为止我所做的应用程序我从未使用过onStart 我在
  • FCM 主题是否适合更多用户?

    我对使用主题消息有点困惑 我的场景是根据通知触发一些作业 请帮助我更多地了解这一点 如果我们正在处理大量用户 则可以使用 FCM 主题向用户发送通知 我们可以只使用数据消息和主题消息吗 使用主题发送的消息是否保证送达 我在 FCM 文档中看
  • 如何从另一个活动更新 Recyclerview 数据

    我有两个活动 MainActivity 和 Addlogactivity 我正在更新 Addlogactivity 中的数据 该数据应显示在 mainactivity recyclerview 中 数据未在数据库中更新 MianActivi
  • Android Webview隐私浏览

    我在我的 Android 应用程序中使用 webview 从多个站点获取一些网页 我对 webview 行为有一些疑问 webview 是否存储历史记录 cookie 表单自动填充信息 如果是的话 我们可以阻止它这样做吗 如果 Webvie

随机推荐

  • 在 C++11 中抛出异常时是否使用移动语义?

    http www drdobbs com cpp practical c error handling in hybrid env 197003350 pgno 4 http www drdobbs com cpp practical c
  • 使用子查询 select 创建新表

    我试图从子查询选择创建一个新表 但出现以下错误 附近的语法不正确 SELECT INTO foo FROM SELECT DATEPART MONTH a InvoiceDate as CalMonth DATEPART YEAR a In
  • 将样式添加到 mat-autocomplete 的 mat-option

    我有这个 HTML代码在这里 https stackblitz com edit angular mat autocomplete with selected value vx1uqg file src 2Fapp 2Fautocomple
  • 如何将 devise/omniauth 重定向到我登录的页面?

    我通过omniauth 进行了身份验证 并且该链接通过layout application html haml 在每个页面上都可用 然而 当他们完成omniauth身份验证后 他们都会进入root权限 我如何设置它 以便他们重定向到他们单击
  • 在 Android 上通话结束时启动活动

    我想在通话结束时启动一项活动 找不到任何对此的参考 我该怎么做 我还没有尝试过这个 但我假设你可以运行一些服务 始终在后台运行 它利用电话状态监听器 http developer android com reference android
  • Gatsby,“gatsby--image”在项目“构建”时不显示图像,但在开发过程中正确显示

    我用 gatsby 构建了我的第一个静态网站 但在使用 gatsby image 时遇到困难 我正在使用 gatsby image 中的 Img 组件 它在开发中正确显示图像 但在构建网站时什么也不显示 我使用图像的标题 import Re
  • 如何实现 Vec 的修剪?

    Rust 提供了字符串的修剪方法 str trim http doc rust lang org stable std primitive str html method trim删除前导和尾随空格 我想要一个对字节串执行相同操作的方法 应
  • 起订量:无法投射到接口

    今天早些时候我问过这个question https stackoverflow com questions 2774785 moq unable to cast 因此 由于起订量从接口创建它自己的类 我无法将其转换为不同的类 所以这让我想知
  • KafkaConsumer Java API subscribe() 与 allocate()

    我是 Kafka Java API 的新手 我正在研究使用来自特定 Kafka 主题的记录 我明白我可以使用方法subscribe 开始从主题轮询记录 Kafka还提供了方法assign 如果我想开始从主题的选定分区轮询记录 我想了解这是否
  • CSS 的波浪形状

    我正在尝试使用 CSS 重新创建此图像 我不需要重复它 这就是我开始的 但它只有一条直线 wave position absolute height 70px width 600px background e0efe3 div div 我认
  • 有没有keras方法来分割数据?

    我认为标题是不言自明的 但要详细询问 有 sklearn 的方法train test split 其工作原理如下 X train X test Y train Y test train test split X Y test size 0
  • python 中的高效外积

    当我们必须处理 10k 维的向量时 Python 中的外积看起来相当慢 有人可以告诉我如何在 python 中加速这个操作吗 代码如下 In 8 a shape Out 8 128 In 9 b shape Out 9 32000 In 1
  • Vim 自动缩进换行

    我如何让vim将光标放在大括号内以新行开始 即用 表示光标位置 class 现在我的设置只能做到这一点 class 我在 vimrc 文件中得到了这个 设置自动缩进 shiftwidth 2 tabstop 2 noexpandtab 基本
  • 创建一个从用户输入开始的 java gui 倒计时器

    这是github link https github com syedsadman16 CountdownTimer 所以我试图创建一个应用程序并将其分为 3 个部分 其中之一是创建一个计时器 该计时器有两个字段 一个用于输入分钟 一个用于
  • 太多的导入正在垃圾邮件我的 Java 代码

    在我的项目中我有一个shapes包含我为图形程序设计的形状的包 例如 长方形 and Circle 我还有一两个同名的软件包java awt类 现在 由于我不想重命名代码库中的每个类 为了显示我的源文件 当我声明一个新的矩形时 我需要执行以
  • 在玩笑中运行普通转换后如何转换模块

    用笑话测试 React 组件 其中一些组件使用 OpenLayers ol 软件包 v5 2 0 在 ol 包 v4 中 我应用了 transformIgnorePatterns 来转换 ol 包 jest transformIgnoreP
  • Swift SpriteKit edgeLoopF​​romRect 问题

    下面的代码可以识别底部和顶部边缘场景和球按预期弹开 但是 那左边缘和右边缘现场的情况一直被破坏 如果施加足够的力 球会离开屏幕 然后最终返回 就好像场景的边缘超出了 iPhone 模拟器窗口的边缘 import SpriteKit clas
  • 如何使用 javascript 或 jquery 生成 CSS 路径?

    关于如何生成元素的 CSS 路径有什么建议吗 CSS 路径是识别特定元素所需的 css 选择器的路径 例如 如果我的 html 是 div div class bar ul li 1 li li 2 li li span class sel
  • 如何在java中获得整数的0填充二进制表示?

    例如 对于1 2 128 256输出可以是 16 位 0000000000000001 0000000000000010 0000000010000000 0000000100000000 I tried String format 16s
  • 如何在android中实现触摸平滑图像橡皮擦?

    我已经从 API 演示中看到了finturePaint java 我想实现触摸平滑橡皮擦 通过在android中触摸移动来擦除部分图像 FingerPaint 告诉我要实现这个 mPaint setXfermode new PorterDu