Skip to content Skip to sidebar Skip to footer

Android: ImageView Rotation Animation - Keep Scale Type Fit Center

I have an ImageView that has android:scaleType='fitCenter' Copy

Instead of

 iv.animate().rotationBy(90f).start();

two more update take android:configChanges like that

 <activity
        android:name=".youactivity"
        android:label="@string/app_name"

        android:configChanges="keyboard|keyboardHidden|orientation|screenLayout|uiMode|screenSize|smallestScreenSize"
        >

android:adjustViewBounds true to imageview

  <ImageView
    android:id="@+id/iv"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:scaleType="fitCenter"
    android:layout_centerInParent="true"
    android:adjustViewBounds="true"
    android:src="@mipmap/android"/>

Solution 2:

My Solution is not elegant (i am a noob in developing) I hope someone can provide a better solution ....

    int h,w;
    Boolean safe=true;

Getting the parameters of imageView is not possible at initialisation of activity To do so please refer to this solution OR set the dimensions at onClick of a Button Like this

    rotateButton.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            if(imageView.getRotation()/90%2==0){
                h=imageView.getHeight();
                w=imageView.getWidth();

            }
        .
        .//Insert the code Snippet below here 
       }

And the code to be run when we want to rotate ImageView

if(safe)     
imageView.animate().rotationBy(90).scaleX(imageView.getRotation()/90%2==0?(w*1.0f/h):1).scaleY(imageView.getRotation()/90%2==0?(w*1.0f/h):1).setDuration(2000).setInterpolator(new LinearInterpolator()).setListener(new Animator.AnimatorListener() {
                @Override
                public void onAnimationStart(Animator animation) {
                      safe=false;
                }

                @Override
                public void onAnimationEnd(Animator animation) {
                      safe=true;

                }

                @Override
                public void onAnimationCancel(Animator animation) {

                }

                @Override
                public void onAnimationRepeat(Animator animation) {

                }
            }).start();
        }
    });

This solution is sufficient for the Problem above.Although it will shrink the imageView even if it is not necessary(when height is smaller than Width).If it bothers you,you can add another ternary operator inside scaleX/scaleY.


Solution 3:

To do this follow these steps:

  1. set scaleType to matrix:
 <ImageView ...
    android:scaleType="matrix"/>
  1. In onCreate, load image into imageview and set rotate button onClick listener:
imageView.post(new Runnable() {
            @Override
            public void run() {
                Bitmap bitmap= BitmapFactory.decodeResource(getResources(),R.drawable.dummy);


           imageView.setImageBitmap(bitmap);

            if (bitmap.getWidth() > 0) {

                float scale = ((float)imageView.getMeasuredWidth())/((float)imageView.getDrawable().getIntrinsicWidth());

                imageView.getLayoutParams().height = (int)(scale * imageView.getDrawable().getIntrinsicHeight());
                imageView.setImageMatrix(scaleMatrix(scale, scale));
            }
        }
    });

And

btnRotate.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
              animateImageHeight(imageView,btnRotate);
            }
        });
  1. Add the animateImageHeight method in the activity:

void animateImageHeight(final ImageView imageView, final Button btnRotate){

    final float drawableWidth = imageView.getDrawable().getIntrinsicWidth();
    final float drawableHeight = imageView.getDrawable().getIntrinsicHeight();
    float viewWidth = imageView.getMeasuredWidth();
    final float viewHeight = imageView.getMeasuredHeight();
    final int rotation = imageRotation % 360;
    final int newRotation = (rotation + 90);

    final int newViewHeight;
    final float imageScale;
    final float newImageScale;

    if (rotation==0 || rotation==180)
    {
        imageScale = viewWidth / drawableWidth;
        newImageScale = viewWidth / drawableHeight;
        newViewHeight = (int)(drawableWidth * newImageScale);
    }
    else if (rotation==90 || rotation==270){
        imageScale = viewWidth / drawableHeight;
        newImageScale = viewWidth / drawableWidth;
        newViewHeight = (int)(drawableHeight * newImageScale);
    }
    else{
        throw new UnsupportedOperationException("rotation can 0, 90, 180 or 270. ${rotation} is unsupported");
    }


    ValueAnimator animator= ValueAnimator.ofFloat(0f,1f) .setDuration(1000L);



    animator.setInterpolator(new AccelerateDecelerateInterpolator());

    animator.addListener(new Animator.AnimatorListener() {
        @Override
        public void onAnimationStart(Animator animator) {
            btnRotate.setEnabled(false);
        }

        @Override
        public void onAnimationEnd(Animator animator) {
            imageRotation = newRotation % 360;
            btnRotate.setEnabled(true);
        }

        @Override
        public void onAnimationCancel(Animator animator) {

        }

        @Override
        public void onAnimationRepeat(Animator animator) {

        }
    });

    animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
        @Override
        public void onAnimationUpdate(ValueAnimator animation) {
            float animVal = (float)animation.getAnimatedValue();
            float complementaryAnimVal = 1 - animVal;

            int animatedHeight =
                    (int)(complementaryAnimVal * viewHeight + animVal * newViewHeight);
            float animatedScale =
                    (complementaryAnimVal * imageScale + animVal * newImageScale);
            float animatedRotation =
                    (complementaryAnimVal * rotation + animVal * newRotation);


            imageView.getLayoutParams().height=animatedHeight;

            Matrix matrix=
                    rotationMatrix(
                    animatedRotation,
                    drawableWidth / 2,
                    drawableHeight / 2
            );

            matrix.postScale(
                    animatedScale,
                    animatedScale,
                    drawableWidth / 2,
                    drawableHeight / 2);
            matrix.postTranslate(-(drawableWidth - imageView.getMeasuredWidth())/2, -(drawableHeight - imageView.getMeasuredHeight())/2);

            imageView.setImageMatrix(matrix);

            imageView.requestLayout();
        }
    });

    animator.start();
}

You can find the kotlin version and the complete demonstration here.


Solution 4:

try:

<?xml version="1.0" encoding="utf-8"?>
<layout>

    <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context=".MainActivity">

        <ImageView
            android:id="@+id/image"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:src="@drawable/pic"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintLeft_toLeftOf="parent"
            app:layout_constraintRight_toRightOf="parent"
            app:layout_constraintTop_toTopOf="parent" />
    </androidx.constraintlayout.widget.ConstraintLayout>
</layout>
    private lateinit var binding: ActivityMainBinding
    private var scale = 1F
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = DataBindingUtil.setContentView(this, R.layout.activity_main)
        //Change to your own calculation logic to calculate the zoom factor
        val outMetrics = DisplayMetrics()
        windowManager.getDefaultDisplay().getRealMetrics(outMetrics)
        val w = outMetrics.widthPixels
        val h = outMetrics.heightPixels
        scale = if (w > h) w.toFloat() / h.toFloat() else h.toFloat() / w.toFloat()
        binding.image.scaleX = scale
        binding.image.scaleY = scale
    }

    fun set() {
        sfRotation = (sfRotation + 90) % 360
        Log.d(">>>sfRotation", sfRotation.toString())
        Log.d(">>>hwrotation", hwRotation.toString())
        binding.image.rotation = sfRotation.toFloat()
        binding.image.scaleX = scale
        binding.image.scaleY = scale
    }

Post a Comment for "Android: ImageView Rotation Animation - Keep Scale Type Fit Center"