View Animation in onResume doesn't work after rotation change - android

I animate a view in onResume() based on a certain boolean.
mView.startAnimation(mAnimation);
The animation always starts when returning to the activity, but it never starts when onResume() is called following a screen orientation change. I know that the above line of code is getting called because I checked it with debugging, so the boolean is not the problem.
What's different about an Activity that's coming back from a rotation that would cause an animation not to work?

My Animation was my own extended Animation that slides a view down by modifying its top margin. To find out the correct distance to slide it, I feed it the height of the view that it's sliding down to reveal. However, views don't have any height until onResume() is done, so I was inadvertently feeding it an offset of zero.
When returning from other activities, the view tree already has the heights left over from before. But after a screen rotation, the Activity is completely destroyed, so the views don't have any dimensions in onResume().
I fixed it by doing the following:
final ViewTreeObserver observer = mObscuredView.getViewTreeObserver();
observer.addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
boolean mDone=false;
#Override
public void onGlobalLayout() {
if (!mDone){
mAnimation.setTranslation(mObscuredView.getMeasuredHeight());
mView.startAnimation(mAnimation);
mDone=true;
}
}
});

Related

Setting android view location has no effect

I have a simple view inside of a RelativeLayout that I animate up & down so it slides off and on screen. This works every time except the very first time, where the animation does nothing.
This lead me to trying to set the Y location manually in the activity's onCreate() method. Oddly, that had no effect either.
Is there some reason a view's Y location can't be set until after the activity has been fully displayed? If not, why am I seeing this weird behavior, and is there a way to fix it?
The first time you're calling it's before the view has laid out.
You can get around this by listening for the view to be laid out.
view.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
view.getViewTreeObserver().removeOnGlobalLayoutListener(this);
// Perform whatever actions you want here
}
});

Refreshing custom view layout position

