Живопись по сенсорным экранам (с перерывами) - PullRequest
1 голос
/ 26 марта 2012

Файл класса моей активности:

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);

        }
    }
}

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>

Когда я пробую это на эмуляторе, линия разрывается посередине, но продолжает рисовать. Я тоже попробовал на устройстве, и такие же проблемы случаются, но меньше. Кроме того, дисплей иногда мигает или становится полностью пустым. Когда он полностью черный, он возвращается, если я коснусь один раз.

Что-то не так, что я делаю, я должен изменить свой подход.

Любые предложения приветствуются. Спасибо

Ответы [ 2 ]

2 голосов
/ 27 марта 2012

Это проблема синхронизации. По сути, invalidate() является , а не блокирующим вызовом: он просто говорит системе перерисовать в какой-то момент в будущем. Итак, что происходит:

  • Вы устанавливаете значение для (x1, y1) и (x2, y2)
  • invaldate() планирует перерисовку как можно скорее
  • , но другое событие касания перезаписывает (x1, y1) и (x2, y2) до того, как нарисована линия : старые значения теряются навсегда

Вы можете доказать это, просто добавив два счетчика хитов, один для invalidate() и один для onDraw(). Через некоторое время вы видите, что количество звонков на invalidate() превышает количество обращений на onDraw(). Я предлагаю сохранить очки от сенсорных событий в Queue. Также обратите внимание, что каждый раз, когда вы выделяете Bitmap, вам необходимо вызывать recycle, чтобы избежать утечек памяти. Фактически, пиксели хранятся в собственной памяти и не удаляются мусором при разрушении представления. Я обычно звоню recycle, когда моя деятельность прекращается. Вот мой код:

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:)

0 голосов
/ 27 марта 2012

Для motionEvent.ACTION_MOVE они могут и будут сгруппированы.Я считаю, что именно поэтому в линиях есть разрывы.

См. Это в документации:

Пакетирование

Для эффективности события движения с ACTION_MOVE могутПакет вместе несколько образцов движения в одном объекте.Самые последние координаты указателя доступны с использованием getX (int) и getY (int).Более ранние координаты в пакете доступны с помощью getHistoricalX (int, int) и getHistoricalY (int, int).Координаты являются «историческими» только в том случае, если они старше, чем текущие координаты в пакете;однако они по-прежнему отличаются от любых других координат, о которых сообщалось в предыдущих событиях движения.Для обработки всех координат в пакете во временном порядке сначала используются исторические координаты, а затем текущие координаты.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...