I have an activity that (when started) shows some coachmark views (All ImageButtons) on screen that indicate how the app should be used (function of certain buttons, swipe behaviour, etc). A fade out animation is associated with each of these views that triggers after some predefined interval. This works as expected. However, I would like those marks to disappear earlier if the user interacts with the activity in a certain way. When these actions are triggered I cancel the animations and callsetVisibility(View.INVISIBLE); on the coachmark views. However, the visibility of the view does not change. I have experimented with other techniques - removing the view from the parent and setting alpha to 0 and these work fine but altering view visibility does nothing.
The code that sets up the coachmark looks as follows:
private void animateCoachmark(int id) {
AlphaAnimation animation = new AlphaAnimation(1.0f, 0.0f);
final View view = findViewById(id);
animation.setStartOffset(10000);
animation.setDuration(500);
animation.setAnimationListener(new AnimationListenerBase(null) {
#Override
public void onAnimationEnd(Animation animation) {
view.setVisibility(View.INVISIBLE);
}
});
view.startAnimation(animation);
coachmarkViews.add(view);
}
The problematic code to change visiblity:
for (final View coachmarkView : coachmarkViews) {
Animation animation = coachmarkView.getAnimation();
if (animation != null) {
animation.cancel();
}
coachmarkView.setVisibility(View.INVISIBLE);
}
This issue seems to be that changes to visibility are not honoured as long as an animation is associated with a view even if the animation has been cancelled. Altering my cleanup code to first set the animation on the view to null allows the view to disappear as expected.
for (final View coachmarkView : coachmarkViews) {
Animation animation = coachmarkView.getAnimation();
if (animation != null) {
animation.cancel();
coachmarkView.setAnimation(null);
}
coachmarkView.setVisibility(View.INVISIBLE);
}
Related
I am trying to slide down a view on a button click and on the same button click slide upwards
Everything works on the first time once slide down and slide up is done the again it wont work
if (slideView.getVisibility() != View.VISIBLE) {
Transition transition = new Slide(Gravity.TOP);
transition.setDuration(300);
transition.addTarget(slideView);
TransitionManager.beginDelayedTransition(slideViewParent, transition);
slideView.setVisibility(View.VISIBLE);
transition.removeTarget(slideView);
} else {
slideView.animate()
.translationY(-slideView.getHeight())
.setDuration(400)
.setListener(new AnimatorListenerAdapter() {
#Override
public void onAnimationEnd(Animator animation) {
super.onAnimationEnd(animation);
animation.end();
slideView.setVisibility(View.GONE);
}
});
}
it will slide down initially from the parent view .. then on button click it will slide up.. the again on button click nothing happens.. I want to slide down it again
I have no enough reputation to comment.
But, if your view is already visible or even already gone then your error is at this two lines:
slideView.setVisibility(View.VISIBLE);
slideView.setVisibility(View.GONE);
The view is already visible or already gone and you are setting it to visible/gone again ending in an infinite loop of going down/up.
So, change your code to this:
if (slideView.getVisibility() != View.VISIBLE) {
Transition transition = new Slide(Gravity.TOP);
transition.setDuration(300);
transition.addTarget(slideView);
TransitionManager.beginDelayedTransition(slideViewParent, transition);
slideView.setVisibility(View.GONE);
transition.removeTarget(slideView);
} else {
slideView.animate()
.translationY(-slideView.getHeight())
.setDuration(400)
.setListener(new AnimatorListenerAdapter() {
#Override
public void onAnimationEnd(Animator animation) {
super.onAnimationEnd(animation);
animation.end();
slideView.setVisibility(View.VISIBLE);
}
});
}
Since you are animating the view depending on its visibility, i.e. (slideView.getVisibility() != View.VISIBLE), then it is not a good idea to set its visibility in this piece of code. You might want to animate it on a different boolean ( in my case if music is playing, slide up and visibility visible, else slide down and visibility gone). If there is another thing changing your view's visibility, then the following codes will work as is.
Inside the onClickListener:
if (slideView.getVisibility() != View.VISIBLE) {
// if the view is not visible, slide it up
slideView.animate()
.translationY( -slideView.getHeight() )
.setInterpolator( new LinearInterpolator() )
.setDuration( 500 )
.start();
} else {
// if the view is visible, slide it back where it was
// 0 indicates the original position the view was in
slideView.animate()
.translationY( 0 )
.setInterpolator( new LinearInterpolator() )
.setDuration( 500 )
.start();
}
Please keep in mind, this all depends on the visibility of the view itself and on how you do that!
You might need to tell us who , in your codes , changes the visibility of the view to give you a better if statement.
I want animate view on click of it. I am animating that view using AnimatorSet
But when user scroll at that time state of animation is not maintain or not clearAnimation properly. It will animate other item's icon.
anyone has idea on it?
animation method:
public static void likeAnimation(Object object) {
if (object == null) {
return;
}
AnimatorSet set = new AnimatorSet();
Object myView = object;
set.setInterpolator(new LinearInterpolator());
set.playTogether(
ObjectAnimator.ofFloat(myView, "rotation", 0, 360)
);
set.setDuration(500).start();
}
RecyclerView code:
#Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
holder.imageView_like.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(final View v) {
likeAnimation(v);
}
}
You're just in time with this question, and I hope I'm not too late. An idea here is very simple. You have to keep in mind that your RecyclerView reuses every single ViewHolder which has ever been created. Usually, it creates about 7~8 items, but it depends on screen size.
So, in your particular case if you want to animate an item upon click, you have to track the state of every item in your RecyclerView. Basically, you can have three states:
Enter state or your very animation. When the user clicks on some item from the list, you start animating that item, and in the end of animation switch the state of the item to Animated state.
Animated state. This is the state of an item that has been animated, and doesn't need this animation again, so when the user scrolls up/down you just need to set a view into the animated state. In your case, you can try the following code:
private void animatedState(View view){
//perform the same action but without animation
view.setRotation(360);
}
Default state or normal state. That is View without rotation, just a normal state. For instance,
private void defaultState(View view){
view.setRotation(0);
}
Also you may want to animate the items back upon click, if yes, you have to add one more state which is an Exit state, and then switch from that state to the Default state.
You can find the entire implementation of this idea by this link.
I am doing an animation inside a fragment.
I have 2 views on top of each other, one of them set on View.GONE.
when I press a button I want my 2nd fragment to translate animation from the bottom to top.
I am doing it fine and it's working great,
the problem is that in my first run, the xml view is gone, but he is in the same Y he is suppose to be.
so the first animation I do isn't doing anything, just switch from GONE to VISIBLE, after that, I press dismiss and the fragment goes away and comes back just like I want too.
my problem is just the first run.
how can I set my view Y to be 100% below my screen?
here's the code I use :
private void moreCustomAnimation() {
int yOffset = moreMenuFrameLayout.getMeasuredHeight();
TranslateAnimation moveAnim = new TranslateAnimation(0, 0, yOffset, 0);
moveAnim.setDuration(500);
moveAnim.setFillAfter(true);
blackView.setVisibility(View.VISIBLE);
moreMenuFrameLayout.setVisibility(View.VISIBLE);
moreMenuFrameLayout.startAnimation(moveAnim);
moveAnim.setAnimationListener(new Animation.AnimationListener() {
#Override
public void onAnimationStart(Animation animation) {
}
#Override
public void onAnimationEnd(Animation animation) {
}
#Override
public void onAnimationRepeat(Animation animation) {
}
});
}
on the way out of the screen I use the same code just switch the
yOffset to the other Y integer, and set the view to GONE at animation end.
thanks a lot in advance for any help !
You can use the onGlobalLayout event to set the position of the view.
Like this:
moreMenuFrameLayout.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
moreMenuFrameLayout.setTranslationY(moreMenuFrameLayout.getMeasuredHeight());
moreMenuFrameLayout.getViewTreeObserver().removeOnGlobalLayoutListener(this);
}
});
This event happens when your views get their actual size and position before being drawn to the screen. However, they happen every time the view is drawn so you must remember to remove the listener right after the first time.
HTH
First time you can add the 'yOffset' value to the view orginal points
moreMenuFrameLayout.setY(currentYpostition + yOffset)
and this will place the view to the bottom of the screen. You can enable the visibility when the animation starts.
I have a LinearLayout, I'm applying a translation animation to it. I'm filling the animation before and after. Visually it works fine. The animation ends by translating the view off screen. But if I click an x,y coordinate on screen that happens to be where the view was at some point during its animation, a button on the view has its click listener fire.
The only solution I've found is to add an animation listener, and when the animation ends, mark the buttons on the (now out of view) layout to visibility=gone, enabled=false. This seems bizarre - the view is no longer on screen, but it's still responding to click events. Is this a known thing, I'm probably not setting the animation up correctly?
Thanks
----- Update --------
I refactored my animation a little. Instead of using animation.setFillAfter(true), I set the layout's visibility to GONE when the animation is complete. Now it doesn't register clicks when off-screen. Still interested to know if this is a known thing, as it'd be easier to simply not have to add an animation listener etc.
Translate Animations on lower level API( below honey comb) changes where the button is drawn, but not where the button physically exists within the container. So, you are on your own to handle this situation. For more information about this you can refer to this link. One way is to actually change the location of the button in the layout(not by animation). Here is how you can achieve this:
params = (LayoutParams) mBtn.getLayoutParams();
TranslateAnimation animation = new TranslateAnimation(0, 0, 0, 400);
animation.setDuration(2000);
animation.setAnimationListener(mAnimationListener);
mBtn.startAnimation(animation);
....
....
private AnimationListener mAnimationListener = new AnimationListener() {
#Override
public void onAnimationStart(Animation animation) {
}
#Override
public void onAnimationRepeat(Animation animation) {
}
#Override
public void onAnimationEnd(Animation animation) {
params.topMargin = params.topMargin + 400;
mButton.setLayoutParams(params);
}
};
Here by changing the layout params we are changing the physical position of the button.
In your case as view is going off the screen so you just need to change the visibility of the button(View.GONE) on animation end.
found many question on same issue.
How to set OnClickListener on the ImageView after rotation animation
How to write the onclick listener for a view after animation?
i also have same issue, any suggestion ?
You ought to write a fresh, concise question about your specific issue rather than just pointing to other questions. The two questions linked to aren't entirely clear.
I assume your issue is that after applying an animation (such as a TranslateAnimation, for example) to a View, the View no longer responds to touch events in its new position. The reason for this is because the View hasn't been moved to the new position in terms of layout parameters, but rather it has had a transformation applied.
The solution is quite simple: immediately after the animation has completed, actually move the View to the new position. You could set myAnimation.setFillAfter() = false, and set a listener to physically move the View to the target location when the animation has finished:
myAmazingAnimation.setFillAfter() = false;
myAmazingAnimation.setAnimationListener(new Animation.AnimationListener(){
#Override
public void onAnimationEnd(Animation animation) {
// Now actually move the View using LayoutParams
}
#Override
public void onAnimationRepeat(Animation animation) {
}
#Override
public void onAnimationStart(Animation animation) {
}
});
Another variation is to physically move the View at the beginning before animation is applied, and then apply an animation that makes the View start where it used to be and end at 0,0.