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.
Related
I have viewpager having 2 items on second item i want to show button translating from downwards on swiping back to first item.
Below is my code:
pager.registerOnPageChangeCallback(object : ViewPager2.OnPageChangeCallback(){
override fun onPageSelected(position: Int) {
super.onPageSelected(position)
if(position == 1){
signIn.visibility = View.VISIBLE
signIn.animate().translationY(signIn.height.toFloat())
}
else{
signIn.visibility = View.INVISIBLE
signIn.animate().translationY(signIn.height.toFloat())
}
}
})
How can I implement the above functionality?
signIn won't move in Y direction because you are feeding it the same value - signIn.height.toFloat.
On top of that, you are making the signIn button INVISIBLE before you try to animate. You won't see any animation.
Here is how I would do it. Say, I want to hide the signIn button with vertical slide (to bottom) + fade out animation.
if (position == 1) {
// SHOW
// assuming that the button is gone before showing it
signIn.setTranslationY(100); // setting the starting Y position of the button
signIn.setAlpha(0f); // zeroing the alpha
signIn.setVisibility(View.VISIBLE); // now we can make it visible and start animating
signIn.animate().setDuration(500)
.translationY(0) // Y goes down from 100 to 0
.alpha(1f) // alpha goes form 0 to 1
.start();
} else {
// HIDE
signIn.animate()
.setDuration(500)
.translationY(100) // it animates Y of the button from 0 to 100
.alpha(0) // animates alpha from 1 to 0
.withEndAction(new Runnable() {
#Override
public void run() {
// this code runs when the animation ends. Every time when you hide a
// button with an animation, you should set its visibility to `GONE` not
// `INVISIBLE` because, `INVISIBLE` buttons can still be clicked which may
// produce undesired flow in your app
signIn.setVisibility(View.GONE);
}
}).start();
}
PS. The code snipped I wrote is in Java, you can still copy and paste it to you Editor and it will automatically convert it to Kotlin.
Don't just set visibility to INVISIBLE immediately before you animate it, you will be animating an invisible view, aka it will not show the animation. Instead, make it invisible after the translation ends.
You are translating Y with a positive value each time. The view will eventually end up outside of the screen. You should be doing a negative translation in one animation, and positive in the opposite animation.
Even better, instead of changing visibility, why don't you just animate alpha with the Y translation.
EDIT:
From docs
private fun crossfade() {
contentView.apply {
// Set the content view to 0% opacity but visible, so that it is visible
// (but fully transparent) during the animation.
alpha = 0f
visibility = View.VISIBLE
// Animate the content view to 100% opacity, and clear any animation
// listener set on the view.
animate()
.alpha(1f)
.setDuration(shortAnimationDuration.toLong())
.setListener(null)
}
// Animate the loading view to 0% opacity. After the animation ends,
// set its visibility to GONE as an optimization step (it won't
// participate in layout passes, etc.)
loadingView.animate()
.alpha(0f)
.setDuration(shortAnimationDuration.toLong())
.setListener(object : AnimatorListenerAdapter() {
override fun onAnimationEnd(animation: Animator) {
loadingView.visibility = View.GONE
}
})
}
Now, you just need to add your translationY() to the animate() chain, like this:
pager.registerOnPageChangeCallback(object : ViewPager2.OnPageChangeCallback(){
override fun onPageSelected(position: Int) {
super.onPageSelected(position)
if(position == 1){
signIn.apply {
alpha = 0
visibility = view.VISIBLE
animate()
.alpha(1f)
.translationY(signIn.height.toFloat())
}
}
else{
signIn.animate()
.alpha(0f)
.translationY(-signIn.height.toFloat())
.withEndAction {signIn.visibility = View.GONE}
}
}
}
})
I managed to have a relative layout with an image in the middle over a constraint layout - this image should be shown instead of a Toast-Message (fade in => fade out)
When the app starts - just to prove that it works - it shows that image from the XML settings (thumb up / visibility).
Now I want to use the following function to change the image:
public void showThumbs(Integer like){
if (like > 0){
overlayout.bringToFront();
overlay.setImageResource(R.drawable.like);
overlay.bringToFront();
overlay.animate().alpha(1.0f).setDuration(800);
overlay.animate().alpha(0.0f).setDuration(800);
}
if (like < 0){
overlayout.bringToFront();
overlay.setImageResource(R.drawable.dislike);
overlay.bringToFront();
overlay.animate().alpha(1.0f).setDuration(800);
overlay.animate().alpha(0.0f).setDuration(800);
}
}
I tried to work with visibility which did not work and now I tried the animation fader.
What happens is this:
At the beginning it shows the thumb up as set in the XML-layout itself - OK
When I set like to a negative value it changes the image and fades it out
When I set like to a positive value it uses the thumbs up and fades it out
But it only works fades the image the first time and only the fade out part.
As soon as it is gone I can call this function again an again and it will not show any picture anymore.
Any idea where my mistake is?
It should work like a Toast-Message (Fade in => Fade out).
First of all there should be else between if statements. So you should have if( ){ } else { } instead of if( ) { } if( ) { }
Secondly, this line makes your image invisible permanently:
overlay.animate().alpha(0.0f).setDuration(800);
To make it work you should "chain" you animations. First option is:
if (isLiked) {
overlay.setImageResource(R.drawable.like);
// overlay is invisible by default
overlay.animate()
.alpha(1.0f)
.setListener(new AnimatorListenerAdapter() {
#Override
public void onAnimationEnd(Animator animation) {
super.onAnimationEnd(animation);
overlay.animate().alpha(0.0f).setDuration(800);
}
}).setDuration(800);
} else {
//...
}
Another option is using AnimatorSet.
ObjectAnimator fadeOut = ObjectAnimator.ofFloat(overlay, "alpha", 1f, 0f);
fadeOut.setDuration(800);
ObjectAnimator fadeIn = ObjectAnimator.ofFloat(overlay, "alpha", 0f, 1f);
fadeIn.setDuration(800);
final AnimatorSet mAnimationSet = new AnimatorSet();
mAnimationSet.play(fadeOut).after(fadeIn);
mAnimationSet.start();
I am trying to do animation with my custom view. This custom view is a combination of other view. I am trying to do a very simple animation and it get triggered when a button is clicked. I want the view to slide and disappear in 2 seconds. But It seems it disappears in less than 2 seconds. I tried to increase the duration but it did not help.
public void hideBar() {
this.setVisibility(View.GONE);
}
private void animateAndHide(){
this.animate()
.translationY(0)
.setDuration(2000)
.alpha(0.0f)
.setListener(new AnimatorListenerAdapter() {
#Override
public void onAnimationEnd(Animator animation) {
super.onAnimationEnd(animation);
hideBar();
}
});
}
I am not sure what I am doing wrong here.
This happened with me before the view seems to be invisible because the alpha becomes very low before it becomes 0 so try another value like alpha 0.1
Have you tried setStartOffset(2000)? The offset will delay your animation, so if you want to start your animation after a specific time, use the offset method.
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 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);
}