Coder Social home page Coder Social logo

ryanlintott / iliketomoveit Goto Github PK

View Code? Open in Web Editor NEW
28.0 1.0 0.0 74 KB

Accessible move actions for SwiftUI Lists and easy custom drag and drop for older iOS

License: MIT License

Swift 100.00%
a11y accessibility swift swiftui swiftui-lists ios

iliketomoveit's Introduction

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

Overview

DragAndDrop (example app)

Check out the example app to see how you can use this package in your iOS app.

Installation and Usage

  1. In Xcode go to File -> Add Packages
  2. Paste in the repo's url: https://github.com/ryanlintott/ILikeToMoveIt and select by version.
  3. Import the package using import ILikeToMoveIt

Platforms

This package is compatible with iOS 14+ but the accessibility move feature only works for iOS 15+.

Support iLikeToMoveIt

If you like this package, buy me a coffee to say thanks!

ko-fi

Or you can buy a t-shirt with the iLikeToMoveIt logo

ShapeUp T-Shirt


Details

AccessibilityMoveable

*iOS 15+

Two modifiers are required to enable accessible move actions. One for each item and one for the list itself.

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

.accessibilityMoveable

Adding this modifier will add accessibility actions to move the item up, down, to the top of the list and to the bottom. If you want to customize these actions you can supply your own array.

Example: If you have a short list and only want up and down.

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

Example: If you have a long list and want options to move items more than one step at a time.

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

When the user triggers an accessibility action the following results are reported back via a UIAccessibility announcement:

  • "moved up", "moved down", or "not moved"
  • "by [number of spaces]" if moved by more than one space.
  • "above [item label]" if moved down and "below [item label]" if moved up. Only if a label keypath is was provided.
  • "At top" or "At bottom" if at the top or bottom of the list.

.accessibilityMoveableList

This modifier applies the changes from the move actions to the list and adjusts the accessibility focus to ensure it stays on the correct item.

You pass in a binding to the array of items and an optional label keypath. This label will be read out after moving an item to let the user know what item is directly below after moving up or directly above after moving down.

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

Known issues

  • Moving the same item again immediately after moving it may cause the accessibility focus to lag and another item will be moved instead.

Providable

This protocol allows for easier drag and drop for Codable objects in iOS 14 and 15

Drag and drop operations were made much easier in iOS 16 by the Transferable protocol. Older methods use NSItemProvider and were cumbersome to set up.

How to use it

Conform your object to Providable. Add readable and writable types, then add functions to transform your object to and from those types.

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
        }
    }
}

You will need to add any custom types to your project. Project > Target > Info > ExportedTypeIdentifiers

Adding drag and drop operations

Add a drag option to a view like this:

.onDrag { bird.provider }

And a drop option like this:

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

And even an insert option like this:

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

UserActivityProvidable

Extension to the Providable protocol to add easy drag to new window (a feature not supported by Transferable) on iPadOS 16+

Add your activity type string to plist under NSUserActivityTypes and then add the same string to the activityType parameter on your codable type.

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

Use the onContinueUserActivity overload function that takes a UserActivityProvidable object to handle what your app does when opened via this activity.

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

You can also target a separate WindowGroup for your object. Make sure you still use onContinueUserActivity in your view to ensure the object gets loaded.

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

iliketomoveit's People

Contributors

ryanlintott avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.