【问题标题】:Android invalidateDrawable() not workingAndroid invalidateDrawable()不起作用
【发布时间】:2016-05-26 22:24:11
【问题描述】:

我在自定义视图中有一堆可绘制对象。我希望用户能够按下一个或多个可绘制对象并更改颜色。目前,每个可绘制对象只是一个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;
    }
}

【问题讨论】:

    标签: android android-drawable statelistdrawable android-view-invalidate


    【解决方案1】:

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

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

    其他 0,02$:

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

    View.invalidate(new Rect(0, 0, 49, 49));
    

    【讨论】:

    • 嗨,ssh,你的第一句话是什么意思,只是有点理解困难。我试图使 rect 无效,但我仍然实现了非常缓慢的时间
    • @yun.cloud 我的意思是你在 UI 线程中有很长时间的工作。也许它是这样的对话框,或进度条或类似的。花一点时间来检查您的代码,并提出“这个方法/类中的硬逻辑是什么?”的问题。如果您确定问题不在这里,请尝试通过 DDMS 工具检查您的代码并查看系统中发生了什么。为什么你有滞后?
    • 好吧,我确实有一个音频线程在应用程序运行的整个过程中都在运行,所以可能是这样吗?我想这很重要,因此每次按下可绘制对象时都会播放正弦波。当我不必每次都重绘时,多点触控就可以了。但是,尝试对每个按下的可绘制对象进行重绘会减慢跟踪速度 - 有时当同时按下 3 个可绘制对象时,两个会立即更改/播放,而第三个则需要更长的时间来播放/更改颜色。我猜这种延迟与我的音频处理速度减慢有关?
    • @yun.cloud 如果您准备好每个声音或从文件系统加载它,它可能会产生滞后。我想你是在 UI 线程中这样做的。
    • 嗯,我在 Open SLES 中运行我的音频线程,是这样吗?我只是在没有运行音频线程的情况下对其进行了测试,并且触摸仍然滞后(同样的问题但没有声音)
    【解决方案2】:

    我也遇到了这个问题,但最后我解决了。这个问题的原因是你在上下文中使用的Drawable对象没有通过调用setBounds(Rect)来设置它的Bounds,所以它的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(0,0,0,0),如果你没有设置Drawable.Bounds。因此View.invalidate()不起作用。

    那么你要做的就是在代码的某个地方设置Drawable.Bounds,像这样:

    @Override
    public void draw(@NonNull Canvas canvas) {
        Rect localRect = canvas.getClipBounds();
        this.setBounds(localRect);
        ...
    }
    

    【讨论】:

      猜你喜欢
      • 2010-10-28
      • 2013-06-03
      • 2016-06-19
      • 2015-04-21
      • 2018-10-15
      • 2011-04-03
      • 2016-12-03
      • 2016-05-03
      • 1970-01-01
      相关资源
      最近更新 更多