Element is disappearing after animation - android

I have a button alternates its visibility when a second button is clicked. For example, on the first click it slides from the right (outside the screen) to the position defined on layout file and on the second click it slides to the right. These animations also use fade in/out.
I'm currently using this code (click listeners ommited for the sake of simplicity):
<ImageButton
android:id="#+id/unlock_button"
android:layout_width="40dp"
android:layout_height="40dp"
android:layout_gravity="right"
android:layout_marginRight="16dp"
android:layout_marginTop="16dp"
android:background="#drawable/ic_lock_red"
android:visibility="gone" />
Java
//Hiding
mUnlockButton.animate()
.alpha(0)
.setDuration(600)
.translationX(50)
.setInterpolator(new AccelerateInterpolator())
.setListener(new AnimatorListenerAdapter() {
#Override
public void onAnimationEnd(Animator animation) {
mUnlockButton.setVisibility(View.GONE);
}
})
.start();
//Show
mUnlockButton.setAlpha(0f);
mUnlockButton.setTranslationX(50);
mUnlockButton.setVisibility(View.VISIBLE);
mUnlockButton.animate()
.alpha(1.0f)
.setDuration(600)
.translationX(-50)
.setInterpolator(new AccelerateInterpolator())
.start();
After the third click (show, hide, then show again) the animation is run but the button disappears when the animation ends.
Why?

Related

Why won't the ImageView move?

I'm making a mobile game, and I want to make the ImageView move horizontally when I press the left and right buttons.
I've tried setX() and And Object Animator, but it still won't move
Left and right buttons.
btnRight.setOnClickListener(new View.OnClickListener() {
public void onClick(View right) {
x++;
ObjectAnimator d = ObjectAnimator.ofFloat(first, "translationX", x);
d.setDuration(2000);
d.start();
}
});
btnLeft.setOnClickListener(new View.OnClickListener() {
public void onClick(View left) {
x--;
ObjectAnimator animation = ObjectAnimator.ofFloat(first, "translationX", x);
animation.setDuration(2000);
animation.start();
}
});
Imageview XML
<ImageView
android:id="#+id/first"
android:layout_width="100dp"
android:layout_height="100dp"
android:layout_marginStart="8dp"
android:layout_marginLeft="8dp"
android:layout_marginTop="160dp"
android:layout_marginEnd="166dp"
android:layout_marginRight="168dp"
android:layout_marginBottom="471dp"
android:adjustViewBounds="true"
android:background="#00FFFFFF"
android:contentDescription="#android:string/untitled"
android:scaleType="fitXY"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.963"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="1.0"
app:srcCompat="#android:color/background_light"
tools:srcCompat="#android:color/background_light" />
When I used setX, the object would always move left if I pressed both buttons,and would stay there. When I use ObjectAnimator, it just stays there.
ObjectAnimator should be OK.
I tried your code and it works, but the translate distance is really small, I have to click the button many times to see an obvious movement.
You can change the x++ to x += 10 or even x += 50 to check if it works actually.

Animate visibility of a view from gone to visible with animation

