Android: поворот изображения в режиме просмотра изображения на угол

Я использую следующий код, чтобы повернуть изображение в ImageView на угол. Есть ли более простой и менее сложный метод?

ImageView iv = (ImageView)findViewById(imageviewid);
TextView tv = (TextView)findViewById(txtViewsid);
Matrix mat = new Matrix();
Bitmap bMap = BitmapFactory.decodeResource(getResources(),imageid);
mat.postRotate(Integer.parseInt(degree));===>angle to be rotated
Bitmap bMapRotate = Bitmap.createBitmap(bMap, 0, 0,bMap.getWidth(),bMap.getHeight(), mat, true);
iv.setImageBitmap(bMapRotate);

29 ответов

Решение

Еще один простой способ повернуть ImageView:
ОБНОВИТЬ:
Требуемый импорт:

import android.graphics.Matrix;
import android.widget.ImageView;

Код: (при условии imageView, angle, pivotX & pivotY уже определены)

Matrix matrix = new Matrix();
imageView.setScaleType(ImageView.ScaleType.MATRIX);   //required
matrix.postRotate((float) angle, pivotX, pivotY);
imageView.setImageMatrix(matrix);

Этот метод не требует создания нового растрового изображения каждый раз.

ПРИМЕЧАНИЕ. Чтобы повернуть ImageView ontouch во время выполнения вы можете установить onTouchListener на ImageView & поверните его, добавив две последние строки (т.е. матрицу postRotate и установите ее на imageView) в разделе кода выше в части ACTION_MOVE слушателя касания.

mImageView.setRotation(angle) с API>=11

Если вы поддерживаете API 11 или выше, вы можете просто использовать следующий атрибут XML:

android:rotation="90"

Он может отображаться некорректно в предварительном просмотре XML для Android Studio, но работает должным образом.

Есть два способа сделать это:

1 Использование Matrix создать новое растровое изображение:

imageView = (ImageView) findViewById(R.id.imageView);
Bitmap myImg = BitmapFactory.decodeResource(getResources(), R.drawable.image);

Matrix matrix = new Matrix();
matrix.postRotate(30);

Bitmap rotated = Bitmap.createBitmap(myImg, 0, 0, myImg.getWidth(), myImg.getHeight(),
        matrix, true);

imageView.setImageBitmap(rotated);

2 использования RotateAnimation на View Вы хотите повернуть, и убедитесь, что анимация установлена ​​на fillAfter=true, duration=0, а также fromDegrees=toDgrees

 <?xml version="1.0" encoding="utf-8"?>
<rotate
  xmlns:android="http://schemas.android.com/apk/res/android"
  android:fromDegrees="45"
  android:toDegrees="45"
  android:pivotX="50%"
  android:pivotY="50%"
  android:duration="0"
  android:startOffset="0"
/>

и надуйте анимацию в коде:

Animation rotation = AnimationUtils.loadAnimation(this, R.anim.rotation);
myView.startAnimation(rotation);

Я знаю, что это безумно поздно, но это было полезно для меня, так что это может помочь другим.

Начиная с API 11, вы можете программно установить абсолютное вращение ImageView, используя imageView.setRotation(angleInDegrees); метод.

Под абсолютным я имею в виду, что вы можете многократно вызывать эту функцию, не отслеживая текущее вращение. Смысл, если я поворачиваю мимо 15F к setRotation() метод, а затем вызвать setRotation() снова с 30FПоворот изображения с 30 градусов, а не 45 градусов.

Примечание. Это действительно работает для любого подкласса объекта View, а не только для ImageView.

Для Котлина,

mImageView.rotation = 90f //angle in float

Это будет вращать imageView, а не изображение

Кроме того, хотя это метод в Viewучебный класс. Таким образом, с его помощью вы можете практически повернуть любой вид.

Поворот изображения в Android с задержкой:

imgSplash.animate().rotationBy(360f).setDuration(3000).setInterpolator(new LinearInterpolator()).start();

Также можно сделать так:

imageView.animate().rotation(180).start();

получил отсюда

