Swift Compatibility Platform Compatibility License - MIT Version GitHub last commit Mastodon Twitter

概述

演示

Example 文件夹中有一个应用程序,演示了此软件包的功能以及如何设置自定义类型的拖放

ILikeToMoveIt demo app with the logo at the top and two lists at the bottom. The left list contains a number of birds. Chicken is dragged up a few spaces. Cardinal is dragged to the empty list on the right. Robin, Goose, and Swan are picked up from the left list and dropped on the right list. Text reading StringBird above the list is dragged onto the right list. Switching over to the reminders app, two reminders named Crow and Finch are picked up and dragged back into the right list of ILikeToMoveIt. VoiceOver is turned on and Robin is moved up and down using accessibility actions. Each time the move and the final position above Chicken or below Blue Jay is reported along with At Top or At Bottom if applicable.

安装和使用

  1. 在 Xcode 中,转到 File -> Add Packages
  2. 粘贴仓库的 URL:https://github.com/ryanlintott/ILikeToMoveIt 并按版本选择。
  3. 使用 import ILikeToMoveIt 导入软件包

平台

此软件包与 iOS 14+ 兼容,但辅助功能移动功能仅适用于 iOS 15+。

支持 iLikeToMoveIt

如果您喜欢这个软件包,请买杯咖啡感谢我!

ko-fi

或者您可以购买一件带有 iLikeToMoveIt 标志的 T 恤

ShapeUp T-Shirt


详情

AccessibilityMoveable

*iOS 15+

需要两个修饰符来启用辅助功能移动操作。每个项目一个,列表本身一个。

List {
  ForEach(items) { item in
    Text(item.name)
      .accessibilityMoveable(item)
  }
}
.accessibilityMoveableList($items, label: \.name)

.accessibilityMoveable

添加此修饰符将添加辅助功能操作,以将项目向上、向下、移动到列表顶部和底部。如果您想自定义这些操作,您可以提供自己的数组。

示例:如果您的列表很短,只想向上和向下移动。

.accessibilityMoveable(item, actions: [.up, .down])

示例:如果您的列表很长,并且希望一次移动多个步骤的选项。

.accessibilityMoveable(item, actions: [.up, .down, .up(5), .down(5), .toTop, .toBottom])

当用户触发辅助功能操作时,以下结果将通过 UIAccessibility 公告报告返回

.accessibilityMoveableList

此修饰符将移动操作的更改应用于列表,并调整辅助功能焦点以确保其停留在正确的项目上。

您传入项目数组的绑定和一个可选的标签键路径。此标签将在移动项目后读出,以使用户知道向上移动后直接下方的项目或向下移动后直接上方的项目是什么。

.accessibilityMoveableList($items, label: \.name)

已知问题

Providable

此协议允许在 iOS 14 和 15 中更轻松地拖放 Codable 对象

在 iOS 16 中,Transferable 协议使拖放操作变得更加容易。旧方法使用 NSItemProvider 且设置繁琐。

如何使用它

使您的对象符合 Providable。添加可读和可写类型,然后添加函数以在这些类型之间转换您的对象。

extension Bird: Providable {
    static let writableTypes: [UTType] = [.bird]

    static let readableTypes: [UTType] = [.bird, .plainText]

    func data(type: UTType) async throws-> Data? {
        switch type {
        case .bird:
            return try JSONEncoder().encode(self)
        default:
            return nil
        }
    }

    init?(type: UTType, data: Data) throws {
        switch type {
        case .bird:
            self = try JSONDecoder().decode(Bird.self, from: data)
        case .plainText:
            let string = String(decoding: data, as: UTF8.self)
            self = Bird(name: string)
        default:
            return nil
        }
    }
}

您需要将任何自定义类型添加到您的项目。项目 > 目标 > Info > ExportedTypeIdentifiers

添加拖放操作

像这样向视图添加拖动选项

.onDrag { bird.provider }

像这样添加放置选项

.onDrop(of: Bird.readableTypes) { providers, location in
  providers.loadItems(Bird.self) { bird, error in
    if let bird {
        birds.append(bird)
    }
  }
  return true
}

甚至像这样添加插入选项

.onInsert(of: Bird.readableTypes) { index, providers in
  providers.loadItems(Bird.self) { bird, error in
    if let bird {
      birds.insert(bird, at: index)
    }
  }
}

UserActivityProvidable

Providable 协议的扩展,用于在 iPadOS 16+ 上轻松拖动到新窗口(Transferable 不支持的功能)

将您的活动类型字符串添加到 plist 中的 NSUserActivityTypes 下,然后将相同的字符串添加到您的可编码类型上的 activityType 参数。

extension Bird: UserActivityProvidable {
  static let activityType = "com.ryanlintott.draganddrop.birdDetail"
}

使用接受 UserActivityProvidable 对象的 onContinueUserActivity 重载函数来处理您的应用程序通过此活动打开时的操作。

.onContinueUserActivity(Bird.self) { bird in
  /// Adjust state based on your object.
}

您还可以为您的对象定位单独的 WindowGroup。确保您仍然在视图中使用 onContinueUserActivity 以确保对象被加载。

WindowGroup {
  BirdDetailView()            
}
.handlesExternalEvents(matching: [Bird.activityType])

自定义类型的拖放

创建新的可拖动类型

struct Bird: Codable {
    let name: String
}

项目 > 目标 > Info > Exported Type Identifiers

Exported Type Identifiers with the description Bird, Identifier com.ryanlintott.draganddrop.bird and conforms to public.data
import UniformTypeIdentifiers

extension UTType {
    static let bird = UTType("com.ryanlintott.draganddrop.bird") ?? .data
}

iOS 14 和 15 中的可拖动自定义类型

iOS 16 中的可拖动自定义类型

static var transferRepresentation: some TransferRepresentation {
    CodableRepresentation(contentType: .bird)

    DataRepresentation(importedContentType: .plainText) { data in
        let string = String(decoding: data, as: UTF8.self)
        return Bird(name: string)
    }
}

将拖放添加到您的 SwiftUI 视图

一旦您的类型符合 Transferable,添加 SwiftUI 拖放修饰符就很容易了!

draggable(_:)

通过添加此修饰符使任何视图可拖动

.draggable(bird)

dropDestination(for:action:isTargetted:)

任何视图都可以是放置目标。使用 action 添加放置的项目,如果需要,可以使用 location 进行动画,并使用 isTargeted 闭包在可放置内容悬停时为视图添加动画。

.dropDestination(for: Bird.self) { droppedBirds, location in
    birds.append(contentsOf: droppedBirds)
    return true
} isTargeted: {
    isTargetted = $0
}

dropDestination(for:action:)

添加到 ForEach 时,放置的项目可以插入到其他项目之间。

.dropDestination(for: Bird.self) { droppedBirds, offset in
    birds.insert(contentsOf: droppedBirds, at: offset)
}