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!
Related
I want to animate my button that reveal from left offset of button to right of that. What I want is linear reveal animation instead of circular reveal animation.
Please help me. Thanks.
Update
I want two method that show and hide view based on linear reveal animation.
try below code for linear reveal effect -
public class ViewAnimationUtils {
public static AnimatorSet createLinearReveal(final View viewToReveal, final int offsetWidth, final int offsetHeight, final int duration) {
viewToReveal.clearAnimation();
final int targetWidth = viewToReveal.getMeasuredWidth();
final int targetHeight = viewToReveal.getMeasuredHeight();
viewToReveal.getLayoutParams().height = offsetHeight;
viewToReveal.requestLayout();
final ValueAnimator heightAnimator = ValueAnimator
.ofInt(offsetHeight, targetHeight)
.setDuration(duration);
heightAnimator.addUpdateListener(animation -> {
viewToReveal.getLayoutParams().height = (int) animation.getAnimatedValue();
viewToReveal.requestLayout();
});
final ValueAnimator widthAnimator = ValueAnimator
.ofInt(offsetWidth, targetWidth)
.setDuration(duration);
widthAnimator.addUpdateListener(animation -> {
viewToReveal.getLayoutParams().width = (int) animation.getAnimatedValue();
viewToReveal.requestLayout();
});
final AnimatorSet set = new AnimatorSet();
set.playSequentially(widthAnimator, heightAnimator);
set.setInterpolator(new AccelerateInterpolator());
return set;
}
}
after adding this class just pass your view to animate and offset values to the createLinearReveal method.
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 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();
I need to implement this things, a height of item in ListView will be reduced slowly, when its height reduce to 0, it's gone. On this process, the remain views that below the item, should move up slowly.
At First, I use the ObjectAnimator to change the 'scaleY', but the size of item occupy was not changed, when Animator ends, ListView refresh, the empty rectangle was gone.
ObjectAnimator oa = ObjectAnimator.ofFloat(itemView, 'scaleY', 1f, 0f);
And I found another way to do this, I write a Runnable to change the height of the item, but there are some child view in my item, like a ImageView, with the height changing, the ImageView changing too, I think this is not look well.
LayoutParams lp = itemView.getLayoutParams();
lp.height = newHeight;
itemView.setLayoutParams(lp);
At last, I found third way to do, change the 'bottom' value of the item, yes, It looks like a window with reducing height, but height not changed, the remain views that below the item didn't move until Runnable ends and ListView refresh.
itemView.setBottom(itemView.getTop() + newHeight);
How to solve this?
I do something similar to this and work fine:
public void collapse(final View v, final int toHeight, final int toWidth) {
final int initialHeight = v.getMeasuredHeight();
Animation a = new Animation() {
#Override
protected void applyTransformation(float interpolatedTime, Transformation t) {
v.getLayoutParams().height = (int) (toHeight * interpolatedTime);
v.getLayoutParams().width = (int) (toWidth * interpolatedTime);
v.requestLayout();
}
#Override
public boolean willChangeBounds() {
return true;
}
};
// 1dp/ms
a.setDuration(ANIMATION_DURATION);
a.setInterpolator(new AccelerateInterpolator());
v.startAnimation(a);
}
the height set in the layout can not be fixed (put wrap_content). Hope it help you!!
Background
It's possible to change the background of the actionbar, and even animate between two colors, as such:
public static void animateBetweenColors(final ActionBar actionBar, final int colorFrom, final int colorTo,
final int durationInMs) {
final ValueAnimator colorAnimation = ValueAnimator.ofObject(new ArgbEvaluator(), colorFrom, colorTo);
colorAnimation.addUpdateListener(new AnimatorUpdateListener() {
ColorDrawable colorDrawable = new ColorDrawable(colorFrom);
#Override
public void onAnimationUpdate(final ValueAnimator animator) {
colorDrawable.setColor((Integer) animator.getAnimatedValue());
actionBar.setBackgroundDrawable(colorDrawable);
}
});
if (durationInMs >= 0)
colorAnimation.setDuration(durationInMs);
colorAnimation.start();
}
The problem
I can't find a way to get the view of the action mode, so that I could change its background on some cases (while it's showing).
What I tried
Only thing I found is a hack-y way which assumes that the id of the action mode will stay the same, and even this would work just for the view of the "done" button (the one that looks like an "V" and is actually more like "cancel").
I also found how to change it via themes, but that's not what I need, since I need to do it programmatically.
The question
How do I get the view of the actionMode, or, more precisely, how can I change its background using an animation?
How do I get the view of the actionMode, or, more precisely, how can I
change its background using an animation?
You have two choices, unfortunately neither of which involve native ActionMode APIs:
The ActionBarContextView is responsible for controlling the ActionMode
Use Resources.getIdentifier to call Activity.findViewById and pass in the ID the system uses for the ActionBarContextView
Use reflection to access to Field in ActionBarImpl
Here's an example of both:
Using Resources.getIdentifier:
private void animateActionModeViaFindViewById(int colorFrom, int colorTo, int duration) {
final int amId = getResources().getIdentifier("action_context_bar", "id", "android");
animateActionMode(findViewById(amId), colorFrom, colorTo, duration);
}
Using reflection:
private void animateActionModeViaReflection(int colorFrom, int colorTo, int duration) {
final ActionBar actionBar = getActionBar();
try {
final Field contextView = actionBar.getClass().getDeclaredField("mContextView");
animateActionMode((View) contextView.get(actionBar), colorFrom, colorTo, duration);
} catch (final Exception ignored) {
// Nothing to do
}
}
private void animateActionMode(final View actionMode, final int from, int to, int duration) {
final ValueAnimator va = ValueAnimator.ofObject(new ArgbEvaluator(), from, to);
final ColorDrawable actionModeBackground = new ColorDrawable(from);
va.addUpdateListener(new AnimatorUpdateListener() {
#Override
public void onAnimationUpdate(final ValueAnimator animator) {
actionModeBackground.setColor((Integer) animator.getAnimatedValue());
actionMode.setBackground(actionModeBackground);
}
});
va.setDuration(duration);
va.start();
}
Results
Here's a gif of the results animating from Color.BLACK to Color.BLUE at a duration of 2500: