Android, canvas: Как очистить (удалить содержимое) холста (= растровые изображения), живущего в surfaceView?

Чтобы сделать простую игру, я использовал шаблон, который рисует холст с растровыми изображениями следующим образом:

private void doDraw(Canvas canvas) {
    for (int i=0;i<8;i++)
        for (int j=0;j<9;j++)
            for (int k=0;k<7;k++)   {
    canvas.drawBitmap(mBits[allBits[i][j][k]], i*50 -k*7, j*50 -k*7, null); } }

(Холст определяется в "run()" /SurfaceView живет в GameThread.)

Мой первый вопрос: как очистить (или перерисовать) весь холст для нового макета?
Во-вторых, как я могу обновить только часть экрана?

// This is the routine that calls "doDraw":
public void run() {
    while (mRun) {
        Canvas c = null;
        try {
            c = mSurfaceHolder.lockCanvas(null);
            synchronized (mSurfaceHolder) {
                if (mMode == STATE_RUNNING) 
                    updateGame();
                doDraw(c);          }
        } finally {
            if (c != null) {
                mSurfaceHolder.unlockCanvasAndPost(c);  }   }   }       }

Ответ 1

Как очистить (или перерисовать) холст WHOLE для нового макета (= попробовать в игре)?

Просто вызовите Canvas.drawColor(Color.BLACK) или любой цвет, который вы хотите удалить с помощью Canvas.

И: как я могу обновить только часть экрана?

Нет такого метода, который просто обновляет "часть экрана", так как ОС Android перерисовывает каждый пиксель при обновлении экрана. Но, когда вы не очищаете старые рисунки на вашем Canvas, старые рисунки все еще находятся на поверхности, и это, вероятно, один из способов "обновить только часть" экрана.

Итак, если вы хотите "обновить часть экрана", просто не вызывайте метод Canvas.drawColor().

Ответ 2

Нарисуйте прозрачный цвет с прозрачным режимом PorterDuff делает трюк за то, что я хотел.

Canvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR)

Ответ 3

Обнаружено это в группах google, и это сработало для меня.

Paint clearPaint = new Paint();
clearPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
canvas.drawRect(0, 0, width, height, clearPaint); 

Это удаляет прямоугольники чертежей и т.д., сохраняя заданное растровое изображение.

Ответ 4

Я попробовал ответить @mobistry:

canvas.drawColor(Color.TRANSPARENT, Mode.CLEAR);

Но это не сработало для меня.

Решение для меня было:

canvas.drawColor(Color.TRANSPARENT, Mode.MULTIPLY);

Возможно, у кого-то такая же проблема.

Ответ 5

используйте метод reset класса Path

Path.reset();

Ответ 6

mBitmap.eraseColor(Color.TRANSPARENT);

canvas.drawBitmap(mBitmap, 0, 0, mBitmapPaint);

Ответ 7

пожалуйста, вставьте ниже код в конструктор класса расширения видаviewview.............

кодирование конструктора

    SurfaceHolder holder = getHolder();
    holder.addCallback(this);

    SurfaceView sur = (SurfaceView)findViewById(R.id.surfaceview);
    sur.setZOrderOnTop(true);    // necessary
    holder = sur.getHolder();
    holder.setFormat(PixelFormat.TRANSPARENT);

xml-кодирование

    <com.welcome.panelview.PanelViewWelcomeScreen
        android:id="@+id/one"
        android:layout_width="600px"
        android:layout_height="312px"
        android:layout_gravity="center"
        android:layout_marginTop="10px"
        android:background="@drawable/welcome" />

попробуйте код выше...

Ответ 8

Вот код минимального примера, показывающий, что вам всегда нужно перерисовывать каждый пиксель Canvas в каждом кадре.

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

Я тестировал его на своем телефоне (Nexus S, Android 2.3.3) и на эмуляторе (Android 2.2).

public class TestCanvas extends Activity {
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(new TestView(this));
    }
}

class TestView extends SurfaceView implements SurfaceHolder.Callback {

    private TestThread mThread;
    private int mWidth;
    private int mHeight;
    private Bitmap mBitmap;
    private SurfaceHolder mSurfaceHolder;

    public TestView(Context context) {
        super(context);
        mThread = new TestThread();
        mBitmap = BitmapFactory.decodeResource(context.getResources(), R.drawable.icon);
        mSurfaceHolder = getHolder();
        mSurfaceHolder.addCallback(this);
    }