I have to implement slidable menu in my app. User should be able to show/hide it by tapping on it and move left/right.
To implement this, I`ve created custom SlidableFrameLayout that extends FrameLayout.
By overriding onTouchEvent method I calculate slide position and call
private void setLeftLayout(int left) {
layout(left, getTop(), getRight(), getBottom());
}
to change position for SlidableFrameLayout. Everything works fine, but when I keyboard shows (after focusing EditText), SlidableFrameLayout changes its left value to 0, so if menu was closed, it becomes opened. The same thing happens when I hide the keyboard (generally, it appears in all actions that prevents calling layout methods, I think).
I can not invent how to fix it. Could you help me? If any additional info is required, I`ll attach it. Thanks
I think your issue is related to calling layout directly. When the container view changes size as a result of the keyboard being shown/hidden onMeasure/onLayout will be called with the view's default bounds. In your case I'm guessing the left bound is 0, so layout is being called with 0 for left every time your window resizes.
Instead you probably want to use something like setTranslationX or scrollTo ..
Good luck!
As a result, I changed my logic:
private void setLeftLayout(int left) {
FrameLayout.LayoutParams params = getFrameLayoutParams();
params.leftMargin = left;
params.rightMargin = -left;
requestLayout();
}
In my case, view is a parent of FrameLayout, so I haven`t added any conditions in 1st line of the method. This method works pretty fine.

How can I tell when a Layout (and all its child Views) has fully finished inflating?

I have a situation where I have a custom Layout which contains a bunch of children and which I inflate into a ViewFlipper.
My problem is that the ViewFlipper badly stutters its animation as it tries to animate the Layout in, even as the Layout is still loading all its child Views.
I tried using onLayout, but that gets called the moment the parent Layout is done inflating (it doesn't wait for the child views to inflate, so the stutter persists)
I also tried onMeasure, but that's called dozens of times and keeps getting called every time anything in the Layout changes (such as the EditText getting focus, or changing value).
So, I'm stumped... does *ANYTHING happen, that I can listen for, when the Layout is fully inflated, so that I can THEN tell the Flipper to perform the animation?
You can override onFinishInflate() in your custom layout. This is called as the last phase of inflation, after all child views have been added.
You could use an OnPreDrawListener. This will be called immediately before the View is going to draw its first frame, at which point all of the children will be laid out.
CustomView myCustomView = (CustomView) findViewById(R.id.my_custom_view);
final ViewTreeObserver obs = myCustomView.getViewTreeObserver();
obs.addOnPreDrawListener(new OnPreDrawListener () {
#Override
public boolean onPreDraw () {
//We only care the first time it happens, so remove it
obs.removeOnPreDrawListener(this);
//Post your animation here, then return true
return true;
}
});

How do you find the bottom scrollable position in a ScrollView?

In an android scrollView, how do you find the lowest position in the scrollview so you can then use the scrollTo(x,y) method to scroll right to the bottom. I need the actual numeric value. Using the getHeight() method does not ever return the right value. The scrollbar will sometimes scroll to the end, and sometimes not reach it. There is a linearlayout with a textview in the scrollview. There has to be something that I am missing?
If you want to just scroll to the end, you should be able to just use fullScroll(ScrollView.FOCUS_DOWN). If you need a particularly numerical value based on the height of the scroll view, you will have to subclass your scroll view and override onSizeChanged, which will give you the actual numerical height. Keep in mind onSizeChanged will only be called after onResume, and will not necessarily be called every time your activity resumes.
Part of the reason why you sometimes scroll to the end and sometimes don't is probably because of a race condition. Sometimes your scroll happens before other important things (like populating the view) have happened, so it doesn't appear to do anything.
Try posting your calls to your scroll view's handler:
yourScrollView.post(new Runnable(){
#Override
public void run(){
yourScrollView.fullScroll(ScrollView.FOCUS_DOWN);
}
};
Sometimes even adding a short delay can help:
yourScrollView.postDelayed(new Runnable(){
#Override
public void run(){
yourScrollView.fullScroll(ScrollView.FOCUS_DOWN);
}
}, 200);
Thanks for the response. I found a quick hack if anyone is interested.
sView.fullScroll(View.FOCUS_DOWN);
sView.fullScroll(View.FOCUS_DOWN);
y = sView.getScrollY();
sView.fullScroll(View.FOCUS_UP);
This will jump down to the bottom of the scrollable, collect y, then jump up again. It happens so fast it is not visible and it will get you the bottom value of y every time. You have to call focus down twice or else y will return 0.

Android ViewFlipper measures of undisplayed child

I have a ViewFlipper on my main Activity's View. At onCreate I instante Views which are added to ViewFlipper. After that I set displayed child to first one. And when a button is clicked I switch ViewFlipper's display child to second view. Right after calling viewFlipper.setDisplayedChild(1) I need to do some calculations and instantate some objects which are based on width and height of displayed child.
Main problem here is that at first time (second = 1) child is displayed measurement of view is not done yet. So my width and height are 0. If I go back (setDisplayedChild(0)) and than goes back to second child it is ok (width and height are correct).
I have done some research about that behavior of views and found out that there is a method [onMeasure](http://developer.android.com/reference/android/view/View.html#onMeasure(int, int)) which can be overrided and everything can be done here. OK that how it should be. Actually it is but problem is that onMeasure is called 4 times on each view switch. And my findings was that at first and third call width and height are full screen sized. The second and fourth call are proper width and height. Because I have to instantate new objects at that point it is unwise to do it in onMeasure.
Is there any other, proper way of doing it?
Is it possible to force measurement?
Do I really need to show view on screen for measurements?
Regards
Zmeda
Your init-action (based on width and height of displayed child) should be invoked after measuring of ViewFlipper's children, you can achieve that using method post, e.g.:
viewFlipper.setDisplayedChild(1);
viewFlipper.post(new Runnable() {
#Override
public void run() {
Log.d("test", "w: " + viewFlipper.getCurrentView().getWidth());// not 0
//do some calculations and instantate some objects
}
});

Categories

Resources