0

我在自定义视图中有一堆可绘制对象。我希望用户能够按下一个或多个可绘制对象并更改颜色。目前,每个可绘制对象都只是StateListDrawable具有两种状态:state_pressed和未按下。每次我按下可绘制对象时,setState都会返回 true,因此我假设它实际上已更改,但我没有看到可绘制图像更改。是invalidateDrawable不是什么都不做?我究竟做错了什么?如何在按下时重绘一个drawable而不需要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;
    }
}
4

2 回答 2

0

我最初是这样做的,但发现我的应用程序运行非常缓慢/效率低下

如果这样做,那么您在代码中的某个地方有很大的优势,或者(我想)在绘制之前不会缩放图像。所以试着在你的代码上找到一个对系统有巨大优势的逻辑。因为View.invalidate()方法太快了。

其他 0,02$ :

我想你开发了类似键盘的东西。对于这种情况,您只需要使画布的区域无效。

View.invalidate(new Rect(0, 0, 49, 49));
于 2016-02-15T22:10:17.760 回答
0

我也有这个问题,但最后我解决了。出现此问题的原因是Drawable您在上下文中使用的对象不是Bounds通过 call设置的setBounds(Rect),因此默认情况下它BoundsRect(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.ThereforeView.invalidate()不起作用。

所以你要做的就是Drawable.Bounds在代码的某个地方 设置,像这样:</p>

@Override
public void draw(@NonNull Canvas canvas) {
    Rect localRect = canvas.getClipBounds();
    this.setBounds(localRect);
    ...
}
于 2019-05-07T01:35:11.260 回答