Android: как заставить пользовательский вид частично перерисовываться?

У меня есть пользовательский вид, который заполняет весь экран. (Клавиатура фортепиано) Когда пользователь касается клавиши, вызывается invalidate(), и вся клавиатура перерисовывается, чтобы показать новое состояние с нажатой клавишей.

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

Вот я и подумал, давайте посмотрим на частичную перерисовку. Теперь я вызываю invalidate(Rect dirty) с правильным грязным регионом. Я установил свой метод onDraw(Canvas canvas), чтобы отрисовывать ключи только в грязной области, если я действительно хочу частичную перерисовку. Это приводит к тому, что эти клавиши рисуются, но остальная часть клавиатуры полностью черная / вообще не рисуется.

Я ошибаюсь, ожидая, что вызов invalidate(Rect dirty) будет «кэшировать» текущий canvas и «разрешит» рисовать только в грязной области?

Могу ли я каким-то образом добиться того, чего хочу? (Способ «кэшировать» холст и перерисовывать только грязную область?»


person Peterdk    schedule 01.06.2010    source источник


Ответы (2)


Текущий хороший обходной путь - вручную кэшировать весь холст в растровое изображение:

 private void onDraw(Canvas canvas)
 {
     if (!initialDrawingIsPerformed)
     {
          this.cachedBitmap = Bitmap.createBitmap(getWidth(), getHeight(),
            Config.ARGB_8888); //Change to lower bitmap config if possible.
          Canvas cacheCanvas = new Canvas(this.cachedBitmap);
          doInitialDrawing(cacheCanvas);
          canvas.drawBitmap(this.cachedBitmap, 0, 0, new Paint());
          initialDrawingIsPerformed = true;
     }
     else
     {
          canvas.drawBitmap(this.cachedBitmap, 0, 0, new Paint());
          doPartialRedraws(canvas);
     }
 }

Конечно, вам нужно хранить информацию о том, что перерисовывать самостоятельно, и желательно не использовать каждый раз новый Paint, но это детали.

Также обратите внимание: растровые изображения довольно сильно потребляют память вашего приложения. У меня были сбои, когда я кешировал представление, которое использовалось со скроллером и которое было примерно в 5 раз больше высоты устройства, поскольку оно использовало> 10 МБ памяти!

person Peterdk    schedule 01.06.2010
comment
Хм, мне не нравится это решение, потому что причина, по которой его ключи частично нарисованы, заключается в том, что он все равно должен сначала полностью нарисовать свой холст. Таким образом, вопрос в том, почему его холст изначально не рисовался правильно. - person ; 08.11.2012
comment
Я должен отметить, что теперь я понимаю, что когда вы вызываете invalidate с грязным rect, вы можете просто использовать свой обычный код рисования, и он должен фактически выполнять только те операции рисования, которые находятся в грязном rect. Canvas отбрасывает операции, находящиеся за пределами rect. Тем не менее, это означает, что большая часть вашего собственного кода все еще отображается, и в моих тестах с аппаратным ускорением это было медленнее, чем просто полная визуализация представления. - person Peterdk; 07.01.2014
comment
Обратите внимание, что для рисования растровых изображений на холсте параметр рисования может быть нулевым, например. canvas.drawBitmap(bitmap, 0, 0, null). - person greg7gkb; 19.03.2016

Чтобы дополнить ответ Peterdk, вы можете сохранить свои операции в изображении вместо растрового изображения.

  • Bitmap сохранит все пиксели, как он сказал, это может занять много памяти.
  • Изображение сохранит вызовы, такие как drawRect, drawLine и т. д.

Это зависит от того, что действительно тяжело в вашем приложении: много операций рисования, несколько операций рисования, но контролируемых тяжелыми вычислениями, много пустого/неиспользуемого пространства (предпочитайте изображение) и т. д.

person MappaM    schedule 06.05.2011
comment
Извините меня. Будет ли Picture записывать drawBitmap(bitmap) звонки? Наверное нет, да? - person Yeung; 01.02.2013
comment
Обратите внимание, что воспроизведение изображений поддерживается только на программных холстах, поэтому вы не можете использовать аппаратные слои для представлений, в которых это используется. - person greg7gkb; 19.03.2016