I have a bottomBar that i would like to expand. I think i know how to do it with animations.
But according to What is the difference between an Animator and an Animation?
If i use old animations. Then the buttons would not be relocated. Only visually.
How could i achieve this with Animators.
What i am trying to achieve
So could someone nudge me in the right direction.
This solved my problem.
public static ValueAnimator slideAnimator(int start, int end, final View view, int duration) {
ValueAnimator animator = ValueAnimator.ofInt(start, end);
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
#Override
public void onAnimationUpdate(ValueAnimator valueAnimator) {
int val = (Integer) valueAnimator.getAnimatedValue();
ViewGroup.LayoutParams layoutParams = view.getLayoutParams();
layoutParams.height = val;
view.setLayoutParams(layoutParams);
}
});
animator.setDuration(duration);
return animator;
}
Credit to: Android property animation: how to increase view height?
Well, that can be done with a "one-liner":
TransitionManager.beginDelayedTransition(viewGroup);
ViewGroup.LayoutParams layoutParams = view.getLayoutParams();
layoutParams.height = endValue;
view.invalidate();
Related
I have a DialogFragment I'm trying to animate so that when onClick()'ed a confirmation appears underneath.
I have tried using setVisibility() with an Animator, but that isn't what I'm looking for. I want the layout to Slide In with the animation not appear after, or conversely disappear before.
I have been playing with some code from Github here https://github.com/ThePreviousOne/Example
`
handle.setOnClickListener( new View.OnClickListener() {
float startHeight;
#Override
public void onClick(View v) {
startHeight = slideDownView.getHeight();
// Adjust the slide down height immediately with touch movements.
if (down) {
LayoutParams params = slideDownView.getLayoutParams();
params.height = (int) (startHeight - 300);
slideDownView.setLayoutParams(params);
down = false;
} else {
LayoutParams params = slideDownView.getLayoutParams();
params.height = (int) (startHeight + 300);
slideDownView.setLayoutParams(params);
down = true;
}
}
});
This works but I dont know how to connect the new code to an animator so I can control the speed the fragment resizes at
You can define a custom animator that updates the height property at each frame of the animation. For example:
int startHeight = slideDownView.getHeight();
// Note that you should not hardcode "300" as that will be different pixel values on
// different devices - get the value from a dimen resource or scale by the
// device density
int endHeight = startHeight - getDistanceToAnimate();
// Create a simple int animator that animates between the starting and ending height
ValueAnimator animator = ValueAnimator.ofInt(startHeight, endHeight);
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
#Override
public void onAnimationUpdate(ValueAnimator valueAnimator) {
// On each frame, update the view height
int value = (Integer) valueAnimator.getAnimatedValue();
ViewGroup.LayoutParams layoutParams = view.getLayoutParams();
layoutParams.height = value;
view.setLayoutParams(layoutParams);
}
#Override
public void onAnimationEnd(Animator animation) {
// Once the animation finishes, you might have to update the view's final
// height and / or its `layout_height` attribute.
}
});
animator.setDuration(getAnimationTime());
animator.start();
Hope that helps!
I created a RecyclerView which I want to animate by clicking on the CardView inside it. I want to apply this animation of material design which resize the selected item and push up the item below and push down the item above :
I tried with this code but it just collapses and expands without pushing the item below :
private void expandCardView()
{
mCardViewContent.setVisibility(View.VISIBLE);
final int widthSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
final int heightSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
mCardViewContent.measure(widthSpec, heightSpec);
ValueAnimator mAnimator = slideAnimator(0, mCardViewContent.getMeasuredHeight());
mAnimator.start();
}
private void collapseCardView ()
{
int finalHeight = mCardViewContent.getHeight();
ValueAnimator mAnimator = slideAnimator(finalHeight, 0);
mAnimator.addListener(new AnimatorListenerAdapter()
{
#Override
public void onAnimationEnd(Animator animator)
{
mCardViewContent.setVisibility(View.GONE);
}
});
mAnimator.start();
}
private ValueAnimator slideAnimator(int start, int end)
{
ValueAnimator animator = ValueAnimator.ofInt(start, end);
animator.addUpdateListener(valueAnimator->
{
int value = (Integer) valueAnimator.getAnimatedValue();
ViewGroup.LayoutParams layoutParams = mCardViewContent.getLayoutParams();
layoutParams.height = value;
mCardViewContent.setLayoutParams(layoutParams);
});
return animator;
}
I had faced exactly same problem in my few projects and I have found a great solution at stackoverflow, which works like charm!
https://stackoverflow.com/a/13381228/6569739
You can make an invisible RelativeLayout in each RecyclerView element, which will hold all the data You want the user to see when expaned.
Then simply call expand(View v) on specific layout to expand it.
For now that is the best and most reliable way to make this kind of animation I've found so far!
I'm trying to create an animation that expands a View from top to bottom.
Like this:
I can't use a ScaleAnimation with pivotY set to 0 because this stretches the Nine-Patch like a normal Bitmap. I need to modify the height of my View.
My current solution: (test is the View reference)
ValueAnimator anim = ValueAnimator.ofInt(test.getMeasuredHeight(), 800);
anim.setInterpolator(new FastOutSlowInInterpolator());
anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
#Override
public void onAnimationUpdate(ValueAnimator animation) {
ViewGroup.LayoutParams params = test.getLayoutParams();
params.height = (int) animation.getAnimatedValue();
test.setLayoutParams(params);
}
});
anim.setDuration(250).start();
This works perfectly, but it expands the view to both sides:
Does anyone know a way to create such animation? Any help is appreciated.
A solution is to keep your implementation but limit the expansion to bottom by having an element above that won't let your view grow up:
Example:
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<FrameLayout
...
android:layout_height="100dp"/> //assuming your view starts 100dps from top
<YourView
...
.../>
</LinearLayout>
Since your container is a LinearLayout and the first View(FrameLayout) is 100dp height and above the view you wish to expand, it won't expand it's Height up because it can't overlap an element of the same hierarchy, so it will expand down
It also works if you use RelativeLayout by adding android:below="#id/framelayout_id" to YourView which will also guarantee that YourView doesn't expand up
Add an extra variable that holds initial position on Y axis.
expands top
public void expandTop(final View test) {
final float bottomAnchor = test.getY() + test.getHeight();
final ValueAnimator anim = ValueAnimator.ofInt(test.getMeasuredHeight(), 800);
anim.setInterpolator(new FastOutSlowInInterpolator());
anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
#Override
public void onAnimationUpdate(ValueAnimator animation) {
ViewGroup.LayoutParams params = test.getLayoutParams();
params.height = (int) animation.getAnimatedValue();
test.setY(bottomAnchor - (int) animation.getAnimatedValue());
test.setLayoutParams(params);
}
});
anim.setDuration(2500).start();
}
expandBottom
public void expandBottom(final View test) {
final float topAnchor = test.getY();
final ValueAnimator anim = ValueAnimator.ofInt(test.getMeasuredHeight(), 800);
anim.setInterpolator(new FastOutSlowInInterpolator());
anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
#Override
public void onAnimationUpdate(ValueAnimator animation) {
ViewGroup.LayoutParams params = test.getLayoutParams();
params.height = (int) animation.getAnimatedValue();
test.setY(topAnchor);
test.setLayoutParams(params);
}
});
anim.setDuration(2500).start();
}
I use this code for animate view in android its work perfect
problem when I set margin to zero or margin less the current margin its doesn't animate
the code
int margin = 100;
ValueAnimator varl = ValueAnimator.ofInt(margin);
varl.setDuration(200);
varl.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
#Override
public void onAnimationUpdate(ValueAnimator animation) {
RelativeLayout.LayoutParams lp = (RelativeLayout.LayoutParams) myView.getLayoutParams();
lp.setMargins((Integer) animation.getAnimatedValue(), 0, 0, 0);
myView.setLayoutParams(lp);
}
});
varl.start();
Now when I set margin to 100 it animates, but when I want to set it to zero its set margin without animation
int margin = 0;
ValueAnimator varl = ValueAnimator.ofInt(margin);
varl.setDuration(200);
varl.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
#Override
public void onAnimationUpdate(ValueAnimator animation) {
RelativeLayout.LayoutParams lp = (RelativeLayout.LayoutParams) myView.getLayoutParams();
lp.setMargins((Integer) animation.getAnimatedValue(), 0, 0, 0);
myView.setLayoutParams(lp);
}
});
varl.start();
The problem is that you didn't use the ValueAnimator.ofInt(int... values); correctly: you should explicitly tell the animator from which to which value it should animate. So, for example, you should animate from the current value to the wanted value. If your previous value, was, for example, 50, then the statement should be like this:
ValueAnimator varl = ValueAnimator.ofInt(50, margin);
You can use my library for that:
ViewPropertyObjectAnimator.animate(myView).leftMargin(100).setDuration(200).start();
Ok, so i checked out
http://android-developers.blogspot.com/2011/02/animation-in-honeycomb.html
He says you can animate the property of an object in a given time. And i tried moving around objects and it looks fine. I encountered a problem when i went changing the width of a LinearLayout. I got this:
10-26 14:51:27.190: E/PropertyValuesHolder(12681): Couldn't find setter/getter for property width with value type float
Then i tried extending LinearLayout, with "myWidth"
public void setMyWidth(int myWidth) {
LinearLayout.LayoutParams params = (LayoutParams) getLayoutParams();
params.weight = myWidth;
setLayoutParams(params);
requestLayout();
this.myWidth = myWidth;
}
No luck. Then i tried changing LayoutParams.width, turns out width and height are the only public properties in java history, and ObjectAnimator needs getter and setter. No luck.
I'm embarassed to say i tried extending LayoutParams too... with no luck ofc.
Anybody succeded doing such a thing? I used old android.view.animation and i got what i wanted, but i'm curious for the future.
In situations where there isn't a simple property getter/setter you should use ValueAnimator and perform the animation manually.
Assuming:
v is the view you're animating
END_WIDTH is the target width of the view in pixels.
DURATION is the desired length of the animation in milliseconds.
Your code should look something like this:
ValueAnimator anim = ValueAnimator.ofInt(v.getMeasuredWidth(), END_WIDTH);
anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
#Override
public void onAnimationUpdate(ValueAnimator valueAnimator) {
int val = (Integer) valueAnimator.getAnimatedValue();
ViewGroup.LayoutParams layoutParams = v.getLayoutParams();
layoutParams.width = val;
v.setLayoutParams(layoutParams);
}
});
anim.setDuration(DURATION);
anim.start();
For what it's worth this works. After you change the width on the layout params you have to reset the layout params object.
private class WidthEvaluator extends IntEvaluator {
private View v;
public WidthEvaluator(View v) {
this.v = v;
}
#Override
public Object evaluate(float fraction, Object startValue, Object endValue) {
int num = (Integer)super.evaluate(fraction, startValue, endValue);
ViewGroup.LayoutParams params = v.getLayoutParams();
params.width = num;
v.setLayoutParams(params);
return num;
}
}
// your client code
ValueAnimator.ofObject(new WidthEvaluator(box), box.getWidth(), v.getWidth()).start();
I've created a small library ViewPropertyObjectAnimator that can do that in a very simple way (and uses a similar approach to this proposed by Tomer Weller).
You could achieve this animation with (assuming the mLinearLayout is the animated View and mEndWidth is the end value of the View's width):
ViewPropertyObjectAnimator.animate(mLinearLayout).width(mEndWidth).start();
You have made a mistake
params.weight = myWidth;
I think it is params.width not params.weight
I think a better way to accomplish this would be to use View's scaleX and scaleY property which are defined all the way down in View class, so it would be valid with practically any view or layout.
For example, consider this
ObjectAnimator objectAnimator=ObjectAnimator.ofFloat(MyLinearLayout,"scaleX",0f,1f);
objectAnimator.setDuration(300);
objectAnimator.start();
It works.