Overlapping TransitionManager animations in android - android

I am trying to expand and collapse my view with the help of TransitionManager animation. Following is the output,
See the overlapping layout while collapsing top view. How to avoid that ? I set "detailedView" (one with icons) visibility GONE and use following code for animation,
topView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
TransitionManager.beginDelayedTransition(topView);
TransitionManager.beginDelayedTransition(bottomView);
if (detailsView.getVisibility() == View.VISIBLE) {
detailsView.setVisibility(View.GONE);
cardText.setText("Collapse Title");
} else {
detailsView.setVisibility(View.VISIBLE);
cardText.setText("Expanded Title");
}
}
});

I would build the animation differently. I would make a LinearLayout with the top cell with wrap_content, and when clicking I would do something like:
valueAnimator = ValueAnimator.ofInt(titleContainer.getHeight(),titleContainer.getHeight() + newHeight );
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
#Override
public void onAnimationUpdate(ValueAnimator animation) {
titleContainer.setHeight(animation.getAnimatedValue());
}
});
valueAnimator.setDuration(270);
valueAnimator.start();

I had the same problem.
The first argument that the TransitionManager.beginDelayedTransition() function takes must be the parent of all the views that will interact in the transition e.g:
I have the next layout:
<!-- The scene root -->
<LinearLayout
android:id="#+id/transition_container" >
<!-- First card -->
<androidx.cardview.widget.CardView
android:id="#+id/expandableCard1">
<LinearLayout
android:id="#+id/staticHeader1">
</LinearLayout>
<LinearLayout
android:id="#+id/expandableContent1">
</LinearLayout>
</androidx.cardview.widget.CardView>
<!-- Second card -->
<androidx.cardview.widget.CardView
android:id="#+id/expandableCard2">
<LinearLayout
android:id="#+id/staticHeader2">
</LinearLayout>
<LinearLayout
android:id="#+id/expandableContent2">
</LinearLayout>
</androidx.cardview.widget.CardView>
</LinearLayout>
And my code (kotlin):
// toggle
if( expandableContent1.visibility == View.GONE ){
// apply to the root scene
TransitionManager.beginDelayedTransition(transition_container )
// change the visibility of the expandable content
expandableContent1.visibility = View.VISIBLE
arrowBtn.setImageResource( R.drawable.ic_arrow_up_24)
} else {
// apply to the root scene
TransitionManager.beginDelayedTransition(transition_container )
// change the visibility of the expandable content
expandableContent1.visibility = View.GONE
arrowBtn.setImageResource( R.drawable.ic_arrow_down_24)
}

Related

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! :)

Push above view up while animating slide up another view

I have following view inside my layout
<RelativeLayout
android:id="#+id/wrapper"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true">
<LinearLayout
android:id="#+id/header"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentTop="true">
<!-- some child views here -->
</LinearLayout>
<LinearLayout
android:id="#+id/footer"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="#+id/header"
android:visibility="gone">
<!-- some other child views here -->
</LinearLayout>
</RelativeLayout>
The wrapper RelativeLayout is aligned to bottom of its parent. And initialy footer view is not displayed (View.GONE). When header view is tapped, then footer should be shown to user with slide up animation from bottom of screen and when user taps again footer should be slide down to bottom. When i start an slide up animation on footer view, it does not push header view simultaneously with animation. If i first set footer view visibility to View.INVISIBLE first and then start animation, header view is pushed up immediately (not together with animation or footer view), and footer view comes with animation.
Here is the code to call animation
footer.setVisibility(View.INVISIBLE);
Animation animation = AnimationUtils.loadAnimation(activity, R.anim.slide_up_from_bottom);
animation.setDuration(animDuration);
footer.startAnimation(animation);
footer.postDelayed(new Runnable() {
#Override
public void run()
{
footer.setVisibility(View.VISIBLE);
}
}, animDuration);
and this is the animation file content:
How can i make this animation to push header view, while footer view sliding up?
Hope i made myself clear. All i want is both views moves up/down together.
If i apply animation to wrapper view then it slides up from bottom (not from current location).
If you want your header to push along with footer animation, you can do it manually as follows
public class MainActivity extends Activity {
private LinearLayout header,footer;
private RelativeLayout wrapper;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
header = (LinearLayout) findViewById(R.id.header);
footer = (LinearLayout) findViewById(R.id.footer);
wrapper = (RelativeLayout) findViewById(R.id.wrapper);
header.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if(footer.getVisibility() == View.VISIBLE){
int footerHeight = footer.getMeasuredHeight();
float initialWrapperY = wrapper.getY();
ObjectAnimator oa=ObjectAnimator.ofFloat(wrapper, "y", initialWrapperY,initialWrapperY+footerHeight);
oa.setDuration(400);
oa.start();
oa.addListener(new AnimatorListenerAdapter() {
public void onAnimationEnd(android.animation.Animator animation) {
footer.setVisibility(View.INVISIBLE);
};
});
}
else{
final float initialWrapperY = wrapper.getY();
footer.setVisibility(View.VISIBLE);
wrapper.setY(initialWrapperY);
ViewTreeObserver vto=wrapper.getViewTreeObserver();
vto.addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
#Override
public boolean onPreDraw() {
wrapper.getViewTreeObserver().removeOnPreDrawListener(this);
final int footerHeight = footer.getMeasuredHeight();
ObjectAnimator oa=ObjectAnimator.ofFloat(wrapper, "y", initialWrapperY,(initialWrapperY-footerHeight));
oa.setDuration(400);
oa.start();
return true;
}
});
}
}
});
}
}

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.
}

Custom View and Layout Animation android

I have a layout which at start has '0dp' width but when a button is clicked it animates from Left to right and its width is increased accordingly. In this layout I am initializing a custom view. The view is initialized correctly when I place it at right or at centre but when I place it on the left it's not shown.
Here is my XML:
<RelativeLayout
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="0"
android:background="#drawable/bg">
<com.example.Wheel
android:id="#+id/wheel"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_centerVertical="true" >
</com.example.Wheel>
</RelativeLayout>
And here is what I do in java:
MenuListLeft = (RelativeLayout) findViewById(R.id.ControlLayout);
openButton.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
if (isExpandedLeft) {
isExpandedLeft = false;
MenuListLeft.startAnimation(new CollapseAnimationLTR(MenuListLeft, 0,(int)(screenWidth*1), 5));
}
else {
isExpandedLeft = true;
MenuListLeft.startAnimation(new ExpandAnimationLTR(MenuListLeft, 0,(int)(screenWidth*1), 5));
init();
}
}
});
You would be better of using weights in a combination of Relative and Linear Layout rather than just in a Relative Layout.
Here...
weight = 0 gets you no space expansion. Try setting it to 1.
In case you want to understand more on how weight works:
http://teamdroid.wordpress.com/2012/06/06/android-layout-weight-explained/
Also, for your case, wouldn't a View.Visibility GONE, VISIBLE...with animation may work better.

Categories

Resources