I have a small irritating behaviour of my sliding Animation.
I made a video and posted it on youtube.
I could'nt find any app that can make a screen video from non-rooted phone, so I hade to do it this way :)
NOTE: look closely at the first animation, starting from 00:07
You will notice a small flash..that happens only for the first time, I trigger animation...
Afterwards, in the video, I trigger animation few more times, and there is no flash and everything runs smoothly.
Here is the code I use:
private void slideDown(){
// Here I calculate the height of a header and the ListView (That is not populated in the video, therefore - white and empty), as it will be different for different screen sizes
float headerHeight = header.getHeight();
float topicNameHeight = topHeader.getHeight()+1;
float totalHeight = headerHeight+topicNameHeight;
float listSize = listView.getHeight();
int theSizeIWant = (int) (listSize+totalHeight);
//slide down
if (counter==0){
listView.setPivotY(0);
ObjectAnimator slideAnimation = ObjectAnimator.ofFloat(listView, "y",topicNameHeight);
ObjectAnimator rotateAnimation = ObjectAnimator.ofFloat(btn_slider, "rotation",0f,180f);
listView.setLayoutParams(new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, theSizeIWant));
rotateAnimation.setDuration(800);
slideAnimation.setDuration(800);
slideAnimation.start();
rotateAnimation.start();
counter=1;
}
//slide up
else{
ObjectAnimator slideAnimation = ObjectAnimator.ofFloat(listView, "y",totalHeight);
ObjectAnimator rotateAnimation = ObjectAnimator.ofFloat(btn_slider, "rotation",180f,360f);
listView.setLayoutParams(new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, (int)listSize));
rotateAnimation.setDuration(800);
slideAnimation.setDuration(800);
slideAnimation.start();
rotateAnimation.start();
counter=0;
}
}
What seems to be the source of the problem?
I know it's a small thing, but it is majorly irritating, and needs to be fixed!
Related
We need to have an animation to push the title bar view out of the screen and pull it into the screen. The title bar locates on top of the screen.
To do this specific animation will cost a lot for the screen that the animation is not smooth. I implement is in this way:
ValueAnimator animDown = ValueAnimator.ofFloat(1f, 0f);
animDown.setDuration(300);
params = (RelativeLayout.LayoutParams) titleView.getLayoutParams();
animDown.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
#Override
public void onAnimationUpdate(ValueAnimator animation) {
float currentValue = (float) animation.getAnimatedValue();
newHeight = -(int) (titleView.getHeight() * currentValue);
if (newHeight != lastHeight) {
params.setMargins(0, newHeight, 0, 0);
titleView.requestLayout();
}
lastHeight = newHeight;
}
});
this works fine in some places but not here, for I found that the callback method onAnimationUpdate is called very few times (say 6-8 times) during the animation, which means one frame update cost over 40ms, which looks too laggy.
My question is: is there a way to increase the frequency of the callback method onAnimationUpdate, or is there any other way to do this animation more smoothly?
Previously we are using other animations such as fade out and it works well, but push out animation here cost too much while the grid view list below the title view also is quite heavy.
there's something I want to do but don't know how... that would be a button that slides from the bottom of the screen to a certain position, triggered by something. Very similar to how snackbar show, with the difference that it stays in place instead of disappearing and has the property of being "clickable". This would NOT be a panel draggable from the bottom, but a panel that slides automatically triggered by something.
How can I accomplish this?
Sounds like a fairly straightforward animation along the y axis, with a start value that matches the height of the screen (such that it renders just off screen), to whatever the final value is. Below code is from memory, but it should work.
To grab the screen height:
int getScreenHeight() {
DisplayMetrics displaymetrics = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(displaymetrics);
return displaymetrics.heightPixels;
}
And to animate a view (in this case, to 80% of the total screen height):
void animateOnScreen(View view) {
final int screenHeight = getScreenHeight();
ObjectAnimator animator = ObjectAnimator.ofFloat(view, "y", screenHeight, (screenHeight * 0.8F));
animator.setInterpolator(new DecelerateInterpolator());
animator.start();
}
Sliding a View down by a distance:
view.animate().translationY(distance);
You can later slide the View back to its original position like this:
view.animate().translationY(0);
I am trying to expand and shrink the width of container with animation.
I am doing both of those with ValueAnimator and both of those are working fine separately.
The expand animation will be perform when the user scroll up the cards and shrink animation will be perform when the user scroll down the cards.
Because all of those cards are in ScrollView container, the user can scroll up / down whenever they want even though the expanding / shrinking Animation is not finished.
To be more clear, it looks like the shrink animation is being triggered when the cards are still expanding. Below is my code for expanding / shrinking.
private void animateResizeWidth(final View vcLogin, int widthReduce){
ValueAnimator anim;
if(widthReduce == 0){
anim = ValueAnimator.ofInt((ScreenUtils.getObjInstance().getPixelFromDPI(CARD_WIDTH) - ScreenUtils.getObjInstance().getPixelFromDPI(widthReduce)), ScreenUtils.getObjInstance().getPixelFromDPI(CARD_WIDTH));
}else{
anim = ValueAnimator.ofInt(ScreenUtils.getObjInstance().getPixelFromDPI(CARD_WIDTH), (ScreenUtils.getObjInstance().getPixelFromDPI(CARD_WIDTH) - ScreenUtils.getObjInstance().getPixelFromDPI(widthReduce)));
}
final RelativeLayout.LayoutParams finalLp2 = new RelativeLayout.LayoutParams(vcLogin.getLayoutParams());
anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
#Override
public void onAnimationUpdate(ValueAnimator valueAnimator) {
int val = (Integer) valueAnimator.getAnimatedValue();
finalLp2.width = val;
finalLp2.addRule(RelativeLayout.CENTER_HORIZONTAL);
vcLogin.setLayoutParams(finalLp2);
vcLogin.invalidate();
}
});
anim.setDuration(400);
anim.start();
}
So, whenever that happen, the size of the cards are being set to regular size and the resize animation won't trigger anymore (Need to restart the Host Activity).
I have tried the answer from here. But, it is not helping me.
My Questions are 1: Is there any other Animation Mechanism that
I can use for width animation except ValueAnimator ? I have checked
ObjectAnimator but, not supporting. Ref 2: Is that thread
issue ? 3: I should not be blocking user from scrolling down
just because my expanding animation is not finished. So, what I haven
in mind is if the user scroll down, I will just terminate any of my
pending animations. Is there any thread-related issue that I need to consider for this approach ? (I have written a Custom
ScrollView to detect those scroll-related events.)
I think I am missing a few thread-safe logics in above animation implementation.
Thanks
What I want to do is simultaneously scale and translate an ImageView based when the user touches is. The final position and size of the ImageView should be equal to the target.
Below is a snipper of the OnClickListener attached to every ImageView that should perform this action. The new position and size is obtained from ivYou, which also is an ImageView.
#Override
public void onClick(View v) {
// Create animations
int[] from = new int[2];
int[] to = new int[2];
//v.getLocationInWindow(from);
v.getLocationOnScreen(from);
//ivYou.getLocationInWindow(to);
ivYou.getLocationOnScreen(to);
TranslateAnimation transAnim = new TranslateAnimation(0, to[0] - from[0], 0, to[1] - from[0]);
float factorX = ivYou.getWidth() / v.getWidth();
float factorY = ivYou.getHeight() / v.getHeight();
ScaleAnimation scaleAnim = new ScaleAnimation(1.0f, factorX, 1.0f, factorY);
// Create animation set
AnimationSet set = new AnimationSet(true);
set.setFillAfter(true);
set.setDuration(ANIM_DURATION);
set.addAnimation(transAnim);
set.addAnimation(scaleAnim);
// Start animations and disable click listener
v.startAnimation(set);
v.setOnClickListener(null);
}
ANIM_DURATION is 2000 miliseconds.
When I run this code the strangest things happen. The ImageView turns half a circle and gets smaller then its supposed to be. When I do not add the ScaleAnimator to the animation set, then the ImageView is moved to the new position. However, this new position isn't the same for every ImageView. Note that the ImageView's with this OnClickListener all have a different initial position.
Any help and feedback is greatly appreciated!
I was able to achieve this animation by wrapping the target View in a layout group and animating them separately.
In other words, I translate the wrapper layout, and scale the child view. Translating and scaling the same view at the same time always seems to result in unexpected animation trajectories as the scaling messes with the coordinate system the translate animation is using.
translateTarget.animate().x(deltaX).y(deltaY).setDuration(1000);
scaleTarget.animate().scaleX(0.01f).scaleY(0.01f).setDuration(1000)
Did you try this constructor?
ScaleAnimation (float fromX, float toX, float fromY, float toY, float pivotX, float pivotY) and have pivotX be widthofimageview/2 and pivotY be the heightofimageview/2 for it to be the center. This is what I used in my translate scale animation.
In a RelativeLayout, I added an ImageView with some margin set in LayoutParams:
RelativeLayout.LayoutParams rlLayoutParams = new RelativeLayout.LayoutParams(
RelativeLayout.LayoutParams.WRAP_CONTENT,
RelativeLayout.LayoutParams.WRAP_CONTENT);
rlLayoutParams.topMargin = (int) convertDpToPixel(kMARGIN_HEADER);
rlLayoutParams.leftMargin = (int) myMAGIC_MARGIN;
Now this ImageView is somewhere in the middle of the screen. I want to have it slide a few hundred pixels to its right, and stay there, so I applied the following TranslateAnimation:
private TranslateAnimation getAnimation(ImageView view, int displacement, int duration) {
int[] view_pos = new int[2];
view.getLocationOnScreen(view_pos);
TranslateAnimation slide = new TranslateAnimation(
view_pos[0],
view_pos[0] + displacement,
view_pos[1],
view_pos[1]);
slide.setFillAfter(true);
slide.setDuration(duration);
return slide;
}
Immediately after applying this animation, the whole view is gone. I checked the value of view_pos[] in debug mode, they are fine (not all zeroes). If I make the setFillAfter to false, then the view will come back after animation duration (for obvious reasons). So where did it go?
I also tried the following:
TranslateAnimation slide = new TranslateAnimation(
view_pos[0],
view_pos[0], // don't do the + displacement,
view_pos[1],
view_pos[1]);
I was expecting the view to stay where it is. But no, it was vanished as well, with a chance of coming back afterwards, depending on the value of setFillAfter.
I start to think I cannot apply TranslateAnimation if the view was placed by LayoutParams in a RelativeLayout. How should I achieve the goal of sliding the view?
The parameters for TranslateAnimation are deltas not positions, so you just want:
slide = new TranslateAnimation(0, displacement, 0, 0).
If you don't need to support Android <3.0 then use a Property Animation instead of a View Animation - see the Android docs for more details.