I have a view that is invisible by default(Just for the first time).
Now I need to switch the visibility to VISIBLE with this animation:
if (myView.getVisibility() == View.INVISIBLE) {
myView.setVisibility(View.VISIBLE);
myView.animate().translationY(0);
}
(Like the SnackBar default animation)
But this isn't working. It will turn visible with default animation
Is there any simple way that I could achieve this?
Note
I'm animating my view to dismiss, like this:
myView.animate().translationY(myView.getHeight());
You can do this using XML animation.
Create a slide-up animation XML using set and alpha and put this XML into your resource anim folder.
slide_up.xml
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android" >
<translate
android:duration="500"
android:fromYDelta="100%"
android:toYDelta="0" />
</set>
USE:
Use AnimationUtils.loadAnimation() to load animation from XML and set and start animation using .startAnimation() method.
Here is an example:
ImageView imageView = (ImageView) findViewById(R.id.imageView);
// slide-up animation
Animation slideUp = AnimationUtils.loadAnimation(this, R.anim.slide_up);
if (imageView.getVisibility() == View.INVISIBLE) {
imageView.setVisibility(View.VISIBLE);
imageView.startAnimation(slideUp);
}
Hope this will help~
Add animations using ConstraintLayout
Just add below code above the views whose visibility is updated:
TransitionManager.beginDelayedTransition(constraintLayout)
Note:
ConstraintLayout will only perform animation on its direct children since it only knows when you change layout parameters and constraints on the children that it handles.
ConstraintLayout only animates layout related changes.
For more see this post https://robinhood.engineering/beautiful-animations-using-android-constraintlayout-eee5b72ecae3
This is the best way to animate views visibility :
private void viewGoneAnimator(final View view) {
view.animate()
.alpha(0f)
.setDuration(500)
.setListener(new AnimatorListenerAdapter() {
#Override
public void onAnimationEnd(Animator animation) {
view.setVisibility(View.GONE);
}
});
}
private void viewVisibleAnimator(final View view) {
view.animate()
.alpha(1f)
.setDuration(500)
.setListener(new AnimatorListenerAdapter() {
#Override
public void onAnimationEnd(Animator animation) {
view.setVisibility(View.VISIBLE);
}
});
}
And then call this method wherever you wanted to make a view visible or gone and give the intended view to methods as the parameter.
Just You need to add android:animateLayoutChanges="true" to your layout.
When I set visibility gone to linear_container, linear_bottom will animate from bottom to up and take place of "linear_container".
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:animateLayoutChanges="true"
android:orientation="vertical"
android:layout_height="match_parent">
<android.support.design.widget.AppBarLayout
android:id="#+id/layoutTop"
android:layout_width="match_parent"
android:layout_height="wrap_content">
</android.support.design.widget.AppBarLayout>
<LinearLayout
android:id="#+id/linear_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
</LinearLayout>
<LinearLayout
android:id="#+id/linear_bottom"
android:layout_width="match_parent"
android:layout_height="wrap_content"
</LinearLayout>
</LinearLayout>
Based on this answer:
with this methods, I can set the visibility of my view to VISIBLE with a slideUp animation(Like snackbar animation):
int getScreenHeight() {
DisplayMetrics displaymetrics = new DisplayMetrics();
activity.getWindowManager().getDefaultDisplay().getMetrics(displaymetrics);
return displaymetrics.heightPixels;
}
public void animateOnScreen(View view) {
final int screenHeight = getScreenHeight();
ObjectAnimator animator = ObjectAnimator.ofFloat(view, "y", screenHeight, (screenHeight * 0.8F));
animator.setInterpolator(new DecelerateInterpolator());
animator.start();
}
Then I can use it like this:
if (myView.getVisibility() == View.INVISIBLE) {
myView.setVisibility(View.VISIBLE);
animateOnScreen(myView);
}

Android show hide LinearLayout

Working on this app in which I'am trying to manage show/hide animation on a LinearLayout.
The problem I have is, on toggling the visibility it seems to hide any children the second time..
To make my story more clear here a screenshot:
on start - hidden
1st click - shows linear layout with children (textview)
2th click - hids linear layout again
3th click - shows linear layout but no children (textview)
Layoutfile:
<TextView
android:id="#+id/tv_lecture"
style="#style/Text.Primary.Light"
android:singleLine="true" />
<LinearLayout
android:visibility="gone"
android:id="#+id/grades_container"
style="#style/Container.Vertical">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="10"/>
</LinearLayout>
code:
private void animate(final LinearLayout gradesContainer) {
if (gradesContainer.getVisibility() == View.GONE) {
gradesContainer.animate()
.translationY(gradesContainer.getHeight())
.alpha(1.0f)
.setListener(new AnimatorListenerAdapter() {
#Override
public void onAnimationStart(Animator animation) {
super.onAnimationStart(animation);
gradesContainer.setVisibility(View.VISIBLE);
gradesContainer.setAlpha(0.0f);
}
});
}
else {
gradesContainer.animate()
.translationY(0)
.alpha(0.0f)
.setListener(new AnimatorListenerAdapter() {
#Override
public void onAnimationEnd(Animator animation) {
super.onAnimationEnd(animation);
gradesContainer.setVisibility(View.GONE);
}
});
}
}
On lecture TextView click will trigger the method: animate()
So whats the problem here? Can't figure it out thats why I'am asking you guys. Thanks!
If you are aiming for just the simple animation. You can just go on ahead and use animateLayoutChanges in your xml.
Cheers! :)

Shared elements and content transitions in Fragments