Это моя реализация RotatableImageView. Использовать очень просто: просто скопируйте attrs.xml и RotatableImageView.java в ваш проект и добавьте RotatableImageView в свой макет. Установите желаемый угол поворота, используя пример: параметр угла.

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:example="http://schemas.android.com/apk/res/com.example"
    android:layout_width="match_parent"
    android:layout_height="wrap_content">

    <com.example.views.RotatableImageView
        android:id="@+id/layout_example_image"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:adjustViewBounds="true"
        android:scaleType="fitCenter"
        android:src="@drawable/ic_layout_arrow"
        example:angle="180" />
</FrameLayout>

Если у вас возникли проблемы с отображением изображения, попробуйте изменить код в методе RotatableImageView.onDraw() или используйте метод draw().

Кроме того, если вы хотите повернуть ImageView на 180 градусов по вертикали или горизонтали, вы можете использовать scaleY или же scaleX свойства и установите их -1f, Вот пример Kotlin:

imageView.scaleY = -1f
imageView.scaleX = -1f

1f значение используется для возврата ImageView в его нормальное состояние:

imageView.scaleY = 1f
imageView.scaleX = 1f

Вы можете просто использовать атрибут вращения ImageView

Ниже приведен атрибут из ImageView с подробной информацией из источника Android.

<!-- rotation of the view, in degrees. -->
<attr name="rotation" format="float" />

Я думаю, что лучший способ:)

int angle = 0;
imageView.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            angle = angle + 90;
            imageView.setRotation(angle);
        }
    });

У меня есть решение этого. На самом деле это решение проблемы, возникающей после поворота (прямоугольное изображение не подходит для ImagView), но оно также охватывает и вашу проблему. Хотя в этом решении есть анимация к лучшему или к худшему

    int h,w;
    Boolean safe=true;

Получение параметров imageView невозможно при инициализации действия. Для этого, пожалуйста, обратитесь к этому решениюИЛИ установите размеры в onClick of a Button Вот так

    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 
       }

И код для запуска, когда мы хотим повернуть 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();
        }
    });

Этого решения достаточно для указанной выше Задачи. Хотя оно уменьшит изображение, даже если в этом нет необходимости (если высота меньше, чем Ширина). Если это вас беспокоит, вы можете добавить еще один троичный оператор внутри scaleX/scaleY.

Вот хорошее решение для размещения повернутого рисованного для imageView:

Drawable getRotateDrawable(final Bitmap b, final float angle) {
    final BitmapDrawable drawable = new BitmapDrawable(getResources(), b) {
        @Override
        public void draw(final Canvas canvas) {
            canvas.save();
            canvas.rotate(angle, b.getWidth() / 2, b.getHeight() / 2);
            super.draw(canvas);
            canvas.restore();
        }
    };
    return drawable;
}

использование:

Bitmap b=...
float angle=...
final Drawable rotatedDrawable = getRotateDrawable(b,angle);
root.setImageDrawable(rotatedDrawable);

другая альтернатива:

private Drawable getRotateDrawable(final Drawable d, final float angle) {
    final Drawable[] arD = { d };
    return new LayerDrawable(arD) {
        @Override
        public void draw(final Canvas canvas) {
            canvas.save();
            canvas.rotate(angle, d.getBounds().width() / 2, d.getBounds().height() / 2);
            super.draw(canvas);
            canvas.restore();
        }
    };
}

Кроме того, если вы хотите повернуть растровое изображение, но боитесь OOM, вы можете использовать решение NDK, которое я сделал здесь

Слишком поздно для ответа, кто-то может найти это полезным, я столкнулся с ситуацией, когда мне нужно анимировать вращение og ImageViewнекоторыми angleна первом событии, а потом на втором ClickListenerсобытие, нужно rotateвернуть изображение в исходный угол. Вот как это волшебство произошло

      fun rotateAnim(imageView: ImageView,angle : Float){
    imageView.isEnabled = false
    Log.i(TAG, "onCreate: ${imageView.rotation}")
    val rotation = imageView.animate().rotationBy(angle)
    rotation.interpolator = FastOutSlowInInterpolator()
    rotation.startDelay = 200
    rotation.setListener(object : Animator.AnimatorListener{
        override fun onAnimationEnd(animation: Animator?) {
           imageView.isEnabled = true
        }
        override fun onAnimationStart(animation: Animator?) {}
        override fun onAnimationCancel(animation: Animator?) {}
        override fun onAnimationRepeat(animation: Animator?) {}

    })
    rotation.start()
}

