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}
}
}
}
})
Related
I used Motion Layout for Collapse Layout. Motion layout working perfect as I need but I want to set motion layout animation based on data fit too the screen.
Like if data fit in screen then no need to animation. If data out of the screen then show animation.
Finally I got solution:
motionLogin?.enableTransition(R.id.transitionLogin, false)
constraintLayout.viewTreeObserver.addOnGlobalLayoutListener(object :
ViewTreeObserver.OnGlobalLayoutListener {
override fun onGlobalLayout() {
// If the scrollView can scroll, disable the accept menu item button
if (constraintLayout.canScrollVertically(1) || constraintLayout.canScrollVertically(
-1
)
) {
motionLogin?.enableTransition(R.id.transitionLogin, true)
}
// Remove itself after onGlobalLayout is first called or else it would be called about a million times per second
constraintLayout.viewTreeObserver.removeOnGlobalLayoutListener(this)
}
})
For Java version:
public static void enableDisableTransition(MotionLayout motionLayout, RecyclerView recyclerView){
motionLayout.enableTransition(R.id.transition, false);
recyclerView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
if (recyclerView.canScrollVertically(1) || recyclerView.canScrollVertically(-1 )
) {
motionLayout.enableTransition(R.id.transition, true);
}
recyclerView.getViewTreeObserver().removeOnGlobalLayoutListener(this);
}
});
}
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.
HI i have the below animation for a view below:
val duration = 2000L
val visible = 1.0f
imageAVater.apply {
animate().translationYBy(-100f).alpha(visible).setDuration(duration).setListener(object : AnimatorListenerAdapter(){
override fun onAnimationEnd(animation: Animator?) {
visibility = View.VISIBLE
}
})
}
i want it to move from slightly off-position and into position and to also reveal itself by setting the alpha .
SO far neither works.
ALl the code above does is move the image from current default position on my layout(lets say i positioned it in xml along the Y axis position 200) and then it moves from position 200 to position 100 and also the alpha does not work, the item is visible all the time despite it being set to View.Gone in my xml
android:visibility="gone"
How can i set a start and end Y axis value for this translation animation and how can i get the alpha to work so that the view appears from hidden/gone?
i want it to start at 200 y and have it transition to 100 y and to also reveal itself from being hidden/gone to being shown at the same time as the transition
you need to specify starting values for y and alpha. EG.
imageAVater.apply {
alpha = 0f
animate().alpha(1f).setDuration(2000).start()
}
leave the view's visibility always to visible. You can not animate a view that is 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();
As I've a master in MS Paint, I will just upload a picture selfdescripting what I'm trying to achieve.
I've searched, but I'm not really sure what do I've to search. I've found something called Animations. I managed to rotate, fade, etc an element from a View (with this great tutorial http://www.vogella.com/articles/AndroidAnimation/article.html)
But this is a bit limited for what I'm trying to achieve, and now, I'm stuck, because I don't know how is this really called in android development. Tried words like "scrollup layouts" but I didn't get any better results.
Can you give me some tips?
Thank you.
You can see a live example, with this app: https://play.google.com/store/apps/details?id=alexcrusher.just6weeks
Sincerely,
Sergi
Use something like this as your layout (Use Linear, Relative or other layout if you wish):
<LinearLayout
android:id="#+id/lty_parent">
<LinearLayout
android:id="#+id/lyt_first" />
<LinearLayout
android:id="#+id/lyt_second"/>
</LinearLayout>
And then in an onClick method on whatever you want to use to control it, set the Visibility between Visible and Gone.
public void buttonClickListener(){
((Button) findViewById(R.id.your_button))
.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
if (lyt_second.getVisibility() == View.GONE) {
lyt_second.setVisibility(View.VISIBILE);
}
else {
lyt_second.setVisibility(View.GONE);
}
});
Which is fine if you just want a simple appear/disappear with nothing fancy. Things get a little bit more complicated if you want to animate it, as you need to play around with negative margins in order to make it appear to grow and shrink, like so:
We use the same onClick method that we did before, but this time when we click it starts up a custom SlideAnimation for the hidden/visible view.
#Override
public void onClick(View v) {
SlideAnimation slideAnim = new SlideAnimation(lyt_second, time);
lyt_second.startAnimation(slideAnim);
}
The implementation of the SlideAnimation is based on a general Animation class, which we extend and then Override the transformation.
public SlideAnimation(View view, int duration) {
//Set the duration of the animation to the int we passed in
setDuration(duration);
//Set the view to be animated to the view we passed in
viewToBeAnimated = view;
//Get the Margin Parameters for the view so we can edit them
viewMarginParams = (MarginLayoutParams) view.getLayoutParams();
//If the view is VISIBLE, hide it after. If it's GONE, show it before we start.
hideAfter = (view.getVisibility() == View.VISIBLE);
//First off, start the margin at the bottom margin we've already set.
//You need your layout to have a negative margin for this to work correctly.
marginStart = viewMarginParams.bottomMargin;
//Decide if we're expanding or collapsing
if (marginStart == 0){
marginEnd = 0 - view.getHeight();
}
else {
marginEnd = 0;
}
//Make sure the view is visible for our animation
view.setVisibility(View.VISIBLE);
}
#Override
protected void applyTransformation(float interpolatedTime, Transformation t) {
super.applyTransformation(interpolatedTime, t);
if (interpolatedTime < 1.0f) {
// Setting the new bottom margin to the start of the margin
// plus the inbetween bits
viewMarginParams.bottomMargin = marginStart
+ (int) ((marginEnd - marginStart) * interpolatedTime);
// Request the layout as it happens so we can see it redrawing
viewToBeAnimated.requestLayout();
// Make sure we have finished before we mess about with the rest of it
} else if (!alreadyFinished) {
viewMarginParams.bottomMargin = marginEnd;
viewToBeAnimated.requestLayout();
if (hideAfter) {
viewToBeAnimated.setVisibility(View.GONE);
}
alreadyFinished = true;
}
hideAfter = false;
}
}
EDIT: If anyone had used this code before and found that if you click on the button that starts the animation more than once before the animation was finished, it would mess up the animation from then on, causing it to always hide the view after the animation finished. I missed the reset of the hideAfter boolean near the bottom of the code, added it now.
you can do this manually by using setvisibility feature on the event onClick()
or
use this
dynamically adding two views one below other