В этой статье я хочу рассказать о новой возможности перетаскивать данные между различными Activity в режиме совместного отображения, которая появилась с выходом Android 7 Nougat. Ранее перетаскивать данные можно было только в рамках одной Activity.
Описание технологии и разбор примера
Для передачи данных при перетаскивании используются классы ClipData и DragEvent. В приложении, в котором инициализируется операция перетаскивания, данные упаковываются с помощью ClipData. ClipData представляет собой сложный тип, содержащий в себе один или несколько экземпляров передаваемых данных. ClipData используется для размещения данных в буфере обмена. Для перетаскивания доступны следующие типы данных:
— MIMETYPE_TEXT_HTML: необходим для передачи HTML текста;
— MIMETYPE_TEXT_INTENT: необходим для передачи интента;
— MIMETYPE_TEXT_PLAIN: необходим для передачи обычного текста;
— MIMETYPE_TEXT_URILIST: необходим для передачи URL.
В приложении приемнике на соответствующем элементе интерфейса устанавливается слушатель перетаскивания, который принимает события DragEvent.
Давайте рассмотрим пример использования функции перетаскивания. В примере представлены два приложения: инициализатор (DragNDropExample) и приемник перетаскивания (DragNDropReceiver).
Для того, чтобы приложение отображалось в многооконном режиме необходимо установить в AndroidManifest в секции Application или Activity следующий параметр:
<activity
…
android:resizeableActivity="true"
…
</activity>
В приложении DragNDropExample реализовано перетаскивание изображения и текста. Файл изображения хранится в папке Downloads. При перетаскивании изображения другому процессу передается URI файла изображения. Инициализация перетаскивания происходит по долгому нажатию на соответствующие элементы.
Устанавливаем слушатель долгого нажатия.
imageView.setOnLongClickListener(new View.OnLongClickListener() {
@Override
public boolean onLongClick(View view) {
File downloadFolder = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS);
String[] filNames = downloadFolder.list();
Получаем URI файла для передачи другому процессу. В новой версии Android для получения доступа к файлам, размещенным в мультимедийных папках, необходимо использовать FileProvider.
Uri uri = FileProvider.getUriForFile(MainActivity.this, BuildConfig.APPLICATION_ID + ".provider", new File(downloadFolder, filNames[0]));
Создаем объект ClipData и упаковываем в него URI. При создании объекта ClipData указывается тип упакованных данных. Тип MIMETYPE_TEXT_URILIST указывает, что упаковываютсяURI.
ClipData.Item item = new ClipData.Item(uri);
ClipData clip = new ClipData("text", new String[]{ ClipDescription.MIMETYPE_TEXT_URILIST}, item);
Инициализируем перетаскивание, передавая объект ClipData, объект dragShadowBuilder и устанавливая соответствующие флаги. Флаг View.DRAG_FLAG_GLOBAL разрешает перетаскивание между операциями. Флаги View.DRAG_FLAG_GLOBAL_URI_READ и View.DRAG_FLAG_GLOBAL_URI_WRITE разрешают соответственно чтение и запись URI. Для создания тени при перетаскивании используется DragShadowBuilder. В данном примере тенью является сам элемент интерфейса:
View.DragShadowBuilder dragShadowBuilder = new View.DragShadowBuilder(view);
imageView.startDragAndDrop(clip, dragShadowBuilder, null, View.DRAG_FLAG_GLOBAL | View.DRAG_FLAG_GLOBAL_URI_READ | View.DRAG_FLAG_GLOBAL_URI_WRITE);
return true;
}
});
Аналогично происходит все для перетаскивания текста:
textView = (TextView) findViewById(R.id.text_view);
textView.setOnLongClickListener(new View.OnLongClickListener() {
@Override
public boolean onLongClick(View view) {
ClipData.Item item = new ClipData.Item(textView.getText());
ClipData clip = new ClipData("text", new String[]{ ClipDescription.MIMETYPE_TEXT_PLAIN}, item);
View.DragShadowBuilder dragShadowBuilder = new View.DragShadowBuilder(view);
textView.startDragAndDrop(clip, dragShadowBuilder, null, View.DRAG_FLAG_GLOBAL);
return true;
}
});
В приложении приемнике устанавливаются слушатели OnDragListener:
imageView.setOnDragListener(new View.OnDragListener() {
@Override
public boolean onDrag(View v, DragEvent event) {
В слушателе задаются действия для определенных событий перетаскивания. В данном примере установлены действия для следующих событий:
— ACTION_DRAG_STARTED: перетаскивание начато;
— ACTION_DROP: пользователь отпустил перетаскиваемый элемент.
switch (event.getAction()) {
case DragEvent.ACTION_DRAG_STARTED:
Toast toast = Toast.makeText(getApplicationContext(), R.string.drop_started, Toast.LENGTH_SHORT);
toast.show();
imageView.setBackgroundResource(R.color.grey_200);
break;
case DragEvent.ACTION_DROP:
requestDragAndDropPermissions(event);
ClipData.Item item = event.getClipData().getItemAt(0);
Для того чтобы вставка изображения производилась только в ImageView, а текста в TextView необходима соответствующая проверка. В данном участке кода проверяется тип перетаскиваемых данных и сравнивается с необходимым.
if (event.getClipDescription().getMimeType(0).equals(MIMETYPE_TEXT_URILIST)) {
Uri uri = item.getUri();
imageView.setImageURI(uri);
}
}
return true;
}
});
Для перетаскивания текста все происходит аналогично.
textView.setOnDragListener(new View.OnDragListener() {
@Override
public boolean onDrag(View v, DragEvent event) {
switch (event.getAction()) {
case DragEvent.ACTION_DRAG_STARTED:
Toast toast = Toast.makeText(getApplicationContext(), R.string.drop_started, Toast.LENGTH_SHORT);
toast.show();
break;
case DragEvent.ACTION_DROP:
requestDragAndDropPermissions(event);
ClipData.Item item = event.getClipData().getItemAt(0);
if (event.getClipDescription().getMimeType(0).equals(MIMETYPE_TEXT_PLAIN)) {
CharSequence text = item.getText();
textView.setText(text);
}
}
return true;
}
});
Ниже приведены скриншоты экрана в процессе перетаскивания
В процессе перетаскивания изображения:
После перетаскивания текста и изображения:
Заключение
Возможность перетаскивать информацию между различными процессами позволяет ускорить обмен данными между приложениями, сделать его более удобным и наглядным для пользователя.
Ссылки
- 1. Ссылка на официальную документацию Google по Drad-n-Drop
- 2. Ссылка на официальную документацию Google о Multi-Window Support
Автор: Conacry