Android: ImageView Rotation Animation - Keep Scale Type Fit Center
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:
- set
scaleType
to matrix:
<ImageView ...
android:scaleType="matrix"/>
- 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);
}
});
- 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"