I am using the support.v7 Cardview and when i click on them i made a animation so the cardview expands to show more Information.
This worked fine and smooth, but now i add a toolbar as Support actionbar and now the Animation is laggy and i have no idea why:
I use this to expand a cardview
public void expand(final View v,final View vi) {
v.measure(LayoutParams.MATCH_PARENT,
WindowManager.LayoutParams.WRAP_CONTENT);
final int targetHeight = getHeight((ListView)v);
v.getLayoutParams().height = 0;
v.setVisibility(View.VISIBLE);
Animation a = new Animation()
{
#Override
protected void applyTransformation(float interpolatedTime, Transformation t) {
vi.setAlpha(1-interpolatedTime*10);
v.setAlpha(1-vi.getAlpha());
double heigt = -(targetHeight / (interpolatedTime + 1)) + targetHeight;
v.getLayoutParams().height =new Double(heigt*2).intValue();
v.requestLayout();
}
#Override
public boolean willChangeBounds() {
return true;
}
};
// 1dp/ms
a.setDuration(750);
v.startAnimation(a);
Handler h = new Handler();
h.postDelayed(new Runnable() {
#Override
public void run() {
v.getLayoutParams().height=targetHeight;
v.requestLayout();
vi.setVisibility(View.GONE);
}
},a.getDuration()+100);
}
and this is how i create the toolbar:
toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
toolbar.setTitle("CocktailListe");
toolbar.setSubtitle("Deine Lieblingscocktails in einer app");
toolbar.setTitleTextColor(getResources().getColor(R.color.text_main));
toolbar.setSubtitleTextColor(getResources().getColor(R.color.text_actionbar_secondary));
toolbar.setBackgroundColor(Color.parseColor(db.getActionbarColor()));
I´m pretty stuck and have no idea why it lags while using the toolbar, i hope someone can help
Related
I want to achieve the below animation in android I have tried scenes but scenes do not work with text as per docs it is confirmed :
"If you try to resize a TextView with an animation, the text will pop to a new location before the object has completely resized. To avoid this problem, do not animate the resizing of views that contain text."
Please any solution , the enlarged layout text can contain images too.
animation video
this thing worked some how ,but the animation is little jittery,I guess layout height final value is attained first and layoutWidth later, have to fix this. this is my enlarge/reduce animation :
public class EnlargeAnimation extends Animation {
private final int diffHeight;
private final int diffWidth;
private final int initialHeight;
private final int initialWidth;
private final View targetView;
public EnlargeAnimation(View targetView, float targetHeight, float targetWidth) {
this.targetView = targetView;
this.initialHeight = targetView.getMeasuredHeight();
this.initialWidth = targetView.getMeasuredWidth();
this.diffHeight = (int) (targetHeight-initialHeight);
this.diffWidth = (int) (targetWidth-initialWidth);
}
#Override
public boolean willChangeBounds() {
return true;
}
#Override
protected void applyTransformation(float interpolatedTime, Transformation t) {
float newHeight = initialHeight + diffHeight * interpolatedTime;
float newWidth = initialWidth + diffWidth * interpolatedTime;
targetView.getLayoutParams().height = (int) newHeight;
targetView.getLayoutParams().width = (int) newWidth;
targetView.requestLayout();
}
}
this is when enlarge animation is called :
I am using viewpager so i have to make padding negative to enlarge the card size :
ValueAnimator paddingAnimator = ValueAnimator.ofInt(20, -10).setDuration(400);
paddingAnimator.setInterpolator(new LinearInterpolator());
paddingAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
#Override
public void onAnimationUpdate(ValueAnimator animation) {
int padding = (int) animation.getAnimatedValue();
view.setPadding(padding,
(int) DeviceUtils.convertDpToPx(50, v.getContext()), padding,
(int) DeviceUtils.convertDpToPx(50, v.getContext()));
view.requestLayout();
}
});
viewPagerItemSizeListener.onEnlarged();
EnlargeAnimation
enlargeAnimation =
new EnlargeAnimation(cardView, screenHeight, screenWidth);
enlargeAnimation.setDuration(400);
enlargeAnimation.setAnimationListener(new Animation.AnimationListener() {
#Override
public void onAnimationStart(Animation animation) {
paddingAnimator.start();
seeExampleText.setVisibility(View.INVISIBLE);
}
#Override
public void onAnimationEnd(Animation animation) {
stage.setVisibility(View.GONE);
cardEnlargedWidth = cardView.getLayoutParams().width;
cardEnlargedHeight = cardView.getLayoutParams().height;
crossContianer.setVisibility(View.VISIBLE);
detailTextContianer.setVisibility(View.VISIBLE);
}
#Override
public void onAnimationRepeat(Animation animation) {
}
});
view.startAnimation(enlargeAnimation);
I guess no one is reading it, but if something is confusing about variables let me know i will edit the answer.
I need a drop-down with animation to open/close like this.
It needs animation with cells. You can see that in below animation image.
If anyone has an idea or a tutorial related to this solution than please share it with me.
Thanks in advance.
If you have any questions or querys in your mind than feel free to ask me.
I really want to get the proper solution to this.
You can use custom expand and collapse animations to show and hide a view. On top view clicked, expand and collapse required view. For this, you have to first calculate height of view.
Expand and collapse animation functions are followings.
Expand
/**
* Expanding a view with animation based on its height
*/
public static void expand(final View v,final int targetHeight) {
v.measure(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
v.getLayoutParams().height = 0;
v.setVisibility(View.VISIBLE);
Animation a = new Animation()
{
#Override
protected void applyTransformation(float interpolatedTime, Transformation t) {
v.getLayoutParams().height = interpolatedTime == 1
? targetHeight
: (int)(targetHeight * interpolatedTime);
v.requestLayout();
}
#Override
public boolean willChangeBounds() {
return true;
}
};
// 1dp/ms
a.setDuration((int)(targetHeight*2 / v.getContext().getResources().getDisplayMetrics().density));
v.startAnimation(a);
}
Collapse
/**
* Collapsing a view with animation based on its height
*/
public static void collapse(final View v,final int initialHeight)
{
Animation a = new Animation()
{
#Override
protected void applyTransformation(float interpolatedTime, Transformation t) {
if(interpolatedTime == 1){
v.setVisibility(View.GONE);
}else{
v.getLayoutParams().height = initialHeight - (int)(initialHeight * interpolatedTime);
v.requestLayout();
}
}
#Override
public boolean willChangeBounds() {
return true;
}
};
// 1dp/ms
a.setDuration((int)(initialHeight*2 / v.getContext().getResources().getDisplayMetrics().density));
v.startAnimation(a);
}
Am trying to do a simple animation in order scale a relative layout's width. I managed to do it using this code but the animation is done very quickly even with 5000ms duration. I cant see the intermidiate results. Any suggestion?
RelativeLayout baseLayer;
RelativeLayout fillLayer;
public void animate(int duration){
Animation a = new Animation()
{
#Override
protected void applyTransformation(float interpolatedTime, Transformation t)
{
fillLayer.getLayoutParams().width = (int)(baseLayer.getLayoutParams().width * interpolatedTime);
fillLayer.requestLayout();
}
#Override
public boolean willChangeBounds() {
return true;
}
};
a.setDuration(duration);
a.setInterpolator(new LinearInterpolator());
fillLayer.startAnimation(a);
}
I have found the solution. The problem was that i was calling the animation method from OnStart(). Now am calling it from onWindowFocusChanged().
#Override
public void onWindowFocusChanged(boolean hasFocus) {
super.onWindowFocusChanged(hasFocus);
testBar.animate(2000,0.8);
}
RelativeLayout baseLayer;
RelativeLayout fillLayer;
public void animate(int duration,float fillPercentage){
final int targetWidth = (int)(baseLayer.getMeasuredWidth() * fillPercentage);
Animation a = new Animation()
{
#Override
protected void applyTransformation(float interpolatedTime, Transformation t)
{
fillLayer.getLayoutParams().width = (int)(targetWidth * interpolatedTime);
fillLayer.requestLayout();
}
#Override
public boolean willChangeBounds() {
return true;
}
};
a.setDuration(duration);
a.setInterpolator(new LinearInterpolator());
fillLayer.startAnimation(a);
}
And throughout this procedure I have found from other post an alternative way to do the same job. But again it the method need to be called form the onWindowFocusChanged().
ValueAnimator.ofObject(new WidthEvaluator(fillLayer), fillLayer.getLayoutParams().width, targetWidth).setDuration(2000).start();
class WidthEvaluator extends IntEvaluator {
private View v;
public WidthEvaluator(View v) {
this.v = v;
}
#Override
public Integer evaluate(float fraction, Integer startValue, Integer endValue) {
int num = (Integer)super.evaluate(fraction, (Integer)startValue, (Integer)endValue);
ViewGroup.LayoutParams params = v.getLayoutParams();
params.width = num;
v.setLayoutParams(params);
return num;
}
}
[Update Solution]
Following to that I have added my custom views into a ListView and then the problems started again. ListView should be getting ready before views get their actual size. So the animation wasn't able to be done because getMeasuredWidth() was returning always 0 (this was and the problem from the beginning).
So what i did is i used this code snippet in OnCreate().
ViewTreeObserver vto = listBars.getViewTreeObserver();
vto.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
if (!HackClass.GlobalDrawnFlag) {
adapter.notifyDataSetChanged();
HackClass.GlobalDrawnFlag = true;
}
}
});
And this inside my list adapter class
if (item.getMeasuredWidth==0)
HackClass.GlobalDrawnFlag = false;
else
HackClass.GlobalDrawnFlag = true;
This approach solved all my problems apparently. However is that a good solution ? Any other suggestion is welcome.
I have implemented an animation for a Layout that must flow downwards and upwards. The animation precisely must flow in both low that high. This gridview is located above a ExpandbleListView. So, when I close all the groups the animation is very fluid. When the groups on the list are open, with many elements, however the animation is triggered, it is not as fluid as I would like it to be. I'll post the code of my animation:
public void expand(final View v) {
v.measure(LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT);
final int targtetHeight = v.getMeasuredHeight();
v.getLayoutParams().height = 0;
v.setVisibility(View.VISIBLE);
Animation a = new Animation() {
#Override
protected void applyTransformation(float interpolatedTime,
Transformation t) {
v.getLayoutParams().height = interpolatedTime == 1 ? LayoutParams.WRAP_CONTENT
: (int) (targtetHeight * interpolatedTime);
v.requestLayout();
}
#Override
public boolean willChangeBounds() {
return true;
}
};
Interpolator i = AnimationUtils.loadInterpolator(this,
android.R.anim.linear_interpolator);
a.setInterpolator(i);
a.setDuration(200);
v.startAnimation(a);
}
and :
public static void collapse(final View v) {
final int initialHeight = v.getMeasuredHeight();
Animation a = new Animation() {
#Override
protected void applyTransformation(float interpolatedTime,
Transformation t) {
if (interpolatedTime == 1) {
v.setVisibility(View.GONE);
} else {
v.getLayoutParams().height = initialHeight
- (int) (initialHeight * interpolatedTime);
v.requestLayout();
}
}
#Override
public boolean willChangeBounds() {
return true;
}
};
// 1dp/ms
a.setDuration(200);
v.startAnimation(a);
}
How can I do to make the animation smoother?
--> Edit: I was wrong code, I corrected
I have a list of buttons. When I press a button, a View should slide in a downwards motion out of the button, like this:
Start:
Halfway:
End:
How would I go about this? The View that should slide out is bigger than the button, so first hiding the View behind the button and then sliding it downwards causes the View to be visible above the button. That should not happen.
Any ideas or examples on how to approach this?
I believe the simplest approach is to extend Animation class and override applyTransformation() to change the view's height as follows:
import android.view.View;
import android.view.ViewGroup.LayoutParams;
import android.view.animation.Animation;
import android.view.animation.Transformation;
import android.widget.LinearLayout;
public class MyCustomAnimation extends Animation {
public final static int COLLAPSE = 1;
public final static int EXPAND = 0;
private View mView;
private int mEndHeight;
private int mType;
private LinearLayout.LayoutParams mLayoutParams;
public MyCustomAnimation(View view, int duration, int type) {
setDuration(duration);
mView = view;
mEndHeight = mView.getHeight();
mLayoutParams = ((LinearLayout.LayoutParams) view.getLayoutParams());
mType = type;
if(mType == EXPAND) {
mLayoutParams.height = 0;
} else {
mLayoutParams.height = LayoutParams.WRAP_CONTENT;
}
view.setVisibility(View.VISIBLE);
}
public int getHeight(){
return mView.getHeight();
}
public void setHeight(int height){
mEndHeight = height;
}
#Override
protected void applyTransformation(float interpolatedTime, Transformation t) {
super.applyTransformation(interpolatedTime, t);
if (interpolatedTime < 1.0f) {
if(mType == EXPAND) {
mLayoutParams.height = (int)(mEndHeight * interpolatedTime);
} else {
mLayoutParams.height = (int) (mEndHeight * (1 - interpolatedTime));
}
mView.requestLayout();
} else {
if(mType == EXPAND) {
mLayoutParams.height = LayoutParams.WRAP_CONTENT;
mView.requestLayout();
}else{
mView.setVisibility(View.GONE);
}
}
}
}
To use it, set your onclick() as follows:
int height;
#Override
public void onClick(View v) {
if(view2.getVisibility() == View.VISIBLE){
MyCustomAnimation a = new MyCustomAnimation(view2, 1000, MyCustomAnimation.COLLAPSE);
height = a.getHeight();
view2.startAnimation(a);
}else{
MyCustomAnimation a = new MyCustomAnimation(view2, 1000, MyCustomAnimation.EXPAND);
a.setHeight(height);
view2.startAnimation(a);
}
}
Regards.
Use something like:
Animation a = new ScaleAnimation(1, 1, 0, 1, Animation.RELATIVE_TO_SELF, (float) 0.5, Animation.RELATIVE_TO_SELF, (float) 0);
a.setFillAfter(true);
view.setAnimation(a);
a.setDuration(1000);
view.startAnimation(a);
Here is simple example of hand-made animation, that provide what you want. It works in test app, but I'm not sure that there is no bugs:
public class MainActivity extends Activity implements OnClickListener {
private Timer timer;
private TimerTask animationTask;
private View view1;
private View view2;
boolean animating;
boolean increasing = true;
int initHeight = -1;
private LayoutParams params;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
timer = new Timer();
view1 = findViewById(R.id.view1);// clickable view
view1.setOnClickListener(this);
view2 = findViewById(R.id.view2);// animated view
params = view2.getLayoutParams();
}
#Override
protected void onDestroy() {
super.onDestroy();
timer.cancel();
}
#Override
public void onClick(View v) {
Toast.makeText(this, "start animating...", Toast.LENGTH_SHORT).show();
animationTask = new TimerTask() {
#Override
public void run() {
runOnUiThread(new Runnable() {
#Override
public void run() {
if (animationFinished()) {
animating = false;
cancel();//canceling animating task
return;
}
params.height += increasing ? 1 : -1;
view2.setLayoutParams(params);
}
});
}
private boolean animationFinished() {
int viewHeight = view2.getHeight();
if (increasing && viewHeight >= initHeight) {
return true;
}
if (!increasing && viewHeight <= 0) {
return true;
}
return false;
}
};
//if we already animating - we just change direction of animation
increasing = !increasing;
if (!animating) {
animating = true;
int height = view2.getHeight();
params.height = height;
view2.setLayoutParams(params);//change param "height" from "wrap_conent" to real height
if (initHeight < 0) {//height of view - we setup it only once
initHeight = height;
}
timer.schedule(animationTask, 0, 10);//changing repeat time here will fasten or slow down animation
}
}
}
Maybe you can set the height to 0 and gradually increase the height. But then you will have the problem that you have to be sure your text is aligned at the bottom of the view. And also to know what the maximal height of the view should be.
use a sliding list adapter so much easier than messing around with animations
https://github.com/tjerkw/Android-SlideExpandableListView
Simply pass android:animateLayoutChanges to LinearLayout that holds all the views, you will achieve your desired result.
I would do it like that. First the layout for the whole collapsible panel component: (pseudo xml)
RelativeLayout (id=panel, clip)
LinearLayout (id=content, alignParentBottom=true)
LinearLayout (id=handle, above=content)
This should ensure that the content is always below the handle.
Then when you need to collapse:
Animate the top margin of content from 0 to -content.height
Animate the height of the panel from current to current-content.height