For my current project I'm building a pulldown view with a handle and a content.
When I move the handle by dragging it everything is fine. Then I let it go and start an animation to fully open or close the pulldown.
First: without the animation in it everything is fine, but off course not that smooth...
So I've added this for the animation:
ObjectAnimator animHandle = ObjectAnimator.ofFloat(mHandleContainer, "y", newHandlePosition);
ObjectAnimator animContent = ObjectAnimator.ofFloat(mContent, "y", newContentPosition);
final AnimatorSet animatorSet = new AnimatorSet();
animatorSet.playTogether(animHandle, animContent);
animatorSet.setInterpolator(new AccelerateDecelerateInterpolator());
animatorSet.setDuration(MAX_ANIMATION_DURATION);
animatorSet.start();
Everything is just fine utill here.
But then, when I press the handle (mHandleContainer) again, I want to know where the handle is positioned so I do a
mHandleContainer.getTop()
And that is where it all goes wrong.
When I initialize the custom component I set the top of the handle to 0.
So far so good, then I start dragging, when I let go I see that I will animate to a position of 1134 pixels. Which is fine (meaning the pull down will be entirely open).
But then I press the handle again and get the top (getTop()) and it still returns me 0.
What I want is that my view's getTop() function returns me 1134 again.
Is that possible?
Or should I do something in the onAnimationEnd method of my AnimatorListener?
I already tried to do a mHandleContainer.layout(..) in there and then my getTop() is ok, but then my layout is screwed...
And tricks here for letting the animation end on the correct position (as it does) and persist the position in the view?
I already had a look on SO (and Google) but didn't find something useful. The only thing close to my problem that I could find was this: NineOldAndroids, not clickable view after rotation or move
But didn't help either...
This is because your are animating the "y" property while trying to read the property top, and they aren't the same.
Top is the top position of the view relative to its parent.
Y is the visual y position of the view which is equivalent to translationY + the current top property.
So in your case:
Either animate "top" like this:
ObjectAnimator animHandle = ObjectAnimator.ofFloat(mHandleContainer, "top", 200);
And read it via
mHandleContainer.getTop()
Or "y":
ObjectAnimator animHandle = ObjectAnimator.ofFloat(mHandleContainer, "y", 200);
And read it via
mHandleContainer.getY();
I did solve the issue using the basic ValueAnimator which each time called my custom drawing method for moving all my views.
Related
I tried searching around and found that you have to set a listener to change the actual position of the view when the animation ends. But the thing is, I don't know how I can get the end values from the ObjectAnimator I am using.
Isn't there an easy way to do this aside from setting listeners to all of my Animators, there are like 9 of them. Something like a setFillAfter(true) I always see that but I can't seem to find what Animator object uses it.
It turns out you have to have an AnimatorListener attached to the Animators that will do this for you. But that is too much for me because I have multiple Animators. So what I did, I positioned them on the layout in what they would be after the end animation, then I made the Animator to animate from the start position to their end position. That way I don't have to fret over the actual positions of the views
I have a layout containing several buttons. I want to move this layout to a different position on screen using an animation. When I use a TranslateAnimation, the layout appears to move however the button press events are still only triggered from their old location. I have attempted to then adjust the view's LayoutParams in the onAnimationEnd event - this only resulted in some horrible looking snapping effect when the animation completed. No other answers seem to give a definitive solution to this problem.
How can I move a layout using an animation whilst also ensuring their onClick events are triggered from their new location?
You have to use ObjectAnimator it will actually move your Button with listener attached to their new positions
ObjectAnimator moveButtonAnimator = ObjectAnimator.ofFloat(layout, "translationX", 0, 200f);
moveButtonAnimator.start();
moveButtonAnimator.setDuration(1000);
I'm working on a simple sliding-drawer component. It's a similar to the deprecated SlidingDrawer component.
I'm extending LinearLayout (because that suits what I need to do). I'm not doing anything very fancy, just a handle that you click on to open and close the drawer.
My drawers are contained in a RelativeLayout, and for opening and closing it uses a TranslateAnimation to reposition the view mostly off-screen (with just the handle showing).
The problem I am having is that when the drawer is closed, the child components inside the drawer are responding to touch events at the same screen position as if the drawer was open - even though they are clearly not in that position.
For my right-hand drawer this is particularly bad because the area where you should be able to click the handle does not work, as the event is being handled instead by the component that would be in that position if the drawer were open.
It's really odd. I tried a requestLayout on the drawer in the onAnimationEnd event, but that did not help (in desperation I also tried invalidate and forceLayout - also did not work). I've also tried calling the requestLayout on the parent view.
Any thoughts on what else I could try?
It seems that the weird touch events occur because the view is translated, and for whatever reason this translation is not also applied to the touch region - go figure.
I resolved the problem by clearing the animation (which removes the translation), and then repositioning the view using layout params. Here's a snippet...
#Override
public void onAnimationEnd(Animation a) {
drawer.clearAnimation();
MarginLayoutParams lp = (MarginLayoutParams) drawer.getLayoutParams();
switch (drawer.mAlign) {
case ALIGN_LEFT:
lp.leftMargin = x2;
break;
case ALIGN_RIGHT:
lp.rightMargin = -x;
break;
case ALIGN_TOP:
lp.topMargin = y2;
break;
case ALIGN_BOTTOM:
lp.bottomMargin = -y2;
break;
}
drawer.setLayoutParams(lp);
}
x2 and y2 are the final x and y positions calculated earlier for use in the TranslateAnimation, and then reused here.
Note: On the animation I use setFillAfter(true). You can potentially leave this out, and then you also don't need the clearAnimation() later, but I found that doing this caused a flicker.
I hope this helps others. I'm a bit of a noob to Android, so very happy for any corrections or better ways of handling this!
The pre-3.0 animation system only updates the drawing for a given view, not its actual bounds including touchable areas.
You can use the newer animation properties (you'll need 9OldAndroids if you want to support pre honeycomb), or set the draw view to gone after the animation to slide it off has finished.
You could also try playing with offsetLeftAndRight
I'm playing with webviews in Android and got stuck on the idea of making animation for scrollTo method. Basically the method scrollTo(x,y) scrolls the page to the given point, but it does it instantly.
I would like it to be slower, like an animation transition. Anyone knows how to do it?
Edit 1:
I just tried with xml and code based Translate animations. It seems to move the webview, but only as a "whole" view, so it scrolls down, but not the webview's scrollbar but rather the whole viewport of the webview (does it make sense?) So effectively I can see my current page sliding down with a black screen sliding after it (from top do the bottom). It kind of makes sense, because I'm translating the whole webview (move it down...). I've tried to set Animation.ABSOLUTE, Animation.RELATIVE_TO_PARENT and Animation.RELATIVE_TO_SELF respectively, with no success.
How can I then animate the position of the scroll directly in the webview rather then the whole view?
Edit 2:
After several more tries, I understand more how the animations work. I therefore claim that it's not possible to override default "instant" scrollTo behaviour. If anyone has a different opinion or knowledge about that, let me know.
Use ObjectAnimators. This code smoothly scrolls the WebView to the top:
ObjectAnimator anim = ObjectAnimator.ofInt(mWebView, "scrollY",
mWebView.getScrollPositionY(), 0);
anim.setDuration(400);
anim.start();
I think you need to first set animation to the web view and if you want to use it immediately then you need to say start animation. Use xml to define the Animations.
I have seen an answer related to this question, check this link
I've got an absolute layout. In that layout is a custom view that takes up the left 3rd of the screen. I put a button in the layout that I want to cause the custom view to slide on and off of the screen. I've tried using animation resources (translates... "slidein" and "slideout") and the function startAnimation on the custom view, but I can't get the behavior I am looking for.
OK... I start with the custom view visible and in onCreate I find the view and animate it off screen using my slideout animation. That works fine. I figured out that I need to set "fillAfter" in the animation so that the custom view stays off screen.
Now, when I press my button I want to cause the custom view to slide back on the screen, so I trigger my slidein animation using startAnimation again but with slidein. BUT... that causes the view to first jump back to its original position AND THEN slide to the right... causing it to finish in the middle of the screen.
How do I get the animation to use the view's current position as the animation starting position, not its original position?
Thanks
I also experienced the flicker described in this question. My solution was to use the improved Honeycomb animation APIs. There is a convenient library that ports these all the way back to Android 1.0:
http://nineoldandroids.com/
For more on Honeycomb Animation APIs see:
http://android-developers.blogspot.com/2011/02/animation-in-honeycomb.html
In my case I had 2 overlapped LinearLayouts inside a RelativeLayout. I wanted to slide the top LinearLayout off the screen and reveal the bottom LinearLayout below. Then I wanted to slide to top LinearLayout back on screen to its original position so the top layout covered the bottom layout again. Using the old animation APIs I was seeing a flicker before the second animation (offscreen -> onscreen) was starting.
With the new APIs this task turned out to be trivial:
// Slide out (add to button handler)
ObjectAnimator.ofFloat(mTopLayout, "translationY", mTopLayout.getHeight()).start();
// Slide back in (add to button handler)
ObjectAnimator.ofFloat(mTopLayout, "translationY", 0).start();
The Honeycomb Animation APIs actually move objects around on the screen (rather than pretending to move them like the older animation APIs), so there is no need to fool around with filleAfter, fillBefore, etc.
Look into setting the fillAfter property to keep the end animation state