What event signifies that the draw of a View is complete?
I know about ViewTreeObserver listeners, but I couldn't find the 'final' one, which indicates, that the job is done.
yourView.post(someRunnable) ensures, that someRunnable will be executed after the view is laid out and drawn.
What event signifies that the draw of a TextView is complete?
There is no such hook for View class (or TextView). There is, however, onDraw() method which is called when the view should render its content.
So you can do:
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
// Finished drawing. Do other stuff.
// However you must check if this is the first or subsequent call.
// Each call to "invalidate()" will trigger re-drawing.
}
If I understand your question correctly the method you are looking for is onWindowFocusChanged(boolean hasFocus). Or else you could try the onPostResume() method.
Related
I'd like to be notified after the view finishes redrawing after I ask it to invalidate. As said in this answer, the invalidate() method doesn't call a View's onDraw() the UI immediately, but schedules the repaint in a message queue which is executed after when the main thread is idle.
I'd like to show a progress dialog, do some UI modifications and then dismiss the dialog when the view is drawn properly. Is there some trick that I can do to know when the View was drawn? Maybe by subclassing the view, overriding the onDraw() method?
I think you answered your question yourself. Why not:
public class DrawListenerView extends View{
private Callback callback;
public DrawListenerView(Callback callback){
this.callback = callback;
}
#Override
protected void onDraw (Canvas canvas){
super.onDraw(canvas);
//add your method here you want to call
//Or use a Callback-pattern
callback.finish();
}
}
public interface Callback(){
public void finish();
}
If you look at the Source:
http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android/2.1_r2/android/view/View.java#View.invalidate%28%29
The comment above says
Invalidate the whole view. If the view is visible, onDraw(android.graphics.Canvas) will >be called at some point in the future. This must be called from a UI thread. To call from >a non-UI thread, call postInvalidate().
Try it :)
Edit: probably you want to use a Callback to handle this.
You're finding it strange to try to do this because you're going about it all wrong. ;)
You're talking about wanting to wait to dismiss a dialog until something is finished drawing. That implies that you have a drawing operation that is long enough that you want to wait for it.
Drawing a frame in onDraw should be fast. You have 16 milliseconds per frame to do any sort of input processing and drawing if you want to hit 60fps and have a smooth UI. Drawing should never take long enough that you would want to show a progress dialog while it's finishing. (Aside from that, drawing as a result of invalidating part of your UI blocks your UI thread, and your progress dialog wouldn't illustrate any progress until it's done anyway.)
If you need to do some complex off-screen rendering to show later, you should do it in an AsyncTask or similar off of your UI thread, not in a view's actual onDraw method. Once you get the finished callback from that, you can quickly draw the prerendered image you just created and dismiss your progress dialog.
I need a way to run some code at the exact moment in which the activity is fully loaded, laid out, drawn and ready for the user's touch controls. Which method/listener does that?
Commonsware is right, without explaining what your are trying to do and why, it's not possible to answer your question and I suspect, with detail, you are probably thinking about it the wrong way.
However, I do have some code where I needed to do some very funky layout stuff after everything had been measured.
I could have extended each of the view classes in the layout and overriden onMeasure() but that would have been a lot of work. So, I ended up doing this. Not great, but it works.
mainMenuLayout is the layout I needed to get funky with. The onGlobalLayout callback is called when the layout has completed drawing. Utils.setTitleText() is where the funkiness takes place and as I pass mainMenuLayout to it, it has access to the position and size of all of the child views.
mainMenuLayout.getViewTreeObserver().addOnGlobalLayoutListener(
new ViewTreeObserver.OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
// only want to do this once
mainMenuLayout.getViewTreeObserver().removeGlobalOnLayoutListener(this);
// set the menu title, the empty string check prevents sub-classes
// from blanking out the title - which they shouldn't but belt and braces!
if (!titleText.equals("")){
Utils.setTitleText(_context,mainMenuLayout,titleText);
}
}
});
I've found that if I post a Runnable to the message queue, it will run after the content for the activity has been drawn. For example, if I want the width and height of a View, I would do this:
view.post( new Runnable() {
#Override
public void run() {
int width = view.getWidth(); // will be non-zero
int height = view.getHeight(); // will be non-zero
}
} );
I've found success with this anytime after I call setContentView().
onRestoreInstanceState method is the one called to restore UI state which is called after onResume .I think you can use this onRestoreInstanceState method.. and put your code after restoring UI state from the savedInstanceState...
Try onPostResume() called after onResume() at this moment the Activity instance should be visible and all underlying Views are rendered. In many situations this is true when onResume() is called as well.
Maybe it little helps:
#Override
public void onAttachedToWindow(){}
I subclassed View to get an View on which the user can "draw" with his fingers. I implemented the Interface View.OnTouchListener.
How can I trigger within the onTouch method the redraw of the View? Do I need to implement a Thread / Runnable? I thought that invalidate() triggers the redraw, but this doesn't work.
Just call this.invalidate in the onTouchEvent method of your view, it really should work unless you're not doing the proper thing in your onDraw method. Make sure you're referencing to the right canvas an draw the thing in your overridden onDraw method instead of for example the constructor.
#Override
public boolean onTouchEvent(MotionEvent event) {
this.invalidate();
return true;
}
The class MyImageView extended ImageView, In method onDraw(), I have following code:
#Override
protected void onDraw(Canvas canvas) {
this.setImageBitmap(someBitmap);
super.onDraw(canvas);
}
Although the code works, I am wonder why onDraw has not benn called infinitely, since setImageBitmap will call onDraw -->right or not? I am still want to know is there performance issue for above code?
setImageBitmap() will call invalidate() which will in turn call onDraw() later on. What you are doing is a really bad idea :)
I'm wondering, will it be possible not working with a thread? could i still update the View's Canvas every time i will try to put an image every touch event?
You won't have to create a thread, just put your drawing stuff in the overrided method
View.onDraw
#Override
protected void onDraw(Canvas c) {
// blah blah blah........
}
Call View.invalidate everytime when updating is needed.