如何在执行下一行代码之前强制视图重绘
我有一个 LinearLayout,我想在单击其子视图之一(ImageButton)时更改其背景颜色。我可以做到这一点,但不是立即 - 直到稍后(我认为在 onResume 调用期间)屏幕上才会发生更改。我想了解如何在设置背景后、执行下一行代码之前强制重新绘制布局。这是按钮的 OnClickListener 的 onClick 方法:
public void onClick(View v) {
LinearLayout parentLayout = (LinearLayout) v.getParent();
parentLayout.setBackgroundResource(R.color.my_color);
SystemClock.sleep(1000); //ms
}
sleep 命令用于测试重绘是在其之前还是之后发生。结果:之后。关于此主题的大多数问题(例如此处和此处)说在视图上使用 invalidate() 。我在之间使用了命令 parentLayout.invalidate();
、parentLayout.postInvalidate();
和 parentLayout.refreshDrawableState();
背景和睡眠线,都无济于事。在 sleep 命令之后,重绘仍然发生。谁能告诉我如何立即实现它?
其他可能有用的信息:LinearLayout 绑定到 ListView 的行,上面的 OnClickListener 位于扩展 SimpleCursorAdapter 的自定义类中,而不是位于活动本身中。 (这样我就可以为 ListView 中的每一行设置一个侦听器。)
I have a LinearLayout that I would like to change the background color of when one of its child views (an ImageButton) is clicked. I am able to do this, but not immediately - the change doesn't occur on the screen until later (I think during an onResume call). I would like to find out how to force the layout to redraw after the background is set, before the next line of code executes. Here is the onClick method of my OnClickListener for the button:
public void onClick(View v) {
LinearLayout parentLayout = (LinearLayout) v.getParent();
parentLayout.setBackgroundResource(R.color.my_color);
SystemClock.sleep(1000); //ms
}
The sleep command is in there to test whether the redraw happens before or after it. The result: after. Most questions on this topic (like here and here) say to use invalidate() on the view. I have used the commands parentLayout.invalidate();
, parentLayout.postInvalidate();
, and parentLayout.refreshDrawableState();
in between the background and sleep lines, all to no avail. The redraw still happens after the sleep command. Can anyone tell me how to make it happen immediately?
Other possibly useful information: The LinearLayout is bound to the rows of a ListView, and the OnClickListener above is in a custom class that extends SimpleCursorAdapter, not in the activity itself. (This way I can set a listener for each of the rows in the ListView.)
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
您可以尝试使用
forceLayout()
并立即调用draw(canvas)
。如果您没有重写onLayout()
、onMeasure
、draw()
或onDraw()
,则默认值实施将运行。唯一的问题是您必须获取画布或手动创建画布。强烈建议不要采用这种方法,因为 Android 是专门为避免在正常更新之外进行绘制而设计的。虽然您认为
invalidate()
不会立即发生,但这是鼓励重画的最安全、最好的方法。如果您想在更新之外处理绘图,Android 提供了一种使用 SurfaceHolder 类来实现此目的的方法。You might try
forceLayout()
with a call todraw(canvas)
immediately after. If you did not overrideonLayout()
,onMeasure
,draw()
oronDraw()
, then the default implementation will run. The only issue with this is that you have to either get the Canvas or create one manually.It is strongly discouraged to pursue this approach as Android is specifically designed to avoid drawing outside of normal updates. While you are correct that
invalidate()
does not happen immediately, it is the safest and best way to encourage a redraw. If you want to handle drawing outside of updates, Android provides a way to do that with the SurfaceHolder class.好吧,我终于找到了解决这个问题的方法,而且很简单。问题似乎只是我在 OnClickLIstener 中执行可绘制更改,而我应该在 OnTouchListener 中执行此操作。如果我为按钮设置一个 OnTouchListener 来查找 ACTION_DOWN,然后在其父布局上运行 setBackgroundColor,则更改会立即发生。
另一种不太健壮的解决方案来自 这篇文章。您可以在 xml 中为父布局背景分配一个选择器,然后在上面提到的 OnTouchListener 中,在该布局上运行 setPressed(true) 。这不是一个很好的解决方案,因为选择器为您提供的自由度比直接在代码中更改视图属性要少得多。例如,您无法通过按不同的按钮将布局背景设置为不同的颜色。
感谢那些对此提供帮助的建议!
Okay, I finally found a solution to this issue, and it's simple. It seems that the problem was just that I was executing the drawable changes in an OnClickLIstener, when I should have been doing it in an OnTouchListener. If I set an OnTouchListener for my button that looks for ACTION_DOWN and then runs setBackgroundColor on its parent layout, the change occurs immediately.
An alternative, less robust solution comes from this post. You can assign a selector for the parent layout background in xml, then in the OnTouchListener mentioned above, run setPressed(true) on that layout. It's not a great solution because the selector gives you a lot less freedom than directly changing the view's properties in code. You couldn't set the layout background to a different color by pressing a different button, for example.
Thanks to those who helped out with suggestions on this!
进行更改并调用 listview.invalidate();在 UI 上反映这些更改
make the changes and call listview.invalidate(); to reflect those changes on UI