通过触摸屏跳过绘画(不连续线) [英] Painting by touchscreen skips (discontiguous lines)

查看:276
本文介绍了通过触摸屏跳过绘画(不连续线)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的活动课文件:

package com.drawing.test;

import android.app.Activity;
import android.os.Bundle;


import android.app.Activity;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.os.Bundle;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnTouchListener;
import android.widget.LinearLayout;

public class TstActivity extends Activity implements OnTouchListener
{
    float x1 = 0, y1 = 0, x2 = 0, y2 = 0;
    public static boolean action=false;
    private Bitmap mBitmap;
    private Canvas mCanvas;
    private Paint mBitmapPaint;

    Drawer mDrawer;

    @Override
    public void onCreate(Bundle savedInstanceState) 
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        LinearLayout mLinearLayout = (LinearLayout) findViewById(R.id.drawView);
        mLinearLayout.setOnTouchListener((OnTouchListener) this);
        mLinearLayout.addView(new Drawer(this));
    }

    public boolean onTouch(View v, MotionEvent event) 
    {
        switch (event.getAction()) 
        {
            case MotionEvent.ACTION_DOWN:
                x1 = event.getX();
                y1 = event.getY();
                action=false;
                //v.invalidate();
            return true;
            case MotionEvent.ACTION_MOVE:
                x1=x2;
                y1=y2;
                x2 = event.getX();
                y2 = event.getY();
                v.invalidate();
                action=true;
            return true;
            case MotionEvent.ACTION_UP:
                x2 = event.getX();
                y2 = event.getY();
                v.invalidate();
                action=true;
            return true;

        }
        return false;
    }

    public class Drawer extends View
    {

        public Drawer(Context context)
        {
            super(context);
            mBitmap = Bitmap.createBitmap(400, 800, Bitmap.Config.ARGB_8888);
            mCanvas = new Canvas(mBitmap);
            mBitmapPaint = new Paint(Paint.DITHER_FLAG);
            mBitmapPaint.setColor(Color.MAGENTA);
            invalidate();
        }

        protected void onDraw(Canvas canvas)
        {
            if(x1==x2 && y1==y2)return;
            Paint p = new Paint();
            // Canvas mCanvas1=new Canvas(mBitmap);
            p.setColor(Color.parseColor("#7CFC00"));
            canvas.drawBitmap(mBitmap, 0, 0, p);
            //  canvas.drawLine(x1, y1, x2 , y2, p);
            p.setColor(Color.RED);
            // mCanvas1.drawLine(x1, y1, x2, y2,p);
            if(action==true)mCanvas.drawLine(x1, y1, x2, y2, mBitmapPaint);

        }
    }
}

我的布局XML:

My Layout XML:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:id="@+id/drawView">

</LinearLayout>

当我尝试这一点上模拟器,换行符在中间,但继续画画。我试图在设备上也和同样的问题发生,但数量较少。此外,显示器闪烁,或去完全空白。当它完全黑了,它回来,如果我摸一次。

When I try this out on emulator, the line breaks in middle but continues drawing. I tried on device too, and same problems happen but lesser in number. Also, the display sometimes flickers, or goes completely blank. When its completely black, it comes back if I touch once.

这有什么错,我做的,我会改变我的做法。

Is there anything wrong that I am doing, shall I change my approach.

任何建议都AP preciated。谢谢

Any suggestions are appreciated. Thanks

推荐答案

这是一个同步的问题。基本上,无效()不会阻塞调用:它只是告诉系统在将来的某个时候重新绘制。所以会发生什么:

It's a synchronization problem. Basically, invalidate() is not a blocking call: it just tells the system to redraw at some point in the future. So what happens:


  • 您设置(X1,Y1)和(x2,y2)的
  • 的值
  • invaldate()一个时间表,尽快重绘地

  • 但另一触摸事件覆盖(X1,Y1)和(x2,y2)的之前绘制直线:旧值永远失去

  • You set a value for (x1, y1) and (x2, y2)
  • invaldate() schedules a redraw as soon as possible
  • but another touch event overwrites (x1, y1) and (x2, y2) before the line is drawn: the old values are lost forever

您可以简单地通过增加两个命中计数器,一个用于无效()和一个的onDraw()。一段时间后,您会看到调用到数无效()比命中为的onDraw大于()。我的建议是从触摸事件保持点在队列。另外请注意,每次分配位图您需要调用回收当你已经做是为了避免内存泄漏。实际上,像素被存储在本机存储器而不是垃圾当视图被破坏收集。我通常所说的 回收我的活动停止时。这里是我的code:

You can prove it simply by adding two hits counter, one for invalidate() and one for onDraw(). After some time you see that the number of calls to invalidate() is greater than the hits for onDraw(). My suggestion is to keep the points from touch events in a Queue. Also note that every time you allocate a Bitmap you need to call recycle when you have done to avoid memory leaks. In fact, the pixels are stored in native memory and are not garbage collected when the view is destroyed. I usually call recycle when my activity stops. Here is my code:

public class MainActivity extends Activity {
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
    }

    public static class Drawer extends View  {

        private Bitmap cache;
        private Queue<PointF> points;
        private PointF from;

        public Drawer(Context ctx, AttributeSet attrs) {
            super(ctx, attrs);
            points = new ConcurrentLinkedQueue<PointF>();
        }

        @Override
        public boolean onTouchEvent(MotionEvent evt) {
            switch (evt.getAction()) {
            case MotionEvent.ACTION_DOWN: from = new PointF(evt.getX(), evt.getY()); break;
            case MotionEvent.ACTION_MOVE: points.add(new PointF(evt.getX(), evt.getY())); invalidate(); break;
            case MotionEvent.ACTION_UP: from = null; break;
            default: from = null;
            }
            return true;
        }

        @Override
        public void onSizeChanged(int w, int h, int oldw, int oldh) {
            if (w == 0 || h == 0)
                return;
            cache = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
        }

        @Override
        public void onDraw(Canvas systemCanvas) {
            int w = getWidth();
            int h = getHeight();
            if (w == 0 || h == 0)
                return;
            if (cache == null)
                cache = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
            // Draw on the cache
            Canvas canvas = new Canvas(cache);
            Paint paint = new Paint();
            paint.setStrokeWidth(4);
            paint.setColor(Color.MAGENTA);
            paint.setFlags(Paint.ANTI_ALIAS_FLAG);

            drawPoints(points, canvas, paint);

            // Draw the cache with the system canvas
            systemCanvas.drawBitmap(cache, 0, 0, paint);
        }

        private void drawPoints(Queue<PointF> points, Canvas canvas, Paint paint) {
            if (from == null)
                return;
            PointF to;
            while ((to = points.poll()) != null) {
                canvas.drawLine(from.x, from.y, to.x, to.y, paint);
                from = to;
            }
        }

    }
}

和是这种布局

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical"
    android:id="@+id/drawView">
    <view 
        class="com.zybnet.test.MainActivity$Drawer"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent" />

</LinearLayout>

您可以看到,海关视图可以在XML中使用,也:)

You can see that customs view can be used in XML, too :)

这篇关于通过触摸屏跳过绘画(不连续线)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