Перемещение изображений по экрану в Android

Перемещение различных объектов часто применяется в мобильных играх и различных мультимедиа-приложениях. В этой статье мы рассмотрим, как добавлять изображения на экран и свободно перемещать их.

Для этого нам понадобится выполнить следующие действия:

  1. Создать разметку с элементом FrameLayout.
  2. Создать программно ImageView для добавленного изображения и установить ему OnTouchListener
  3. В методе onTouch() определить действия пользователя
  4. Менять значения LayoutParams в соответствии с текущим расположением ImageView

Для начала создадим новый проект с пустой активностью.

В разметке активности activity_main.xml удалим старую разметку и заменим её на новую. FrameLayout в данном случае будет использоваться как контейнер для добавленных изображений.

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context=".MainActivity"
    >

  <FrameLayout
      android:id="@+id/container"
      android:layout_width="match_parent"
      android:layout_height="match_parent"
      android:layout_above="@id/btn_add"
      android:layout_alignParentTop="true"
      />

  <Button
      android:id="@+id/btn_add"
      android:layout_width="match_parent"
      android:layout_height="wrap_content"
      android:layout_alignParentBottom="true"
      android:text="Добавить изображение"
      />

</RelativeLayout>

Определим созданные элементы разметки в коде активности MainActivity.

public class MainActivity extends AppCompatActivity {
  private FrameLayout container;

  @Override protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    container = findViewById(R.id.container);
    Button btn_add = findViewById(R.id.btn_add);
  }

Для выбора и обрезки добавляемых изображений воспользуемся библиотекой uCrop, которую можно найти на GitHub. Подключим её, добавив в файл build.gradle проекта следующие строки:

allprojects {
  repositories {
    ...
    maven { url "https://jitpack.io" }
  }
}

Затем в файле build.gradle модуля приложения нужно подключить саму библиотеку:

dependencies {
  ...
  implementation 'com.github.yalantis:ucrop:2.2.2-native'
}

После этого в манифест приложения AndroidManifest.xml нужно добавить активность библиотеки.

<activity
    android:name="com.yalantis.ucrop.UCropActivity"
    android:screenOrientation="portrait"
    android:theme="@style/Theme.AppCompat.Light.NoActionBar"/>

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

@Override protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  ...
  btn_add.setOnClickListener(new View.OnClickListener() {
    @Override public void onClick(View view) {
      Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
      intent.setType("image/*");
      startActivityForResult(intent, REQUEST_IMAGE);
    }
  });
}

Чтобы получить Uri выбранного файла, нужно переопределить в коде активности метод onActivityResult(), добавив в него следующий код:

@Override
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
  if (resultCode == RESULT_OK) {
    switch (requestCode) {
      case REQUEST_IMAGE: {
        if (data != null && data.getData() != null) {
          startCrop(data.getData());
        }
        break;
      }
    }
  }
}
private void startCrop(Uri data) {
  String name = getFileName(data);
  File file = new File(getCacheDir(), name);
  filename = name;
}

Метод getFileName() используется, чтобы получить из Uri имя файла, посмотреть его можно будет в исходном коде проекта далее.

Когда у нас есть Uri выбранного файла, мы можем воспользоваться библиотекой uCrop, чтобы обрезать изображение так, как нам требуется. Это можно сделать с помощью следующих строк в методе startCrop().

private void startCrop(Uri data) {
  ...
  UCrop uCrop = UCrop.of(data, Uri.fromFile(file));
  uCrop.start(this);
}

После вызова start() откроется активность библиотеки, в которой можно работать с изображением. Как только работа будет закончена, в нашу активность вернётся интент с Uri обрезанного изображения. Нам, в данном случае, будет проще обратиться к самому файлу, так как его путь и имя известны. Получить его можно всё в том же onActivityResult() следующим образом.

@Override
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
  if (resultCode == RESULT_OK) {
    switch (requestCode) {
      ...
      case UCrop.REQUEST_CROP: {
        createImageView();
        break;
      }
    }
  }
}

private void createImageView() {
  File file = new File(getCacheDir(), filename);
  Bitmap bmp = BitmapFactory.decodeFile(file.getAbsolutePath());
  ImageView imageView = new ImageView(MainActivity.this);
  FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(250, 250);
  params.leftMargin = 0;
  params.topMargin = 0;
  imageView.setLayoutParams(params);
  imageView.setImageBitmap(bmp);
  container.addView(imageView);
  file.delete();
}

Здесь же мы сразу создаём новый ImageView, которому задаём размер и загружаем в него Bitmap, полученный из файла.

Сейчас изображения просто добавляются на экран и с ними нельзя никак взаимодействовать. Чтобы обрабатывать касания для изображений, добавим в код активности переменную OnTouchListener, в которой будет переопределяться метод onTouch(). Этот метод позволяет отлавливать различные касания и жесты, нам же нужны только следующие действия пользователя:

  • Пользователь коснулся изображения;
  • Пользователь двигает пальцем по экрану;
  • Пользователь убрал палец с экрана;

Таким образом, код обработка будет выглядеть следующим образом:

private int xDelta, yDelta;
private View.OnTouchListener touchListener = new View.OnTouchListener() {
  @Override public boolean onTouch(View view, MotionEvent event) {
    final int x = (int) event.getRawX();
    final int y = (int) event.getRawY();

    switch (event.getAction() & MotionEvent.ACTION_MASK) {
      case MotionEvent.ACTION_DOWN: {
        FrameLayout.LayoutParams lParams = (FrameLayout.LayoutParams) view.getLayoutParams();

        xDelta = x - lParams.leftMargin;
        yDelta = y - lParams.topMargin;
        break;
      }
      case MotionEvent.ACTION_UP: {
        Toast.makeText(getApplicationContext(), "Объект перемещён", Toast.LENGTH_SHORT).show();
        break;
      }
      case MotionEvent.ACTION_MOVE: {
        if (x - xDelta + view.getWidth() <= container.getWidth()
            && y - yDelta + view.getHeight() <= container.getHeight()
            && x - xDelta >= 0
            && y - yDelta >= 0) {
          FrameLayout.LayoutParams layoutParams =
              (FrameLayout.LayoutParams) view.getLayoutParams();
          layoutParams.leftMargin = x - xDelta;
          layoutParams.topMargin = y - yDelta;
          layoutParams.rightMargin = 0;
          layoutParams.bottomMargin = 0;
          view.setLayoutParams(layoutParams);
        }
        break;
      }
    }
    container.invalidate();
    return true;
  }
};

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

Теперь остаётся только задать этот обработчик касаний создаваемым ImageView в createImageView().

private void createImageView() {
  ...
  imageView.setOnTouchListener(touchListener);
  container.addView(imageView);
  file.delete();
}

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

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

Посмотреть исходный код приложения можно, перейдя по ссылке на GitHub.

Читайте также

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *