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);
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.
I got a layout in which there's a RelativeLayout with a visibility of GONE. This rl is a layout for a bar with buttons which appears at the bottom of the fragment when setting the visibility to visible. While the RL is still not visible, there are 2 buttons and when I set it to visible, the RL is covering the buttons.
What I want to do is simply move the buttons up above that bar which becomes visible. What I tried to do it:
rl.setVisibility(View.VISIBLE);
rl.post(new Runnable()
{
int dpToPx(final int dp)
{
return (int) (dp * getResources().getSystem().getDisplayMetrics().density + 0.5f);
}
#Override
public void run() {
int h = rl.getHeight(); //height is ready
h = dpToPx(h);
ImageButton button = (ImageButton)inflate.findViewById(R.id.button1);
float y = button.getY();
button.setY((float)h+y - 1100);
ImageButton button2 = (ImageButton)inflate.findViewById(R.id.button2);
y = button2.getY();
button2.setY((float)h+y);
}
});
The button with the -1100 (That number was just something I checked to see how it affects the position of the button and will not stay there obviously) is showing where I want it to be. The other button is so high or low which is no longer visible.
How do I set the position such that the button's Y position will be the old position + the height of the newly shown relative layout so the buttons will show just above it?
This is straightforward, all we need to do is to position the buttons at the y coordinate of our RelativeLayout.
We can get the y coordinate by calling:
rl.getY();
And since we want the button to be above the rl, we will subtract its height from the y coordinate of rl, something like this:
button.setY(rl.getY() - button.getHeight());
I have a View that has an OnClickListener. When clicked, the view translates up to a certain position on the page. This is no problem, the view goes where it should. When the view is clicked again, I would like to position it somewhere else, but this is not the case. After a little bit of trouble shooting, I found that my View's getTop() method returns the same value - even after the translation animation has moved the view to a different part of the screen. For the second animation, it is not using the current position (as I would expect), it instead uses the initial position.
Few things that I am doing: I am using the ObjectAnimation class rather than the TranslationAnimation class, since I wanted to keep the OnClickListener functioning. With the TranslationAnimation class, I found that the view was correctly moved, but the OnClickListener was only working in the area that the View started from. Using the ObjectAnimation class, I was able to easily get the translation to work AND the OnClickListener functions correctly - it is triggered where the view currently is on the screen.
Here's what I have so far:
final LinearLayout child = layouts.get(i); //ArrayList containing some dynamic layouts
final int offset = target - child.getTop();
ObjectAnimator anim = ObjectAnimator.ofFloat(child,"translationY",offset);
anim.setDuration(250);
anim.start();
This is what happens when the view is clicked the first time. It translates up along the Y axis, where the offset determines how far the View needs to move from its current position.
Now, here's what happens on the second click. The goal here was to align the view with the parent's base.
target = parent.getBottom();
offset = target - child.getTop();
anim = ObjectAnimator.ofFloat(child, "translationY",offset);
anim.setDuration(250);
anim.start();
prev = child;
This is where things fall apart - child.getTop() returns the Y coordinate of the view's ORIGINAL position. Not the current position. So after the animation, the view is placed well below the bottom of the parent. I read a different question which stated that I should use child.getY() instead, which is supposed to give me the translationY position plus the top position, but this didn't lead to any better results. I can't seem to get this to work just right. I'd simply like to move the view from its current position to the bottom of the screen, but this appears to be a hard thing to accomplish. Any help would be appreciated.
EDIT
I have added an animation listener:
ObjectAnimator anim = ObjectAnimator.ofFloat(child,"translationY",offset);
anim.setDuration(250);
anim.addListener(new ObjectAnimator.AnimatorListener(){
#Override
public void onAnimationStart(Animator animation) {
System.out.println("start: " + child.getTop() + " " + child.getY());
}
#Override
public void onAnimationEnd(Animator animation) {
System.out.println("end: " + child.getTop() + " " + child.getY() + " " + child.getTranslationY());
child.setTop((int)child.getY());
System.out.println(child.getTop());
}
#Override
public void onAnimationCancel(Animator animation) {}
#Override
public void onAnimationRepeat(Animator animation) {}
});
anim.start();
Here I am setting the listener to try to change where the Top of the view is located. Behaviour is again not working as expected. The view is actually sent up above the screen when I do this. Output of the System.out looks like this:
start: 2008 2008.0
end: 2008 478.0 -1530.0
478
So calling child.getTop() after the animation is complete and setting a new position returns a positive integer, but the view is not actually completely on screen. It is above the screen, partly visible. The height of the view itself is about 700px. I am still so confused as to why this is such a hard thing to accomplish.
EDIT 2
I have also tried setting layoutparams inside the onAnimationEnd method:
RelativeLayout.LayoutParams params = (RelativeLayout.LayoutParams)child.getLayoutParams();
params.removeRule(RelativeLayout.ALIGN_PARENT_BOTTOM);
params.addRule(RelativeLayout.ALIGN_PARENT_TOP, RelativeLayout.TRUE);
params.topMargin = (int)child.getY();
child.setLayoutParams(params);
Result: child.getTop() still returns the original position of 2008.
You can get the very bottom of the screen coordinates like this :
float bottomOfScreen = getResources().getDisplayMetrics().heightPixels;
but you probably want it minus the height of your LinearLayout or else your LinearLayout will be cut off by the bottom :
float bottomOfScreen = getResources().getDisplayMetrics().heightPixels
- child.getHeight();
// if you want a little more space to the bottom
// try something like - child.getHeight()*2;
Then use ViewPropertyAnimator to animate your LL like this :
child.animate()
.translationY(bottomOfScreen)
.setInterpolator(new AccelerateDecelerateInterpolator())
.setDuration(250);
The Interpolator is just to make the animation more realistic.
In the case that child.getHeight() returns 0 , your Linear Layout has not been finished setting up by the system, in that case you might want to do something like :
child.post(new Runnable() {
#Override
public void run() {
float bottomOfScreen = getResources().getDisplayMetrics().heightPixels
- child.getHeight()*2;
child.animate()
.translationY(bottomOfScreen)
.setInterpolator(new AccelerateDecelerateInterpolator())
.setDuration(250);
}
});
Remember that a duration of 250 milliseconds is very fast, and does usually not look cool translating stuff on the screen, so you might want to set it a little higher, but thats just a matter of taste.
I am working on android application in which on button click i am giving width and height to my linear layout to make it full screen and by clicking again i am giving its width and height to 1dp. I just need to animate this thing like when i press the button it will slowly animate to full screen and on again pressing of button it will slowly animate to 1dp width and height. I have used translate for this thing but it didn't work in this scenario.
btnResize.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if(resize==true){
otherLayout.setLayoutParams(new LayoutParams(1, 1));
resize=false;
}else{
resize=true;
int height = LayoutParams.WRAP_CONTENT;
int width = LayoutParams.MATCH_PARENT;
// ImageView imageView = (ImageView)findViewById(R.id.imageView);
//
// Animation animZoomin = AnimationUtils.loadAnimation(getApplicationContext(), R.anim.zoom_in);
//
// imageView.startAnimation(animZoomin);
otherLayout.setLayoutParams(new LayoutParams(width, height));
}
}
});
You can use scale animation:
Start by calculating your screen size: Get screen dimensions in
pixels
Next get the current view width and height.
Calculate the ratio between the 2 to get the scale factor (hint: screenH / viewH)
Next use view.animate().scaleX(xRatio).scaleY(yRatio) to start the
animation
You may need to translate the view too if it is not centered in the screen
Other option is to use this method: Expand/collapse animation
I add a view to the WindowManager using WindowManager.updateViewLayout().
I then attache an onTouch listener to it, and make it "follow" the user's finger (drag). I do this by changing the x and y values of the WindowManager.LayoutParams I passed in updateViewLayout.
When the user lifts the finger, I want the view to animate to the screen's left/right edge according to where it is closer to.
The effect I get is the view sticking to the edge immediately, without any animation.
If the view's width/height change tough (and following that, the width/height of the WindowManager.LayoutParams), the view animates to its new place.
Is there a way to get it to animate after just changing the x/y values (without having the width/height change)?
You can do it like this: run an animator whenever you lift the finger:
// <inside switch case in your touchEvent handling>
// params variable is your view's params
case MotionEvent.ACTION_UP:
ValueAnimator va = ValueAnimator.ofFloat(params.x, 0);
int mDuration = 250;
va.setDuration(mDuration);
va.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
public void onAnimationUpdate(ValueAnimator animation) {
params.x = Math.round((Float) animation.getAnimatedValue());
mWindowManager.updateViewLayout(mOverlayView, params);
}
});
va.start();
This code always animates it to the left edge of the screen as you release your finger. You can sort that out by by keeping track of the view's coordinates and checking against the middle of the screen and then changing the animation target.