Here is my code to translate imageview in X direction(from left to right).
final Animation animTrans = new TranslateAnimation(0f, 1f, 0f, 0f);
animTrans.setRepeatCount(0);
animTrans.setDuration(200);
animTrans.setFillAfter(true);
circleImage.startAnimation(animTrans);
When it starts to translate the image is displaced in y axis. Here is a picture of what happpens.
But when i use an xml to translate everything works fine. What is the problem with my code ?
Xml:
<translate
android:fromXDelta="0%p"
android:toXDelta="80%p"
android:duration="200"
android:fillAfter="true"
/>
I can't understand why, but
circleImage.animate().
translationXBy(width).
setDuration(200).
start();
solved my problem. I think maybe its a problem with final Animation animTrans = new TranslateAnimation(0f, 1f, 0f, 0f);. Those xdelta, ydelta values may be the reason.
Related
I am trying to figure out how to animate an image from left to right, and then from right to left.
For example imagine the following image:
At full resolution, the width of the image would exceed the width of the screen. So initially, only the left side of the image should be visible, but as the animation is running, slowly the right side becomes visible, eg.:
Once the right side of the image was fully uncovered, the animation starts in reverse:
Any ideas how to achieve this?
Android APIs or any techniques would be of great help.
Using ObjectAnimator.
Well, I didn't really know, how to size image in without cropping, so I made view's width 1000dp.
Here is solution:
ImageView imageView = findViewById(R.id.imageView);
imageView.post(() -> {
Point point = new Point();
getWindowManager().getDefaultDisplay().getSize(point);
float width = imageView.getMeasuredWidth();
ObjectAnimator objectAnimator = ObjectAnimator.ofFloat(imageView, "translationX", 0, -(width - point.x));
objectAnimator.setRepeatMode(ValueAnimator.REVERSE);
objectAnimator.setRepeatCount(ValueAnimator.INFINITE);
objectAnimator.setDuration(10000);
objectAnimator.start();
});
Let me explain.
First, I get size of device.
Point point = new Point();
getWindowManager().getDefaultDisplay().getSize(point);
Then, I get width of view and creating ObjectAnimator
float width = imageView.getMeasuredWidth();
ObjectAnimator objectAnimator = ObjectAnimator.ofFloat(imageView, "translationX", 0, -(width - point.x));
First argument is a view, that will be animated. Second argument tells objectAnimator what method (in this case setter) to use. We use translationX, so objectAnimator use setTranslationX().
All other arguments tells objectAnimator from where to where it should animate.
We substracting point.x from width for animation stops when edge of image is shown. Else, imageView will slide to the left until image disappears.
For example:
ObjectAnimator.ofFloat(imageView, "translationX", 0, 200, 100, 300);
says that image should go by axis X to the point 0, then 200, then 100 and in the end 300.
objectAnimator.setRepeatMode(ValueAnimator.REVERSE);
tells that after animation done, do it again, but in reverse.
objectAnimator.setRepeatCount(ValueAnimator.INFINITE);
tells that animation must repeat itself infinitely.
objectAnimator.setDuration(10000);
Duration of the animation in milliseconds.
Try with TranslateAnimation:
First, you have to know how big is the view:
ImageView picture = findViewById(R.id.picture);
int pictureWidth = picture.getWidth();
private void animation(View view, float pictureWidth) {
Animation offSet = new TranslateAnimation(0, - moveTo, 0, 0);
offSet.setInterpolator(new AccelerateDecelerateInterpolator()); // just to make a smooth movement
offSet.setDuration(durationInMillis);
}
The code above will move to the left showing the right side of the image,
you can add something similar to reverse the movement.
There are for sure better and more complete solutions, this is just (I think) the easier.
I'm trying to do a shake animation. It works well when I do it in XML, like this:
<set xmlns:android="http://schemas.android.com/apk/res/android">
<rotate
android:duration="50"
android:fromDegrees="-0.02"
android:pivotX="50%"
android:pivotY="50%"
android:repeatCount="30"
android:repeatMode="reverse"
android:interpolator="#android:anim/linear_interpolator"
android:toDegrees="0.02" />
<translate
android:fromXDelta="-0.02"
android:toXDelta="0.02"
android:repeatCount="30"
android:repeatMode="reverse"
android:interpolator="#android:anim/linear_interpolator"
android:duration="50" />
</set>
But I want to do it using ObjectAnimator, so I'll be able to use AnimatorSet to play this animation at the same time of other animations I've done.
I tried to do it like that:
val pvhR = PropertyValuesHolder.ofFloat(View.ROTATION, -0.05f, 0.05f)
val pvhT = PropertyValuesHolder.ofFloat(View.TRANSLATION_X, -0.05f, 0.05f)
val rotate = ObjectAnimator.ofPropertyValuesHolder(imageView, pvhR). apply {
duration = 50
repeatCount = 20
repeatMode = ValueAnimator.REVERSE
}
val translate = ObjectAnimator.ofPropertyValuesHolder(imageView, pvhT).apply {
duration = 50
repeatCount = 20
repeatMode = ValueAnimator.REVERSE
}
But the translate animation makes my imageView disappear. I had problems with rotation animations before (when I tried to do rotation animation, the imageView changed its position, but I fixed it by using .ofPropertyValuesHolder, instead of using .ofFloat). Probably because I'm using a custom library that implements a zoomable/pinchable layout.
Now I'm trying to do this translate animation, but it doesn't works even with .ofPropertyValuesHolderz. It's working only with XML, but as I said, I can't put it inside an AnimatorSet().
Try this code
val set = AnimatorSet()
val rotation = ObjectAnimator.ofFloat(imageViewMain, "rotation", -0.05f, 0.05f).apply {
duration = 50
repeatCount = 20
repeatMode = ValueAnimator.REVERSE
}
val translation = ObjectAnimator.ofFloat(imageViewMain, "translationX", -0.05f, 0.05f).apply {
duration = 50
repeatCount = 20
repeatMode = ValueAnimator.REVERSE
}
set.playTogether(rotation, translation)
I have two questions:
I have an imageview that when I touch it I send it to an (X,Y) position. I have an S4 and a Galaxy Note 3 both with resolution (1920x1080) and density xxhdpi.
When i test them, i notice the imageView in different devices not send to same position. In Galaxy note the imageView is more to the right and above... why is this happening? have the same resolution and belongs to same density (xxhdpi)!
And how can i fix this for this example and all the screens?
Here is my XML code
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="#drawable/fondo_jugar"
tools:context="com.trucouruguayo.JugarActivity" >
<ImageView
android:id="#+id/imageViewCard1"
android:layout_width="101dp"
android:layout_height="142.50dp"
android:layout_alignLeft="#+id/imageViewMazo"
android:layout_alignTop="#+id/imageViewMazo"
android:layout_marginRight="-50dp"
android:contentDescription="#string/imageViewDescriptionCartd1"
android:src="#drawable/reverso"
android:scaleType="fitXY" />
<ImageView
android:id="#+id/imageViewCard2"
android:layout_width="101dp"
android:layout_height="142.50dp"
android:layout_alignLeft="#+id/imageViewMazo"
android:layout_alignTop="#+id/imageViewMazo"
android:layout_marginRight="-50dp"
android:contentDescription="#string/imageViewDescriptionCard2"
android:src="#drawable/reverso"
android:tag="imageViewCarta1"
android:scaleType="fitXY" />
...
</<RelativeLayout >
And this is the method that move the card:
Point point1 = new Point(-1460, 20);
/*Tira la carta al a mesa (sea de la maquina o del jugador)*/
private void tirarCartaALaMesa(View view, List<Carta> cartas, boolean tiraMaquina) {
cartas.remove(obtenerCartaFromView(view, cartas));
listaImageViewsTiradas.add(view);
indiceOrdenCartas ++;
animSetXY = new AnimatorSet();
ObjectAnimator scaleDownX = ObjectAnimator.ofFloat(view, "scaleX", 0.8f);
ObjectAnimator scaleDownY = ObjectAnimator.ofFloat(view, "scaleY", 0.8f);
ObjectAnimator rotation;
objectX = ObjectAnimator.ofFloat(view, "translationX", point1.x);
objectY = ObjectAnimator.ofFloat(view, "translationY", point1.y);
animSetXY.setInterpolator(new LinearInterpolator());
animSetXY.setDuration(500);
animSetXY.start();
}
Another question I realized is why point1 have to set (-1460, 20) to be in the top left corner and not for example (20,20). I think is because it tooks the (0,0) from the views position. Its a posibility to change that?
Greets
To solve this problem I calculated the X and Y co-ordinates programatically by using DisplayMetrics class like this:
DisplayMetrics metrics= new DisplayMetrics();
Display display = ((WindowManager) getSystemService(WINDOW_SERVICE)).getDefaultDisplay();
display.getMetrics(metrics);
int x=metrics.widthPixels/2; //2 can be changed according to the need
int y=metrics.heightPixels/2; //2 can be changed according to the need
And then You can make the image view appear at that coordinate.
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);
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()
}