Android invalidateDrawable() не работает
У меня есть куча рисования в пользовательском представлении. Я хочу, чтобы пользователь мог нажимать на один или несколько рисунков, и он меняет цвета. В настоящее время каждый чертеж является просто StateListDrawable
с двумя состояниями: state_pressed
и не давить. Каждый раз, когда я нажимаю на отрисовку, setState
возвращает true, поэтому я предполагаю, что оно действительно изменилось, но я не вижу изменения рисованного изображения. Является invalidateDrawable
ничего не делая? Что я делаю неправильно? Как я могу перерисовать тот нарисованный при нажатии без необходимости вызова customView.invalidate()
и перерисовывать все это каждый раз? Первоначально я делал это, но обнаружил, что мое приложение работает очень медленно / неэффективно. Спасибо!
Поток:
Custom View (contains set of our custom class - TouchKey)
- Custom class TouchKey containing drawable and info
- Upon press or release, custom class finds which drawable to change
Вот код для нажатия кнопки внутри TouchKey
класс (MyTouch - это пользовательский класс, отслеживающий все прикосновения на устройстве Android):
public void pressed(MyTouch touch) {
boolean successfulStateChange = this.drawable.setState(new int[]{android.
R.attr.state_pressed});
this.customView.invalidateDrawable(drawable);
}
public void released(MyTouch touch) {
boolean successfulStateChange = this.drawable.setState(new int[]{-android.
R.attr.state_pressed});
this.customView.invalidateDrawable(drawable);
}
Как мой StateListDrawable
рисуется в моем обычном представлении:
public class CustomView extends View {
private TreeMap<Integer, TouchKey> keymap;
/* Initialization Code Stuff Here - call drawKey */
// StateListDrawable Creation
private StateListDrawable drawKey(Canvas canvas, int bounds_l,
int bounds_t, int bounds_r, int bounds_b)
throws Resources.NotFoundException, XmlPullParserException, IOException {
StateListDrawable key = new StateListDrawable();
key.addState(new int[]{android.R.attr.state_pressed},
ContextCompat.getDrawable(mContext, R.drawable.key_pressed));
key.addState(new int[]{-android.R.attr.state_pressed},
ContextCompat.getDrawable(mContext, R.drawable.key_released));
key.setBounds(bound_l, bounds_t, bounds_r, bounds_b);
key.draw(canvas);
return key;
}
}
1 ответ
Я делал это изначально, но обнаружил, что мое приложение работает очень медленно / неэффективно
Если вы сделаете это, у вас есть большие преимущества в каком-то месте вашего кода, или (я полагаю) не масштабирует изображения перед рисованием. Поэтому постарайтесь найти логику в вашем коде, которая имеет огромное преимущество в системе. Так как View.invalidate()
такой быстрый метод.
Другое 0,02$:
Я полагаю, что вы разрабатываете что-то вроде клавиатуры. Для этого случая вам нужно сделать недействительной только область вашего холста.
View.invalidate(new Rect(0, 0, 49, 49));
У меня тоже была проблема, но в конце концов я ее решаю. Причиной этой проблемы является то, что Drawable
объект, который вы используете в контексте не устанавливает это Bounds
по телефону setBounds(Rect)
, так что это Bounds
является Rect(0,0,0,0)
по умолчанию. Это причина invalidateDrawable()
из View
который Drawable
прилагается не работает.
Увидеть View.invalidateDrawable()
:
@Override
public void invalidateDrawable(@NonNull Drawable drawable) {
if (verifyDrawable(drawable)) {
final Rect dirty = drawable.getDirtyBounds();
final int scrollX = mScrollX;
final int scrollY = mScrollY;
invalidate(dirty.left + scrollX, dirty.top + scrollY,
dirty.right + scrollX, dirty.bottom + scrollY);
rebuildOutline();
}
}
Посмотрите галочку Drawable.getDirtyBounds():
/**
* Return the drawable's dirty bounds Rect. Note: for efficiency, the
* returned object may be the same object stored in the drawable (though
* this is not guaranteed).
* <p>
* By default, this returns the full drawable bounds. Custom drawables may
* override this method to perform more precise invalidation.
*
* @return The dirty bounds of this drawable
*/
@NonNull
public Rect getDirtyBounds() {
return getBounds();
}
Так что Rect грязный Rect(0,0,0,0)
, если вы не настроены Drawable.Bounds
.Следовательно View.invalidate()
не работает
Итак, что вам нужно сделать, это настроить Drawable.Bounds
в каком-то месте в коде, как это:
@Override
public void draw(@NonNull Canvas canvas) {
Rect localRect = canvas.getClipBounds();
this.setBounds(localRect);
...
}