I have a RelativeLayout with an ImageView inside it. ImageView is positioned randomly inside a layout. I'm trying to apply translate animation, which will translate the ImageView from it's current position (x,y) to the center of screen (x,y).
I have tried something like code below, but it doesn't do the trick.
<translate
android:fromXDelta="0%"
android:toXDelta="50%"
android:fromYDelta="0%"
android:toYDelta="50%"
android:duration="500"/>
Help appreciated ;)
MY Code:
Understand...
Point windowSize = new Point();
int totalWidth;
//obtem o tamanho da tela que estamos trabalhando no momento
if(Build.VERSION.SDK_INT > 12) {
windowManager.getDefaultDisplay().getSize(windowSize);
totalWidth = windowSize.x;
}
else
totalWidth = windowManager.getDefaultDisplay().getWidth();
//vamos animar ao centro
final int totalWidthFinal = ((totalWidth / 2) - (int)getDimension(R.dimen.fab_actions_spacing)) * -1;
mFloatingActionButton.post(new Runnable() {
#Override
public void run() {
int translationX = totalWidthFinal;
ViewPropertyAnimator.animate(mFloatingActionButton).setDuration(300).translationX(translationX);
}
});
Related
I have quite easy class that draws circles. I'm giving the parameter, view calculates the rest. All I want to give some delay and fade effect for each during draw to canvas. I reviewed a few articles about animators and handlers but I couldn't figure out. Please, show me some implementations. Thanks.
#Override
protected void onDraw(final Canvas canvas) {
super.onDraw(canvas);
int w = getWidth();
int pl = getPaddingLeft();
int pr = getPaddingRight();
int totalWidth = w - (pl + pr);
major = totalWidth / circleCount;
radius = major / 2;
startPoint = totalWidth / (circleCount * 2);
for (int i = 0; i < circleCount; i++) {
canvas.drawCircle(startPoint + major * i, radius, radius, paint);
}
}
Here's a simple alpha animation of a button view [it makes the button blink](it's not so hard ;O) ):
import android.view.animation.AlphaAnimation;
import android.view.animation.Animation;
import android.view.animation.LinearInterpolator;
final Animation animation = new AlphaAnimation(1, 0); // Change alpha from fully visible to invisible
animation.setDuration(500); // duration - half a second
animation.setInterpolator(new LinearInterpolator()); // do not alter animation rate
animation.setRepeatCount(Animation.INFINITE); // Repeat animation infinitely
animation.setRepeatMode(Animation.REVERSE); // Reverse animation at the end so the button will fade back in
final Button btn = (Button) findViewById(R.id.but4);//replace this with your view
btn.startAnimation(animation);
You could use the setAlpha(int a) method from the Paint class.
It should work when you do it on a separate Thread with a little time delay in a loop where you count down from 255 to 0.
Here is a code sample where I tried this for earlier versions of Android some years ago :
private final int FADE_TIME = 10; // modify to your needs
private void fade() {
new Thread(new Runnable() {
#Override
public void run() {
try {
int i = 255;
while (i >= 0) {
paint.setAlpha(i);
Thread.sleep(FADE_TIME);
i--;
}
} catch (InterruptedException e) {
// do something in case of interruption
}
}
}).start();
}
Nowadays I would probably use a Handler with postDelayed() for this job, but this should give you an impression of how it can be done.
I am writing a launcher.
How do I start an activity to show the Marshmallow animation?
I have looked at the AOSP Launcher3 source and only found it to use this:
if (useLaunchAnimation) {
ActivityOptions opts = Utilities.isLmpOrAbove() ?
ActivityOptions.makeCustomAnimation(this, R.anim.task_open_enter, R.anim.no_anim) :
ActivityOptions.makeScaleUpAnimation(v, 0, 0, v.getMeasuredWidth(), v.getMeasuredHeight());
optsBundle = opts.toBundle();
}
Which then get fed into
startActivity(context, optsBundle);
Where the task_open_enter animation looks like this:
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:background="#ff000000"
android:shareInterpolator="false"
android:zAdjustment="top">
<alpha
android:duration="167"
android:fillAfter="true"
android:fillBefore="true"
android:fillEnabled="true"
android:fromAlpha="0"
android:interpolator="#interpolator/decelerate_quart"
android:startOffset="0"
android:toAlpha="1.0" />
<translate
android:duration="417"
android:fillAfter="true"
android:fillBefore="true"
android:fillEnabled="true"
android:fromYDelta="110%"
android:interpolator="#interpolator/decelerate_quint"
android:startOffset="0"
android:toYDelta="0" />
</set>
Unfortunately these are not the same as the Marshmallow animation I am looking for, as shown below:
(gif is slowed down 3 times)
I found the answer in the launcher source code here:
Bundle optsBundle = null;
ActivityOptions opts = null;
if (Utilities.ATLEAST_MARSHMALLOW) {
int left = 0, top = 0;
int width = v.getMeasuredWidth(), height = v.getMeasuredHeight();
// if (v instanceof TextView) {
// // Launch from center of icon, not entire view
// Drawable icon = Workspace.getTextViewIcon((TextView) v);
// if (icon != null) {
// Rect bounds = icon.getBounds();
// left = (width - bounds.width()) / 2;
// top = v.getPaddingTop();
// width = bounds.width();
// height = bounds.height();
// }
// }
opts = ActivityOptions.makeClipRevealAnimation(v, left, top, width, height);
} else if (!Utilities.ATLEAST_LOLLIPOP) {
// Below L, we use a scale up animation
opts = ActivityOptions.makeScaleUpAnimation(v, 0, 0, v.getMeasuredWidth(), v.getMeasuredHeight());
} else if (Utilities.ATLEAST_LOLLIPOP_MR1) {
// On L devices, we use the device default slide-up transition.
// On L MR1 devices, we use a custom version of the slide-up transition which
// doesn't have the delay present in the device default.
opts = ActivityOptions.makeCustomAnimation(context, R.anim.task_open_enter, R.anim.no_anim);
}
optsBundle = opts != null ? opts.toBundle() : null;
context.startActivity(intent, optsBundle);
I'm attempting to rotate an imageView in place while it is not in the middle. I'm using RotateAnimation, and here is my code:
int x = imageView.getLeft();
int y = imageView.getTop();
Animation rotate = new RotateAnimation((float) 0, (float) 359, (float) x, (float) y);
imageView.setAnimation(rotate);
When I do this, the imageView does not rotate in place, instead it rotates around a pivot point off of the screen. However, when I ran it in debugging mode, x and y equated to 300 and 352, which seems right. Can someone explain why the imageView is rotating around some other pivot point instead of the ones I set for it?
create the rotate.xml file in anim folder and use following code
<?xml version="1.0" encoding="UTF-8"?>
<rotate xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="1600"
android:fromDegrees="0"
android:interpolator="#android:anim/linear_interpolator"
android:pivotX="50%"
android:pivotY="50%"
android:repeatCount="infinite"
android:toDegrees="358" />
and in Activity
myImage.startAnimation(AnimationUtils.loadAnimation(MainActivity.this,
R.anim.rotate));
Try this
public static android.graphics.BitmapFactory.Options getSize(Context c, int resId){
android.graphics.BitmapFactory.Options o = new android.graphics.BitmapFactory.Options();
o.inJustDecodeBounds = true;
BitmapFactory.decodeResource(c.getResources(), resId, o);
return o;
}
This returns an Options object that will contain the actual width and height. From an Activity you could use it like this:
ImageView img = (ImageView)findViewById(R.id.yourImageViewId);
Options o = getSize(this, R.drawable.yourImage);
Matrix m = new Matrix();
m.postRotate(angle, o.outWidth/2, o.outHeight/2);
img.setScaleType(ScaleType.MATRIX);
img.setImageMatrix(m);
I am using objectAnimator for animating a button from bottom to top in Android. Now i am using the below code
ObjectAnimator transAnimation = ObjectAnimator.ofFloat(button,"translationY",0,440);
transAnimation.setDuration(440);
transAnimation.start();
I have also tried with sample code below. But still the problem exists
ObjectAnimator transAnimation = ObjectAnimator.ofFloat(loginLayout, "translationY",0f,0.8f);
transAnimation.setDuration(480);
transAnimation.start();
It works fine in large screen devices. But when it comes to small screen devices it goes off the screen. I want to stay it in the top of the screen irrespective of different screen sizes. I think i have to give values in percentage (say 0% to 100% or 0 to 100%p). So my question is how to give values in percentage in objectAnimator in Android. I also noticed one thing that this objectAnimator is introduced only in HoneyComb. So is there any backward compatibility libraries for running it in low versions. Could anyone guide me to find a solution for this.
I also tried extending View and writing getter and setter for the property in offset(). Still it does not move fully to top of screen. Here is the code I have used.
#SuppressLint("NewApi") public float getXFraction()
{
int width = context.getWindowManager().getDefaultDisplay().getHeight();
return (width == 0) ? 0 : (getY());
}
#SuppressLint("NewApi") public void setXFraction(float xFraction) {
int width = context.getWindowManager().getDefaultDisplay().getWidth();
setY((width > 0) ? (width) : 0);
}
Thanks inAdvance
To use ObjectAnimator on pre-Honeycomb devices add NineOldAndroids library to your project and change your imports to use com.nineoldandroids.animation.ObjectAnimator.
To use percentage values in ObjectAnimator instead of getXFraction and setXFraction you have to add getYFraction and setYFraction methods like this
public float getYFraction() {
final WindowManager wm = (WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE);
int height = wm.getDefaultDisplay().getHeight();
return (height == 0) ? 0 : getY() / (float) height;
}
public void setYFraction(float yFraction) {
final WindowManager wm = (WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE);
int height = wm.getDefaultDisplay().getHeight();
setY((height > 0) ? (yFraction * height) : 0);
}
And then you can create xml file project-folder/res/animator/move_bottom.xml like this
<?xml version="1.0" encoding="utf-8"?>
<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="500"
android:propertyName="yFraction"
android:valueFrom="0"
android:valueTo="0.8"
android:valueType="floatType" />
Or create animation in code
final LoginLayout loginLayout = (LoginLayout) findViewById(R.id.login_layout);
final ObjectAnimator oa = ObjectAnimator.ofFloat(loginLayout, "yFraction", 0f, 0.8f);
oa.start();
If you want to create animation from outside of screen with ObjectAnimator. You can do this with Android display size.
#Override
public void onCreate(Bundle savedInstanceState) {
...
sampleImage = BitmapFactory.decodeResource(getResources(), R.drawable.sample);
myImage = (ImageView) findViewById(R.id.image_view);
myImage.setImageBitmap(sampleImage);
//In case API Level is 14 above.
Display display = getWindowManager().getDefaultDisplay();
Point size = new Point();
display.getSize(size);
float displayWidth = size.x;
//In case API Level is 13 below.
//WindowManager wm = (WindowManager) getSystemService(WINDOW_SERVICE);
//Display display = wm.getDefaultDisplay();
//displayWidth = display.getWidth();
animator = ObjectAnimator.ofFloat(myImage, "translationX", displayWidth, 0);
animator.setDuration(500);
}
Sorry, if my suggestion missed the point.
Try using a custom property for ObjectAnimator, instead of creating custom view with custom property, you can create a custom property that accepts a 'fraction':
Property<View, Float> property = new Property<View, Float>(Float.TYPE, "translation_x_fraction") {
#Override public Float get(View view) {
return view.getWidth() <= 0 ? 0 : view.getTranslationX() / view.getWidth();
}
#Override public void set(View view, Float value) {
view.setTranslationX(view.getWidth() * value);
}
}
ObjectAnimator.ofFloat(view, property, 0f, 1f);
I have done this way, I spent too much time but it will save your time.
Arguments:
View (Your support View)
Parent width (Root of your View)
Child width (On which you want to apply Animation)
% (How much percentage you want to move your object or view)
Do not afraid with Arguments, I am explaining here by example.
XML and JAVA code:
activity_main.xml:
<LinearLayout
android:id="#+id/llProgressParent"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_margin="5dp"
android:layout_gravity="center"
android:orientation="horizontal"
android:weightSum="1" >
<View
android:id="#+id/viewSuppot"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="0" >
</View>
<ImageView
android:id="#+id/ivProgressChild"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:src="#drawable/ic_launcher" />
</LinearLayout>
MainActivity.java:
private LinearLayout llProgressParent;
private View viewSuppot;
private ImageView ivProgressChild;
private int childWidth, parentWidth;
private int percentage = 75;
on onCreate():
viewSuppot = findViewById(R.id.viewSuppot);
llProgressParent = (LinearLayout)findViewById(R.id.llProgressParent);
llProgressParent.post(new Runnable() {
#Override
public void run() {
parentWidth = llProgressParent.getMeasuredWidth();
}
});
ivProgressChild = (ImageView)findViewById(R.id.ivProgressChild);
ivProgressChild.post(new Runnable() {
#Override
public void run() {
childWidth = ivProgressChild.getMeasuredWidth();
}
});
Method:
private void animateViewByPercentageOrProgrss(final View view, int parentWidth, int childWidth, int percentage){
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
ValueAnimator anim = ValueAnimator.ofInt(view.getMeasuredWidth(), (int) (((float) percentage * parentWidth) / 100)-(childWidth/2));
anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
#Override
public void onAnimationUpdate(ValueAnimator valueAnimator) {
int val = (Integer) valueAnimator.getAnimatedValue();
ViewGroup.LayoutParams layoutParams = view.getLayoutParams();
layoutParams.width = val;
view.setLayoutParams(layoutParams);
}
});
anim.setDuration(2000);
anim.start();
}
How to call Method:
animateViewByPercentageOrProgrss(viewSuppot, parentWidth, childWidth, percentage);
Its Done.
how about this
Get Y dimen of parent layout then dividing it by 2 and then doing an animation on it ....
int a = parentlayout.getY();
view.animate().setTranslationY(a/2).start();
this one works as you want ....
its my first answer lemme know if it worked or not ..
So Id like to rotate a handful of views all at the same time, all using the same rotation specs. The issue is that for some reason the rotation acts differently for the second element. Apparently this has to do with the animation object actually changing state in between those two lines of code. Obviously I could just create a seperate Animation object and apply it, but I feel like there is an easier way (I have about 15 views)
Rotates only the first view correctly:
Animation rotateAnim = AnimationUtils.loadAnimation(this, R.anim.rotationtoportrait);
target.startAnimation(rotateAnim);
lightBtn.startAnimation(rotateAnim);
Rotates both correctly
Animation rotateAnim = AnimationUtils.loadAnimation(this, R.anim.rotationtoportrait);
Animation rotateAnim2 = AnimationUtils.loadAnimation(this, R.anim.rotationtoportrait);
target.startAnimation(rotateAnim);
lightBtn.startAnimation(rotateAnim2);
XML:
<?xml version="1.0" encoding="utf-8"?>
<rotate
xmlns:android="http://schemas.android.com/apk/res/android"
android:fromDegrees="-90"
android:toDegrees="0"
android:pivotX="50%"
android:pivotY="50%"
android:duration="500" android:fillAfter="true">
Anyone have any ideas?
Do it like this:
ObjectAnimator anim = ObjectAnimator.ofFloat(view, "y", 100f);
arrayListObjectAnimators.add(anim);
ObjectAnimator anim1 = ObjectAnimator.ofFloat(view, "x", 0f);
arrayListObjectAnimators.add(anim1);
ObjectAnimator[] objectAnimators = arrayListObjectAnimators.toArray(new ObjectAnimator[arrayListObjectAnimators.size()]);
AnimatorSet animSetXY = new AnimatorSet();
animSetXY.playTogether(objectAnimators);
animSetXY.duration(1000);
animSetXY.start();
So I guess this just isn't possible, so I created a helper method to just apply the same animation to a list of views:
public void doRotations(ArrayList<View> views, int start, int end, int xprop, float xscale, int yprop, float yscale, int duration, Boolean fillAfter){
for(int i = 0; i < views.size(); i++){
RotateAnimation temp = new RotateAnimation(start, end, xprop, xscale, yprop, yscale);
temp.setDuration(duration);
temp.setFillAfter(fillAfter);
views.get(i).startAnimation(temp);
}
}
Definitely a hack, but I guess thats all I'm able to do right now
I was able to do this in Kotlin by programmatically creating one AnimatorSet.
1. Create an ArrayList of the views you want to animate
var viewList = arrayListOf(view1,view2,view3)
2. Loop through the ArrayList and create a growing AnimatorSet
var ix = 0
var anim = AnimatorSet()
var viewList = arrayListOf(view1,view2,view3)
viewList.forEach{
// Initiate the animator set with one ObjectAnimator
if(ix == 0){
anim = AnimatorSet().apply {
play(ObjectAnimator.ofFloat(it, "rotation", 0F, 360F))
}
}
// Add one ObjectAnimator at a time to the growing AnimatorSet
else{
var currentAnim = ObjectAnimator.ofFloat(it,"rotation",0F,360F)
anim = AnimatorSet().apply {
play(anim).with(currentAnim)
}
}
ix++
}
3. Start the animation
button.setOnClickListener {
AnimatorSet().apply {
play(anim)
start()
}