и реализация похожа

      holder.itemView.setOnClickListener {
    val rotation = imageView.rotation
    if(rotation == 180F){
         rotateAnim(imageView,90F)
    }else{
         rotateAnim(imageView,-90F)
    }
}

К сожалению, я не думаю, что есть. Matrix класс отвечает за все манипуляции с изображениями, будь то вращение, сжатие / увеличение, наклон и т. д.

http://developer.android.com/reference/android/graphics/Matrix.html

Мои извинения, но я не могу придумать альтернативы. Может быть, кто-то еще сможет, но когда мне приходилось манипулировать изображением, я использовал Матрицу.

Удачи!

Если вы хотите повернуть вид только визуально, вы можете использовать:

iv.setRotation(float)

Попробуйте это в пользовательском представлении

public class DrawView extends View {


    public DrawView(Context context,AttributeSet attributeSet){
        super(context, attributeSet);
    }

    @Override
    public void onDraw(Canvas canvas) {
        /*Canvas c=new Canvas(BitmapFactory.decodeResource(getResources(), R.drawable.new_minute1)    );

        c.rotate(45);*/

        canvas.drawBitmap(BitmapFactory.decodeResource(getResources(), R.drawable.new_minute1), 0, 0, null);
        canvas.rotate(45);
    }
}

Просто напишите это в своей активности

            Bitmap yourSelectedImage= BitmapFactory.decodeFile(filePath);
            Matrix mat = new Matrix();
            mat.postRotate((270)); //degree how much you rotate i rotate 270
            Bitmap bMapRotate=Bitmap.createBitmap(yourSelectedImage, 0,0,yourSelectedImage.getWidth(),yourSelectedImage.getHeight(), mat, true);
            image.setImageBitmap(bMapRotate);
            Drawable d=new BitmapDrawable(yourSelectedImage);
            image.setBackground(d); 

Если вы хотите повернуть изображение на 180 градусов, поместите эти два значения в тег imageview:-

android:scaleX="-1"
android:scaleY="-1"

Объяснение:- scaleX = 1 и scaleY = 1, это нормальное состояние, но если мы поместим -1 в свойство scaleX/scaleY, то оно будет повернуто на 180 градусов.

Использование Котлина:

      imageView.rotation = degrees.toFloat()

Без матрицы и анимации:

{
    img_view = (ImageView) findViewById(R.id.imageView);
    rotate = new RotateAnimation(0 ,300);
    rotate.setDuration(500);
    img_view.startAnimation(rotate);
}

Другое возможное решение - создать свой собственный вид изображения (скажем, RotateableImageView extends ImageView)... и переопределите onDraw(), чтобы повернуть холст / растровые изображения перед воспроизведением на холст. Не забудьте восстановить холст обратно.

Но если вы собираетесь вращать только один экземпляр изображения, ваше решение должно быть достаточно хорошим.

Вместо того, чтобы конвертировать изображение в растровое изображение, а затем повернуть его, попробуйте повернуть прямой вид изображения, как показано ниже.

ImageView myImageView = (ImageView)findViewById(R.id.my_imageview);

AnimationSet animSet = new AnimationSet(true);
animSet.setInterpolator(new DecelerateInterpolator());
animSet.setFillAfter(true);
animSet.setFillEnabled(true);

final RotateAnimation animRotate = new RotateAnimation(0.0f, -90.0f,
    RotateAnimation.RELATIVE_TO_SELF, 0.5f, 
    RotateAnimation.RELATIVE_TO_SELF, 0.5f);

animRotate.setDuration(1500);
animRotate.setFillAfter(true);
animSet.addAnimation(animRotate);

myImageView.startAnimation(animSet);
Matrix matrix = new Matrix();
imageView.setScaleType(ImageView.ScaleType.MATRIX); //required
matrix.postRotate((float) 20, imageView.getDrawable().getBounds().width()/2, imageView.getDrawable().getBounds().height()/2);
imageView.setImageMatrix(matrix);

как использовать?