I have the following problem:
I'm trying to transition from Fragment A to Fragment B. There is a shared element between these fragments in the form of a Button and some other View's (see layout).
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:flipper="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.mypackage.view.IndicatorViewFlipper
android:transitionGroup="true"
android:id="#+id/intro_viewflipper"
android:layout_width="match_parent"
android:layout_height="match_parent"
flipper:indicatorColor="#color/white"
flipper:indicatorMargin="4dp"
flipper:indicatorRadius="4dp"
flipper:indicatorBarMargin="104dp"/>
<Button
android:id="#+id/account_create_btn"
style="?android:attr/borderlessButtonStyle"
android:textColor="#color/white"
android:layout_width="match_parent"
android:layout_height="#dimen/button_standard_height"
android:layout_above="#+id/txt_already_account"
android:background="#drawable/button_yellow_selector"
android:transitionName="create_account"
android:text="#string/account_create_btn"
android:textSize="24sp"
android:textAllCaps="false" />
<TextView
android:id="#+id/txt_already_account"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:layout_above="#+id/account_login_btn"
android:layout_marginTop="24dp"
android:text="#string/account_welcome_already_account"/>
<Button
android:id="#+id/account_login_btn"
style="?android:attr/borderlessButtonStyle"
android:layout_width="match_parent"
android:layout_height="#dimen/button_standard_height"
android:layout_marginTop="8dp"
android:layout_alignParentBottom="true"
android:transitionName="login"
android:background="#drawable/button_blue_selector"
android:textColor="#color/white"
android:textSize="24sp"
android:textAllCaps="false"
android:text="#string/account_create_login_btn"/>
</RelativeLayout>
What I'm trying to do is to let all the content in Fragment except for the shared element, transition (slide to the left) and let all the content form Fragment B except for the shared element slide in from the right. During this content transition I want the shared element to remain in its original position until the content transitions are done, and then let it slide to its new position in Fragment B.
This last behaviour is where it goes wrong: once I start the exit transition in Fragment A the shared element disappears and slides in from the right with the content transition of Fragment B. The behaviour of the shared element is correct if I don't add any exit/enter transitions.
The code (in Fragment A):
Fragment fragment = MyFragment.newInstance();
FragmentTransaction fragmentTransaction = getFragmentManager().beginTransaction();
fragmentTransaction.hide(this);
fragmentTransaction.add(R.id.frame_container, fragment, fragment.getClass().getSimpleName());
fragmentTransaction.addSharedElement(sharedElement, sharedElementTag);
Transition sharedElementTransaction = TransitionInflater.from(getActivity()).inflateTransition(android.R.transition.move);
sharedElementTransaction.setStartDelay(400);
fragment.setSharedElementEnterTransition(sharedElementTransaction);
setExitTransition(new Slide(Gravity.LEFT).setDuration(200));
fragment.setEnterTransition(new Slide(Gravity.RIGHT).setDuration(200));
Can anyone help me get the desired behaviour?
Update:
I've made a work around that almost does what I want using animate() on my views to slide/fade them and on completion of this animation trigger the shared element transaction:
Transition sharedElementTransition = TransitionInflater.from(getActivity()).inflateTransition(android.R.transition.move);
sharedElementTransition.setStartDelay(400);
fragment.setSharedElementEnterTransition(sharedElementTransition);
setSharedElementReturnTransition(sharedElementTransition);
mLoginBtn.animate()
.x(-mLoginBtn.getWidth())
.setDuration(400)
.start();
viewFlipper.animate()
.x(-viewFlipper.getWidth())
.setDuration(400)
.setListener(new AnimatorListenerAdapter() {
#Override
public void onAnimationEnd(Animator animation) {
super.onAnimationEnd(animation);
transaction.commit();
}
})
.start();
fragment.setEnterSharedElementCallback(new SharedElementCallback() {
#Override
public void onSharedElementStart(List<String> sharedElementNames, List<View> sharedElements, List<View> sharedElementSnapshots) {
super.onSharedElementStart(sharedElementNames, sharedElements, sharedElementSnapshots);
viewFlipper.animate()
.x(0)
.setDuration(400)
.setListener(null)
.start();
mLoginBtn.animate()
.x(0)
.setDuration(400)
.start();
});
The problem with this solution is that I can't slide in the Views of the called Fragment so there I now just fade in the Views.
If all you need is to animate the fragments while the button stays still, you can move the button to the activity and animate the fragment.

Translate a View from One Layout to Another with Translate Animation

I am new in Android animation and my requirement is to translate a view from one layout to layout in a single xml file on click of that view.
Scenario:
Suppose I click a button, present on the top of the header in a xml file,and it should move/translate downwards (it should give an impact that it lies on the other layout downwards to header), and also I want that when the user clicks on the same again, it should now move to its original position.
Here I am explaining with my xml file:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#drawable/app_bg"
android:orientation="vertical" >
<RelativeLayout
android:id="#+id/top"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:background="#drawable/header"
android:paddingLeft="10dp"
android:paddingRight="10dp" >
<Button
android:id="#+id/btnSearchHeader"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_centerInParent="true"
android:background="#drawable/search_icon" />
</RelativeLayout>
<RelativeLayout
android:id="#+id/bottom"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="#color/app_transparent"
android:paddingLeft="10dp"
android:paddingRight="10dp"
android:layout_marginTop="10dp"
android:visibility="visible" >
<Button
android:id="#+id/btnMenu"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_centerVertical="true"
android:layout_marginRight="5dp"
android:text="ABC" />
<Button
android:id="#+id/btnSearchSelected"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_toRightOf="#+id/btnMenu"
android:text="CDE" />
</RelativeLayout>
</LinearLayout>
MORE PRECISE REQUIREMENT SPECIFICATION (Kindly read carefully:)
Here I have two sub inner layouts:-
Top Layout - id-> top
Bottom Layout- id -> bottom
Now a view (Button -> btnSearchHeader) is lying in my top layout and I want to animate the same to the bottom layout (it should give an impact that it is translated with a translate animation to the bottom layout) on click of that button and when the user clicks on that button, it should again translate back to its original position with a translate animation .. i.e it should show back in the top layout
I have no idea how to give these impacts using translate animations, however i just have a basic translate animation knowledge which is insufficient for me to work upon my requirement.
Any type of related help is appreciable.
Thanks
Have you tried something simple like the following?
final int topHeight = findViewById(R.id.top).getHeight();
final int bottomHeight = findViewById(R.id.bottom).getHeight();
final View button = findViewById(R.id.btnSearchHeader);
final ObjectAnimator moveDownAnim = ObjectAnimator.ofFloat(button, "translationY", 0.F, topHeight + bottomHeight / 2 - button.getHeight() / 2);
final ObjectAnimator moveUpAnim = ObjectAnimator.ofFloat(button, "translationY", topHeight + bottomHeight / 2 - button.getHeight() / 2, 0.F);
button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (0.F == v.getTranslationY())
moveDownAnim.start();
else
moveUpAnim.start();
}
});
If you actually need the button view to change parents, you can use AnimatorListener to achieve this at the end of each animation. Something like:
moveDownAnim.addListener(new Animator.AnimatorListener() {
#Override
public void onAnimationEnd(Animator animation) {
((ViewGroup)findViewById(R.id.top)).removeView(button);
((ViewGroup)findViewById(R.id.bottom)).addView(button);
((RelativeLayout)button.getLayoutParams()).addRule(RelativeLayout.CENTER_IN_PARENT);
button.setTranslationY(0.F); // Since it is now positioned in the new layout, no need for translation.
}
#Override
public void onAnimationCancel(Animator animation) { /* NOP */ }
#Override
public void onAnimationRepeat(Animator animation) { /* NOP */ }
#Override
public void onAnimationStart(Animator animation) { /* NOP */ }
});
(And analogous listener for the moveUpAnim.)
However, I doubt you need to actually do this to achieve the visual effect you want. But if you do this part, you will probably also need to set a fixed height for your top view as opposed to wrap_content. (Otherwise, if a layout pass happens while the button has been moved to the bottom view, the top layout's height might go to 0 if there's nothing else in it.) Easiest would be to just do this directly in the xml layout file. However, if you want to "do it on the fly", you can change the layout's height in the onAnimationEnd() method using something like:
#Override
public void onAnimationEnd(Animator animation) {
final ViewGroup topLayout = findViewById(R.id.top);
topLayout.getLayoutParams().height = topLayout.getHeight(); // Keep it the same height...
topLayout.removeView(button);
((ViewGroup)findViewById(R.id.bottom)).addView(button);
((RelativeLayout)button.getLayoutParams()).addRule(RelativeLayout.CENTER_IN_PARENT);
button.setTranslationY(0.F); // Since it is now positioned in the new layout, no need for translation.
}

Categories

Resources