I've tried various solutions from this topic (see. Android: Expand/collapse animation ) and none of them really worked for me. I'm sure that the most voted ones are good and the reason that it won't work is that I don't understand something. Please tell me what i'm doing wrong. Thank you in advance :)
EDIT: The main point of my problem is, that when I click on the element 'relativeZaplon' it expands very well, yet when I want to collapse it, it does not correspond.
MainActivity
public class MainActivity extends AppCompatActivity {
private boolean isVisible = false;
private RelativeLayout mRelativeZaplon;
private RelativeLayout mRelativeToSlide;
private ExpandOrCollapse mAnimationManager;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mAnimationManager = new ExpandOrCollapse();
mRelativeZaplon = (RelativeLayout) findViewById(R.id.relativeZaplon);
mRelativeToSlide = (RelativeLayout) findViewById(R.id.relativevToSlide);
mRelativeZaplon.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (isVisible) {
mAnimationManager.collapse(mRelativeToSlide, 1000, 200);
isVisible = false;
} else if (!isVisible){
mAnimationManager.expand(mRelativeToSlide, 1000, 200);
isVisible = true;
}
}
});
}
}
Expand/Collapse Class
public class ExpandOrCollapse {
public static void expand(final View v, int duration, int targetHeight) {
int prevHeight = v.getHeight();
v.setVisibility(View.VISIBLE);
ValueAnimator valueAnimator = ValueAnimator.ofInt(prevHeight, targetHeight);
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
v.getLayoutParams().height = (int) animation.getAnimatedValue();
v.requestLayout();
}
});
valueAnimator.setInterpolator(new DecelerateInterpolator());
valueAnimator.setDuration(duration);
valueAnimator.start();
}
public static void collapse(final View v, int duration, int targetHeight) {
int prevHeight = v.getHeight();
ValueAnimator valueAnimator = ValueAnimator.ofInt(prevHeight, targetHeight);
valueAnimator.setInterpolator(new DecelerateInterpolator());
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
v.getLayoutParams().height = (int) animation.getAnimatedValue();
v.requestLayout();
}
});
valueAnimator.setInterpolator(new DecelerateInterpolator());
valueAnimator.setDuration(duration);
valueAnimator.start();
}
}
XML
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<RelativeLayout
android:background="@color/colorPrimaryDark"
android:id="@+id/relativevToSlide"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="gone">
</RelativeLayout>
<RelativeLayout
android:id="@+id/relativeZaplon"
android:background="@color/colorAccent"
android:layout_width="match_parent"
android:layout_height="20dp"
android:layout_below="@+id/relativevToSlide"
android:layout_alignParentRight="true"
android:layout_alignParentEnd="true">
</RelativeLayout>
</LinearLayout>
This is my version of the method, you don´t have to set any height, it will expand or collapse any view depending on its visibility.
public static void expand(final View v, int duration) {
final boolean expand = v.getVisibility()!=View.VISIBLE;
int prevHeight = v.getHeight();
int height = 0;
if (expand) {
int measureSpecParams = View.MeasureSpec.getSize(View.MeasureSpec.UNSPECIFIED);
v.measure(measureSpecParams, measureSpecParams);
height = v.getMeasuredHeight();
}
ValueAnimator valueAnimator = ValueAnimator.ofInt(prevHeight, height);
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
v.getLayoutParams().height = (int) animation.getAnimatedValue();
v.requestLayout();
}
});
valueAnimator.addListener(new Animator.AnimatorListener() {
@Override
public void onAnimationStart(Animator animation) {
if (expand){
v.setVisibility(View.VISIBLE);
}
}
@Override
public void onAnimationEnd(Animator animation) {
if (!expand){
v.setVisibility(View.INVISIBLE);
}
}
@Override
public void onAnimationCancel(Animator animation) {
}
@Override
public void onAnimationRepeat(Animator animation) {
}
});
valueAnimator.setInterpolator(new DecelerateInterpolator());
valueAnimator.setDuration(duration);
valueAnimator.start();
}
Just call the method like this:
expand(YOURVIEWID,500);
It is because
if (isVisible) {
mAnimationManager.collapse(mRelativeToSlide, 1000, 200);
isVisible = false;
} else if (!isVisible){
mAnimationManager.expand(mRelativeToSlide, 1000, 200);
isVisible = true;
}
collapse() and expand() do the same thing, they are both expand Animations in this case. You need to pass a different value to your collapse() method; The simple solution is
mAnimationManager.collapse(mRelativeToSlide, 1000, -200);
But there are some more issues with your coding style, for example you could just get rid of your collapse() method because calling expand two times like this would also work :
if (isVisible) {
mAnimationManager.expand(mRelativeToSlide, 1000, -200);
isVisible = false;
} else if (!isVisible){
mAnimationManager.expand(mRelativeToSlide, 1000, 200);
isVisible = true;
}
I suggest you post it on Code Review.
I'll explain the way I chose to animate layout changes.
Android has a special Animation class named ScaleAnimation
by the help of which we can smoothly expand or collapse views.
Show view by expanding diagonally:
ScaleAnimation expand = new ScaleAnimation(
0, 1.0f,
0, 1.0f,
Animation.RELATIVE_TO_PARENT, 0,
Animation.RELATIVE_TO_PARENT, 0);
expand.setDuration(250);
view.startAnimation(expand)
where the constructor used is:
ScaleAnimation(float fromX, float toX, float fromY, float toY, int pivotXType, float pivotXValue, int pivotYType, float pivotYValue)
So you can change values accordingly.
For example, the below example would animate view horizontally:
ScaleAnimation expand = new ScaleAnimation(
0, 1.1f,
1f, 1f,
Animation.RELATIVE_TO_PARENT, 0,
Animation.RELATIVE_TO_PARENT, 0);
expand.setDuration(250);
You can change fromX
,toX
, fromY
& toY
according to the need.
For example if view is shown and you have to just expand it, put fromX
and fromY
to 1.0f
, and toX
, toY
according to the need.
Now, using the same class you can create a more cool effect for showing view by expanding view a little bit extra and then shrinking it to original size. For this purpose, AnimationSet
will be used. So it would create a kind of bubble effect.
Below example is for creating bubble effect for showing the view:
AnimationSet expandAndShrink = new AnimationSet(true);
ScaleAnimation expand = new ScaleAnimation(
0, 1.1f,
0, 1.1f,
Animation.RELATIVE_TO_PARENT, 0,
Animation.RELATIVE_TO_PARENT, 0);
expand.setDuration(250);
ScaleAnimation shrink = new ScaleAnimation(
1.1f, 1f,
1.1f, 1f,
Animation.RELATIVE_TO_PARENT, 0,
Animation.RELATIVE_TO_PARENT, 0);
shrink.setStartOffset(250);
shrink.setDuration(120);
expandAndShrink.addAnimation(expand);
expandAndShrink.addAnimation(shrink);
expandAndShrink.setFillAfter(true);
expandAndShrink.setInterpolator(new AccelerateInterpolator(1.0f));
view.startAnimation(expandAndShrink);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With