public class MainActivity extends AppCompatActivity {
   int view = R.layout.activity_main;
   TextView textChanger;
   ImageView imageView;
   @RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN)
   @Override
   protected void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
      setContentView(view);
      textChanger = findViewById(R.id.textChanger);
      imageView=findViewById(R.id.imageView);
      textChanger.setOnClickListener(new View.OnClickListener() {
         @Override
         public void onClick(View v) {
            roateImage(imageView);
         }
      });
   }
   private void roateImage(ImageView imageView) {
      Matrix matrix = new Matrix();
      imageView.setScaleType(ImageView.ScaleType.MATRIX); //required
      matrix.postRotate((float) 20, imageView.getDrawable().getBounds().width()/2,    imageView.getDrawable().getBounds().height()/2);
      imageView.setImageMatrix(matrix);
   }
}

Следуйте приведенному ниже ответу для непрерывного вращения изображения.

int i=0;

Если кнопка поворота нажата

imageView.setRotation(i+90);
i=i+90;

Попробуйте этот код на 100% работающий;

Нажмите кнопку поворота и напишите этот код:

        @Override
        public void onClick(View view) {
            if(bitmap==null){
                Toast.makeText(getApplicationContext(), "Image photo is not yet set", Toast.LENGTH_LONG).show();
            }
            else {
                Matrix matrix = new Matrix();
                ivImageProduct.setScaleType(ImageView.ScaleType.MATRIX);   //required
                matrix.postRotate(90,ivImageProduct.getDrawable().getBounds().width()/2,ivImageProduct.getDrawable().getBounds().height()/2);
                Bitmap bmp=Bitmap.createBitmap(bitmap, 0, 0,bitmap.getWidth(), bitmap.getHeight(), matrix, true);
                bitmap.recycle();
                bitmap=bmp;
                ivImageProduct.setImageBitmap(bitmap);
            }
        }

Я добавил несколько решений. Если вы хотите повернуть изображение при нажатии кнопки, размер изображения должен соответствовать родительскому макету. Вы также можете использовать https://github.com/rongi/rotate-layout и /questions/15781854/android-animatsiya-vrascheniya-imageview-derzhite-tip-masshtaba-po-tsentru/15781857#15781857 этот код также работает.

              ImageView photoView = findViewById(R.id.photo_view);
        ImageView rotateBtn = findViewById(R.id.rotate_image);
        FrameLayout photoFrame = dialogView.findViewById(R.id.photoFrame);

        final float[] currentRotation = {0f};
        final boolean[] isFirst = {true};
        final boolean[] isInitial = {true};
        final float[] firstWidth = {0};
        final float[] firstHeight = {0};
        final float[] secondWidth = {0};
        final float[] secondHeight = {0};

        rotate_image.setOnClickListener(view -> {
            if (isInitial[0]) {
                isInitial[0] = false;

                firstWidth[0] = photoView.getWidth();
                firstHeight[0] = photoView.getHeight();

                float frameWidth = photoFrame.getWidth();
                float frameHeight = photoFrame.getHeight();

                if (firstHeight[0] >= firstWidth[0]) {
                    float imageRatio = firstHeight[0] / firstWidth[0];
                    if (frameHeight > frameWidth) {
                        secondWidth[0] = frameWidth;
                        secondHeight[0] = secondWidth[0] / imageRatio;
                    } else {
                        secondHeight[0] = frameHeight;
                        secondWidth[0] = secondHeight[0] * imageRatio;
                    }
                } else {
                    float imageRatio = firstWidth[0] / firstHeight[0];
                    float frameRatio = frameHeight / frameWidth;
                    if (imageRatio >= frameRatio) {
                        secondHeight[0] = frameHeight;
                        secondWidth[0] = secondHeight[0] / imageRatio;
                    } else {
                        secondWidth[0] = frameWidth;
                        secondHeight[0] = secondWidth[0] * imageRatio;
                    }
                }
            }

            float imageWidth = isFirst[0] ? secondWidth[0] : firstHeight[0];
            float imageHeight = isFirst[0] ? secondHeight[0] : firstWidth[0];
            
            isFirst[0] = !isFirst[0];
        // You can use custom animation
        //Animation rotateAnimation = new RotateAnimation(currentRotation, 
        //currentRotation -= 90, Animation.RELATIVE_TO_SELF, 0.5f, 
        //Animation.RELATIVE_TO_SELF, 0.5f);
        //rotateAnimation.setDuration(100);
        //rotateAnimation.setFillAfter(true);
        //photoView.startAnimation(rotateAnimation);

            photoView.animate().rotation(currentRotation[0] -= 90).start();
            photoView.getLayoutParams().height = (int) imageWidth;
            photoView.getLayoutParams().width = (int) imageHeight;
            photoView.requestLayout();
        });

