I am trying to create a padding left animation in RelativeLayout. I wrote code which can animate left in click listener.
This is my code, but it is not working completely.
list.setOnItemClickListener(new OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view,
int position, long id) {
holder = (UserHolder) view.getTag();
layoutParams = (RelativeLayout.LayoutParams) holder.layoutmain
.getLayoutParams();
if (holder.layout.getVisibility() != View.VISIBLE) {
ValueAnimator varl = ValueAnimator.ofInt(-170);
varl.setDuration(1000);
varl.addUpdateListener(new AnimatorUpdateListener() {
#Override
public void onAnimationUpdate(ValueAnimator animation) {
layoutParams.setMargins(
(Integer) animation.getAnimatedValue(), 0,
0, 0);
holder.layoutmain.setLayoutParams(layoutParams);
holder.layout.setVisibility(View.VISIBLE);
}
});
varl.start();
}
else
{
ValueAnimator varl = ValueAnimator.ofInt(0);
varl.setDuration(1000);
varl.addUpdateListener(new AnimatorUpdateListener() {
#Override
public void onAnimationUpdate(
ValueAnimator animation) {
layoutParams.setMargins(0, 0,
(Integer) animation.getAnimatedValue(),
0);
// lp.setMargins(left, top, right, bottom)
holder.layoutmain.setLayoutParams(layoutParams);
holder.layout.setVisibility(View.INVISIBLE);
}
});
varl.start();
}
}
});
The first time, it works (I can animate padding left), but the second time I click the animation is not working. What am I doing wrong?
Through ValueAnimator class you can update margin or padding of any with animation. Please go through the following code :
ValueAnimator animator = ValueAnimator.ofInt(0,50);
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
#Override
public void onAnimationUpdate(ValueAnimator valueAnimator){
frameLayout.setPadding(0, (Integer) valueAnimator.getAnimatedValue(),0,0);
}
});
animator.setInterpolator(new DecelerateInterpolator(2));
animator.start();
Let me know in case of more explanation in comments.
You should try using ValueAnimator.ofInt(fromInt,toInt)
//first
ValueAnimator.ofInt(-70,0)
//second
ValueAnimator.ofInt(0,-70)
Otherwise the value animator doesn't know from or to which value it should animate.
Related
I'm trying to fade out items when it's removed then collapse recycleview. But it doesn't work.
Please help me
for(Object appData : mInvisibleEntries){
mVisibleEntries.remove(appData);
}
for(View view:viewHoldersList){
Animation a = new AlphaAnimation(1.00f, 0.00f);
a.setDuration(2000);
view.startAnimation(a);
}
notifyItemRangeRemoved(MAX_VISIBLE_APPS_COUNT + 1, mInvisibleEntries.size());
collapseRv();
private void collapseRv(){
final int initialHeight = mRecyclerView.getMeasuredHeight();
ValueAnimator valueAnimator = ValueAnimator.ofInt(initialHeight,HEIGHT_VIEW_APPDATA*3+HEIGHT_SECTION_FOOTER);
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
#Override
public void onAnimationUpdate(ValueAnimator animation) {
mRecyclerView.getLayoutParams().height = (int) animation.getAnimatedValue();
mRecyclerView.requestLayout();
}
});
valueAnimator.setInterpolator(new DecelerateInterpolator());
valueAnimator.setDuration(2000);
valueAnimator.start();
}
To make it simlpe, You can use library like https://github.com/wasabeef/recyclerview-animators
The following code is working when the supplied view is a Button but when it's a LinearLayout nothing happens (Background color doesn't change).
If I manually set the color on the LinearLayout without the ValueAnimator it works. I also tried using a ObjectAnimator but the result looked terrible.
An example call:
playBlinkAnimation(view, activity.getResources().getColor(R.color.transparent), activity.getResources().getColor(R.color.colorRed), 5000);
view.getBackground().setColorFilter(activity.getResources().getColor(R.color.colorRed), PorterDuff.Mode.DARKEN);
private void playBlinkAnimation(final View view, int colorFrom, int colorTo, int duration) {
ValueAnimator colorAnimation = new ValueAnimator();
colorAnimation.setIntValues(colorFrom, colorTo);
colorAnimation.setEvaluator(new ArgbEvaluator());
colorAnimation.setDuration(duration);
colorAnimation.setRepeatCount(ValueAnimator.INFINITE);
colorAnimation.setRepeatMode(ValueAnimator.REVERSE);
colorAnimation.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
#Override
public void onAnimationUpdate(ValueAnimator animator) {
view.getBackground().setColorFilter((int) animator.getAnimatedValue(), PorterDuff.Mode.DARKEN);
}
});
colorAnimation.addListener(new Animator.AnimatorListener() {
#Override
public void onAnimationStart(Animator animation) {
}
#Override
public void onAnimationEnd(Animator animation) {
view.getBackground().setColorFilter(null);
}
#Override
public void onAnimationCancel(Animator animation) {
view.getBackground().setColorFilter(null);
view.setAlpha(1);
view.getBackground().setColorFilter(null);
}
#Override
public void onAnimationRepeat(Animator animation) {
}
});
colorAnimation.start();
}
You can try using AnimatorSet and it's playTogether function. It takes an array of Animators, and it's designed to run multiple animations together, but it should work with only one animation as well.
Hope that helps you!
Since you seem to want your layout to transition from transparent background to opaque red, you should animate the layout's alpha parameter
ObjectAnimator animator = ObjectAnimator.ofInt(view, "alpha", 0, 1);
animator.setDuration(5000);
animator.setInterpolator(new LinearInterpolator());
animator.start();
I have a search bar that expands when icon is clicked in toolbar. Now, everything is cool when it is expanded, everything works fine, the thing that is not good is that the height isnt good when the search bar is collapsed. The toolbar upon collapsing search bar has bigger height than it had. Here is the code:
private void expand(View view) {
//set Visible
view.setVisibility(View.VISIBLE);
final int widthSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
final int heightSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
view.measure(widthSpec, heightSpec);
ValueAnimator mAnimator = slideAnimator(0, view.getMeasuredHeight(), view);
mAnimator.start();
}
private ValueAnimator slideAnimator(int start, int end, final View view) {
ValueAnimator animator = ValueAnimator.ofInt(start, end);
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
#Override
public void onAnimationUpdate(ValueAnimator valueAnimator) {
//Update Height
int value = (Integer) valueAnimator.getAnimatedValue();
ViewGroup.LayoutParams layoutParams = view.getLayoutParams();
layoutParams.height = value;
view.setLayoutParams(layoutParams);
}
});
return animator;
}
private void collapse(final View view) {
int finalHeight = view.getHeight();
ValueAnimator mAnimator = slideAnimator(finalHeight, 0, view);
mAnimator.addListener(new Animator.AnimatorListener() {
#Override
public void onAnimationStart(Animator animation) {
}
#Override
public void onAnimationEnd(Animator animator) {
//Height=0, but it set visibility to GONE
view.setVisibility(View.INVISIBLE);
}
#Override
public void onAnimationCancel(Animator animation) {
}
#Override
public void onAnimationRepeat(Animator animation) {
}
});
mAnimator.start();
}
Everything is good here, check where you call method if you are changing background or any other property of the toolbar.
I need to animate a TextView when i click a button. The height of the TextView is wrap_content. This TextView is inside a RecyclerView row and i need to expand it from visibility gone to his real height with content. I used ValueAnimator.
private ValueAnimator slideAnimator(int start, int end) {
ValueAnimator animator = ValueAnimator.ofInt(start, end);
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
#Override
public void onAnimationUpdate(ValueAnimator valueAnimator) {
int value = (Integer) valueAnimator.getAnimatedValue();
ViewGroup.LayoutParams layoutParams = tvAdditional.getLayoutParams();
layoutParams.height = value;
tvAdditional.setLayoutParams(layoutParams);
}
});
return animator;
}
private void expand(View v) {
v.setVisibility(View.VISIBLE);
v.measure(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
ValueAnimator mAnimator = slideAnimator(0, v.getMeasuredHeight());
mAnimator.start();
}
private void collapse(final View v) {
int finalHeight = v.getHeight();
ValueAnimator mAnimator = slideAnimator(finalHeight, 0);
mAnimator.addListener(new Animator.AnimatorListener() {
#Override
public void onAnimationStart(Animator animation) {
}
#Override
public void onAnimationEnd(Animator animator) {
v.setVisibility(View.GONE);
}
#Override
public void onAnimationCancel(Animator animation) {
}
#Override
public void onAnimationRepeat(Animator animation) {
}
});
mAnimator.start();
}
In debug i noticed that when i use getMeasuredHeight() method on view in expand, the value is always 76, also if i added items with more than one row.
P.s. i call expand and collapse inside the click listener of the row.
Screenshot:
SOLVED
I changed my expand method adding a listener in which i set the height to wrap_content at the end of the animation:
private void expand(final View v) {
v.measure(View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED), View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED));
v.getLayoutParams().height = 0;
v.setVisibility(View.VISIBLE);
final int targetHeight = v.getMeasuredHeight();
ValueAnimator mAnimator = slideAnimator(0, targetHeight);
mAnimator.addListener(new Animator.AnimatorListener() {
#Override
public void onAnimationStart(Animator animation) {
}
#Override
public void onAnimationEnd(Animator animation) {
v.getLayoutParams().height = ViewGroup.LayoutParams.WRAP_CONTENT;
v.requestLayout();
}
#Override
public void onAnimationCancel(Animator animation) {
}
#Override
public void onAnimationRepeat(Animator animation) {
}
});
mAnimator.start();
}
When you have the Visibility as GONE, you cannot know it's measured height until it's actually drawn. In order to have that, you need to have GlobalLayoutListener on that TextView, so you can get it's measured height when it's drawn.
In your expand method, I see that you set the Visibility to Visible and then try to measure it, which won't be drawn immediately, so you cannot get the height.
So what you can do to get the actual height of the TextView if it's visibility is initially gone, first you should change the initial visibility to VISIBLE, second, set a Global Layout Listener and as third step, store the TextView's height in a global value after you measure it, and as the last step, you can set the Visibility of TextView as GONE.
This process is normally really quick, so you won't be able to see the TextView's visibility changing from VISIBLE to GONE with your eyes.
Problem
I'm trying to animate the ListView header height. I can get the animation right, but after the animation completes the ListView flickers.
Tried and failed
Use AnimationSet.setFillAfter() without changing the layout params. The animation works fine, but when you start scrolling the list, header jumps back to original position.
Use AnimationSet.setFillAfter() with new layout params applied at onAnimationEnd(). After the animation ends the header jumps to twice the required height (animated height plus the height set in layout params). When you start scrolling the list, header snaps to the required height.
Code
if (mSearchAdapter.getCount() > 0 && mListView.getChildAt(0) == mHeaderPlaceholder) {
Log.i(TAG, "Animating list view to make room for info bar");
AnimationSet slideAnimation = new AnimationSet(true);
TranslateAnimation translate = new TranslateAnimation(0, 0, 0, newHeight);
translate.setDuration(mInfoBarAnimationDuration);
translate.setInterpolator(new DecelerateInterpolator());
slideAnimation.addAnimation(translate);
slideAnimation.setAnimationListener(new Animation.AnimationListener() {
#Override
public void onAnimationStart(Animation animation) {
isAnimatingViewTransition = true;
}
#Override
public void onAnimationEnd(Animation animation) {
isAnimatingViewTransition = false;
final AbsListView.LayoutParams layoutParams = (AbsListView.LayoutParams) mHeaderPlaceholder.getLayoutParams();
layoutParams.height = newHeight;
mHeaderPlaceholder.setLayoutParams(layoutParams);
}
#Override
public void onAnimationRepeat(Animation animation) {
}
});
mListView.startAnimation(slideAnimation);
} else {
Log.i(TAG, "Adjusting list view header to make room for info bar");
mHeaderPlaceholder.getLayoutParams().height = newHeight;
}
I think the flicker can be avoided by listening for and overriding the events onPreDraw() or onGlobalLayout() of the ViewTreeObserver of the ListView. But I don't know exactly how I can achieve it.
Any help is much appreciated!
Instead of animating ListView header I opted to used ValueAnimator to achieve the same effect. Here is code:
if (mSearchAdapter.getCount() > 0 && mListView.getChildAt(0) == mHeaderPlaceholder) {
ValueAnimator mSlideListViewAnimator = ObjectAnimator.ofInt(from, to);
mSlideListViewAnimator.setDuration(mInfoBarAnimationDuration);
mSlideListViewAnimator.setInterpolator(new DecelerateInterpolator());
mSlideListViewAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
#Override
public void onAnimationUpdate(ValueAnimator animation) {
Integer animatedYValue= (Integer) animation.getAnimatedValue();
final AbsListView.LayoutParams layoutParams = (AbsListView.LayoutParams) mHeaderPlaceholder.getLayoutParams();
layoutParams.height = animatedYValue;
mHeaderPlaceholder.requestLayout();
}
});
mSlideListViewAnimator.addListener(new AnimatorListenerAdapter() {
#Override
public void onAnimationStart(Animator animation) {
isAnimatingViewTransition = true;
}
#Override
public void onAnimationEnd(Animator animation) {
isAnimatingViewTransition = false;
}
});
mSlideListViewAnimator.start();
} else {
Log.i(TAG, "Adjusting list view header to make room for info bar");
mHeaderPlaceholder.getLayoutParams().height = newHeight;
}