Введение
Новый протокол Transferable
был представлен на WWDC 2022 и призван значительно сократить усилия, необходимые с нашей стороны для копирования и вставки (Copy & Paste), a также для перетаскивание и “сброса” (Drag & Drop) данных внутри одного приложения или между разными приложениями.
Он пришел на замену классу NSItemProvider
в iOS 16+, macOS 13+ (Ventura и новее), watchOS 9.0+ и tvOS 16+. Познакомиться с некоторыми аспектами применения протокола Transferable
можно в постах Протокол Transferable меняет правила игры для Drag & Drop в SwiftUI и Протокол Transferable в SwiftUI — передача альтернативного контента с помощью ProxyRepresentation. (русскоязычные переводы, там же есть ссылка на оригинал).
Проблема
Однако попытка использовать протокол Transferable
в демонстрационном примере EmojiArt из курса CS193P Стэнфордского университета, Весна 2021 (Лекция 9. Drag &Drop) и заменить класс class NSItemProvider
на протокол Transferable
привела к вопросу о том, как поддерживать “сброс” (Drop) нескольких Transferable
ТИПов в один контейнер.
В таком приложении мы должны предоставить пользователю возможность перетаскивать и «бросать» (Drag & Drop) строку String
, URL
-адрес или данные Data
(например, данные изображения) в один и тот же ZStack
. И до появления протокола Transferable
это было сделано с помощью класса class
NSItemProvider
и View
модификатора .onDrop
:
Проблема в том, что при использовании нового протокола Transferable
и нового View
модификатора .dropDestination (for: action: isTargeted:);
его параметр for
не принимает несколько ТИПов «сбрасываемых» объектов одновременно, как это делает выше приведенный View
модификатор .onDrop (of: [.plainText, .url, .image] ...).
Поэтому я попыталась добавить три модификатора .dropDestination
с тремя различными ТИПами: String.self
, URL.self
и Data.self
:
Однако, если я «сбрасываю» String
, то получаю зеленый значок +
, как и ожидалось, и сбрасывание выполняется успешно. Но когда я перетаскиваю URL
или изображение Data
, соответствующие второму и третьему ТИПам, я вижу значок на запрет этого перетаскивания. Следовательно, последовательность модификаторов .dropDestination
не работает.
Решение
Но можно выполнять “сброс” нескольких ТИПов в одном .dropDestination
, если создать перечисление enumDropItem
для представления различных ТИПов данных, которые нужно “сбросить”:
При реализации протокола Transferable
мы использовали ProxyRepresentation
в обязательном для этого протокола static
свойстве transferRepresentation
и, конечно, определили пользовательский UTI с помощью расширения extension
класса UTType
.
Затем в нашем ZStack
мы просто сообщаем модификатору .dropDestination
, чтобы он принимал элементы ТИПа DropItem.self
:
А внутри .dropDestination
мы разбираемся, что нужно делать в зависимости от того, какой вариант (case
) имеет место при «сбросе»:
Если вы и дальше собираетесь работать только с версиями iOS 16+, то можно убрать расширение extension
массива Array
c NSProvider
элементами, которое предоставил в наше распоряжение профессор Пол Хэгерти из Стэнфорда для удобства работы с классом NSItemProvider
, так как мы заменили класс NSItemProvider
на протокол Transferable
. Если же ваше приложение работает с версиями ниже iOS 16, то это расширение extension
может быть незаменимым при работе с таким непростым классом, как class NSItemProvider
.
Для эмоджи, которые мы перетаскиваем и «бросаем» (Drag & Drop) на нашу «картину» не откуда-то извне, а с тематических палитр внутри нашего приложения, мы должны заменить View
модификатор .onDrag
, предназначенный для NSItemProvider
, на View модификатор .draggable()
, предназначенный для Transferable
объектов:
Заключение
С помощью перечисления enum DropItem
, куда мы включили все возможные объекты (текст String
, URL
-адрес, изображение в виде двоичного файла Data
), нам удалось в SwiftUI
с помощью нового протокола Transferable
обеспечить перетаскивание и «сброс» (Drag & Drop) в один и тот же контейнер (в нашем случае это ZStack
, но может быть и любой другой). При реализации протокола Transferable
перечисление enum DropItem
использует в static
свойстве transferRepresentation
ProxyRepresentation
для каждого «сбрасываемого» ТИПа.
Код находится на Github.com
ссылка на оригинал статьи https://habr.com/ru/post/708676/
Добавить комментарий