Мой XML-код ниже:

      <?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

  <FrameLayout
      android:id="@+id/photoFrame"
      android:layout_width="match_parent"
      android:layout_height="0dp"
      android:layout_marginVertical="10dp"
      app:layout_constraintBottom_toTopOf="@+id/rotate_image"
      app:layout_constraintEnd_toEndOf="parent"
      app:layout_constraintStart_toStartOf="parent"
      app:layout_constraintTop_toTopOf="parent" >

      <ImageView
          android:id="@+id/photo_view"
          android:layout_width="wrap_content"
          android:layout_height="wrap_content"
          android:layout_gravity="center"
          android:adjustViewBounds="true"
          android:scaleType="fitCenter"
          android:src="@mipmap/ic_client_photo_nophoto" />
  </FrameLayout>

    <ImageView
        android:id="@+id/rotate_image"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:src="@drawable/rotate_image"
        android:layout_marginBottom="10dp"

        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent" />


</androidx.constraintlayout.widget.ConstraintLayout>

Я сделал другое решение без анимации, и оно работало с файлом изображения:

          ImageView photoView = findViewById(R.id.photo_view);
    ImageView rotate_image = findViewById(R.id.rotate_image);

    Glide.with(context)
            .load(file)
            .diskCacheStrategy(DiskCacheStrategy.NONE)
            .skipMemoryCache(true)
            .into(photoView);
    
    rotate_image.setOnClickListener(view -> {
        rotateImageFile(file.getPath());
        Glide.with(context)
                .load(file)
                .diskCacheStrategy(DiskCacheStrategy.NONE)
                .skipMemoryCache(true)
                .into(photoView);

    });

public void rotateImageFile(String imagePath) {
    try {
        ExifInterface exif = new ExifInterface(imagePath);
        int orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, 1);

        switch (orientation) {
            case 1:
                exif.setAttribute(ExifInterface.TAG_ORIENTATION, String.valueOf(ExifInterface.ORIENTATION_ROTATE_90));
                break;
            case 6:
                exif.setAttribute(ExifInterface.TAG_ORIENTATION, String.valueOf(ExifInterface.ORIENTATION_ROTATE_180));
                break;
            case 3:
                exif.setAttribute(ExifInterface.TAG_ORIENTATION, String.valueOf(ExifInterface.ORIENTATION_ROTATE_270));
                break;
            case 8:
                exif.setAttribute(ExifInterface.TAG_ORIENTATION, String.valueOf(ExifInterface.ORIENTATION_NORMAL));
                break;
        }
        exif.saveAttributes();
    } catch (Exception e) {
        e.printStackTrace();
    }
}

Другое решение работает с растровым изображением, но без анимации качество может ухудшиться, а вращение может быть не плавным, проверьте.

      ImageView photoView = findViewById(R.id.photo_view);
ImageView rotate_image = findViewById(R.id.rotate_image);
final Bitmap[] bitmap = {BitmapFactory.decodeFile(file.getPath())};
//If you dont use file add this code inside of setOnClickListener
//bitmap[0] =((BitmapDrawable) photoView.getDrawable()).getBitmap();

    rotate_image.setOnClickListener(view -> {
    //bitmap[0] =((BitmapDrawable) photoView.getDrawable()).getBitmap();
    Matrix matrix = new Matrix();
    matrix.postRotate(90);
    bitmap[0] = Bitmap.createBitmap(bitmap[0], 0, 0, bitmap[0].getWidth(), bitmap[0].getHeight(), matrix, true);
    photoView.setImageBitmap(bitmap[0]);
});

Я добавил адрес ссылки выше, и это пример кода:

          ImageView photoView = findViewById(R.id.photo_view);
    ImageView rotate_image = findViewById(R.id.rotate_image);

        rotate_image.setOnClickListener(view -> {
        float scale = photoView.getRotation() % 180 == 0 ? (float) photoView.getWidth() / photoView.getHeight() : 1.0f;
        photoView.animate().rotationBy(90).scaleX(scale).scaleY(scale).setDuration(100).start();
    });
      //setRotation
ImageView.setRotation(float);
Другие вопросы по тегам