    @Override
    public void surfaceChanged(SurfaceHolder holder, int format, int width,
            int height) {
        mWidth = width;
        mHeight = height;
        mThread.start();
    }

    @Override
    public void surfaceCreated(SurfaceHolder holder) {/* Do nothing */}

    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {
        if (mThread != null && mThread.isAlive())
            mThread.interrupt();
    }

    class TestThread extends Thread {
        @Override
        public void run() {
            while (!isInterrupted()) {
                Canvas c = null;
                try {
                    c = mSurfaceHolder.lockCanvas(null);
                    synchronized (mSurfaceHolder) {
                        c.drawBitmap(mBitmap, (int) (Math.random() * mWidth), (int) (Math.random() * mHeight), null);
                    }
                } finally {
                    if (c != null)
                        mSurfaceHolder.unlockCanvasAndPost(c);
                }

                try {
                    sleep(1000);
                } catch (InterruptedException e) {
                    interrupt();
                }
            }
        }   
    }
}

Ответ 9

Для меня вызов Canvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR) или что-то подобное будет работать только после того, как я коснусь экрана. Я бы назвал вышеуказанную строку кода, но экран будет очищен только после того, как я коснулся экрана. Так что для меня работало, чтобы вызвать invalidate(), а затем init(), который вызывается во время создания для инициализации представления.

private void init() {
    setFocusable(true);
    setFocusableInTouchMode(true);
    setOnTouchListener(this);

    mPaint = new Paint();
    mPaint.setAntiAlias(true);
    mPaint.setDither(true);
    mPaint.setColor(Color.BLACK);
    mPaint.setStyle(Paint.Style.STROKE);
    mPaint.setStrokeJoin(Paint.Join.ROUND);
    mPaint.setStrokeCap(Paint.Cap.ROUND);
    mPaint.setStrokeWidth(6);

    mCanvas = new Canvas();
    mPaths = new LinkedList<>();

    addNewPath();
}

Ответ 10

canvas.drawColor(Color.TRANSPARENT, Mode.MULTIPLY);

Ответ 11

Не забудьте вызвать invalidate();

canvas.drawColor(backgroundColor);
invalidate();
path.reset();

Ответ 12

При следующем подходе вы можете очистить весь холст или только его часть.
Пожалуйста, не забудьте отключить аппаратное ускорение, так как PorterDuff.Mode.CLEAR не работает с аппаратным ускорением и, наконец, вызовите setWillNotDraw(false), потому что мы переопределяем метод onDraw.

//view constructor
setWillNotDraw(false);
setLayerType(LAYER_TYPE_HARDWARE, null);

//view onDraw
Paint TransparentPaint = new Paint();
TransparentPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
canvas.drawRect(0, 0, width, height, TransparentPaint); 

Ответ 13

Попробуйте удалить представление в onPause() действия и добавить onRestart()

LayoutYouAddedYourView.addView(YourCustomView); LayoutYouAddedYourView.removeView(YourCustomView);

В момент добавления вашего представления вызывается метод onDraw().

YourCustomView, это класс, который расширяет класс View.

Ответ 14

Ваше первое требование, как очистить или перерисовать весь холст - Answer - использовать метод canvas.drawColor(color.Black) для очистки экрана с цветом черного или любым другим, что вы указываете.

Второе требование, как обновить часть экрана - ответ - например, если вы хотите сохранить все остальные вещи без изменений на экране, но в небольшой области экрана, чтобы показать целое число (скажем, счетчик), которое увеличивается после каждого пять секунд. затем используйте метод canvas.drawrect, чтобы нарисовать эту небольшую область, указав левое верхнее правое нижнее и нарисовать. затем вычислите значение вашего счетчика (используя postdalayed в течение 5 секунд и т.д., например Handler.postDelayed(Runnable_Object, 5000);), преобразуйте его в текстовую строку, вычислите координату x и y в этом маленьком прямоугольнике и используйте текстовое представление, чтобы отобразить изменение значение счетчика.

Ответ 15

Мне пришлось использовать отдельный проход для прорисовки холста (заблокировать, нарисовать и разблокировать):

Canvas canvas = null;
try {
    canvas = holder.lockCanvas();
    if (canvas == null) {
        // exit drawing thread
        break;
    }
    canvas.drawColor(colorToClearFromCanvas, PorterDuff.Mode.CLEAR);
} finally {
    if (canvas != null) {
        holder.unlockCanvasAndPost(canvas);
    }
}

Ответ 16

Просто позвоните

canvas.drawColor(Color.TRANSPARENT)