SwiftyCrop

repository·master·Indexed 43 days ago

https://github.com/benedom/swiftycrop

A SwiftUI library for cropping images with a user-friendly interface. It supports various mask shapes including circle, square, and rectangle, aspect ratio constraints, and high levels of UI customization via SwiftyCropConfiguration. Features include a zoom slider for non-pinch input devices and support for Liquid Glass UI on iOS 26+, visionOS 26, and macOS 26.

Tokens
3K
Snippets
7
Records
9
Agent score
6%

What's inside SwiftyCrop

  1. Configure colors for Liquid Glass UI (iOS 26+)

    master

    On iOS 26, visionOS 26, or macOS 26, SwiftyCrop automatically adopts the Liquid Glass design, which uses icon buttons instead of text buttons.

    Button Foreground Colors

    SwiftyCropConfiguration.Colors foreground keys (cancelButton, rotateButton, resetRotationButton, saveButton) apply to all OS versions. In Liquid Glass, these color the button icons.

    Button Background Colors

    Matching ...Background keys (e.g., cancelButtonBackground) only affect Liquid Glass by tinting the glass background of the button.

    • A .clear background (the default for most buttons) maintains a plain, untinted glass look.
    • On iOS, buttons with a non-.clear background use a prominent glass style that automatically picks a contrasting icon color; in these cases, the foreground color has no effect.

    Design Best Practices

    The toolbar is transparent. To ensure visibility, pick colors that contrast with your chosen background and avoid system-dependent colors like .primary, which may flip with appearance settings while your background does not.

  2. Enable Aspect Ratio Resizing for Rectangular Masks

    master

    When using the .rectangle mask shape, you can allow users to adjust the aspect ratio by dragging edge handles. This is enabled by setting allowAspectRatioResizing to true in the SwiftyCropConfiguration. You can also constrain the allowed range using minAspectRatio and maxAspectRatio.

    let configuration = SwiftyCropConfiguration(
        rectAspectRatio: 4/3,
        allowAspectRatioResizing: true,
        minAspectRatio: 0.5,  // narrowest: 1:2
        maxAspectRatio: 3.0   // widest: 3:1
    )
  3. Install SwiftyCrop via Swift Package Manager

    master

    To integrate SwiftyCrop into your Xcode project, use the Swift Package Manager. In Xcode, navigate to File > Swift Packages > Add Package Dependency... and provide the following URL:

    https://github.com/benedom/SwiftyCrop
  4. Install SwiftyCrop manually

    master
    If you prefer not to use a dependency manager, you can install SwiftyCrop manually by adding the Sources/SwiftyCrop folder directly to your Xcode project. Ensure that you enable Copy items if needed and Create groups during the import process.
  5. Quick Start: Display SwiftyCropView

    master

    To display the cropping interface, use SwiftyCropView. You typically present it in a .fullScreenCover or a sheet after an image has been selected. The view requires the imageToCrop and a maskShape. It provides a trailing closure that returns the final croppedImage.

    import SwiftUI
    import SwiftyCrop
    
    struct ExampleView: View {
        @State private var showImageCropper: Bool = false
        @State private var selectedImage: UIImage?
    
        var body: some View {
            VStack {
                 Button("Crop downloaded image") {
                    Task {
                        selectedImage = await downloadExampleImage()
                        showImageCropper.toggle()
                    }
                 }
            }
            .fullScreenCover(isPresented: $showImageCropper) {
                if let selectedImage = selectedImage {
                    SwiftyCropView(
                        imageToCrop: selectedImage,
                        maskShape: .square
                    ) { croppedImage in
                        // Do something with the returned, cropped image
                    }
                }
            }
        }
    
        private func downloadExampleImage() async -> UIImage? {
            // ... implementation ...
        }
    }
  6. Configure SwiftyCropView with SwiftyCropConfiguration

    master

    You can customize the behavior, appearance, and interaction of the cropper using SwiftyCropConfiguration. This includes settings for magnification, mask radius, rotation, zoom sensitivity, and custom text, fonts, and colors.

    let configuration = SwiftyCropConfiguration(
        maxMagnificationScale: 4.0,
        maskRadius: 130,
        cropImageCircular: false,
        rotateImage: false,
        rotateImageWithButtons: false,
        showsZoomSlider: false,
        zoomSensitivity: 1.0,
        rectAspectRatio: 4/3,
        showsProgressLayer: true,
        progressLayerDelay: .milliseconds(200),
        texts: SwiftyCropConfiguration.Texts(
            cancelButton: "Cancel",
            interactionInstructions: "Custom instruction text",
            saveButton: "Save",
            zoomSliderLabel: "Zoom"
        ),
        fonts: SwiftyCropConfiguration.Fonts(
            cancelButton: Font.system(size: 12),
            interactionInstructions: Font.system(size: 14),
            saveButton: Font.system(size: 12)
        ),
        colors: SwiftyCropConfiguration.Colors(
            cancelButton: Color.red,
            interactionInstructions: Color.white,
            saveButton: Color.blue,
            saveButtonBackground: Color.yellow,
            background: Color.gray,
            zoomSlider: Color.white
        )
    )
    
    // Usage
    SwiftyCropView(
        imageToCrop: selectedImage,
        maskShape: .square,
        configuration: configuration
    ) { croppedImage in
        // ...
    }
  7. Enable the Zoom Slider for non-pinch input devices

    master

    To support input devices that cannot perform pinch gestures (such as a mouse on macOS/Catalyst, VoiceOver, or Switch Control), enable showsZoomSlider in your SwiftyCropConfiguration. This adds a slider that controls the same scale as the pinch gesture.

    Note: Enabling the slider occupies the same toolbar slot as the interaction instructions. When showsZoomSlider is true, the instructions text is hidden and texts.interactionInstructions has no effect.

    let configuration = SwiftyCropConfiguration(
        showsZoomSlider: true,
        texts: SwiftyCropConfiguration.Texts(
            zoomSliderLabel: "Zoom" // Accessibility label, defaults to the localized value
        ),
        colors: SwiftyCropConfiguration.Colors(
            zoomSlider: Color.white
        )
    )
  8. Control view dismissal via `dismissesOnCompletion`

    master

    By default, the cropping view dismisses itself automatically after the onComplete or onCancel closures are called.

    If you need to perform asynchronous tasks (like uploading the cropped image) before the UI changes, set dismissesOnCompletion to false. In this mode, SwiftyCrop will never dismiss itself; you must manually trigger the dismissal within your onComplete or onCancel handlers.

    let configuration = SwiftyCropConfiguration(
        dismissesOnCompletion: false
    )
  9. Reference: SwiftyCropConfiguration properties

    master

    The following properties are available in SwiftyCropConfiguration to customize the cropping experience:

    | Property | Type | Description |
    | ----------- | ----------- | ----------- |
    | `maxMagnificationScale` | `CGFloat` | Maximum scale factor for magnification. Defaults to `4.0`. |
    | `maskRadius` | `CGFloat` | Radius of the mask. Defaults to `130`. |
    | `cropImageCircular` | `Bool` | If `true`, the resulting image is masked as a circle when using `.circle` mask. Defaults to `false`. |
    | `rotateImage` | `Bool` | Enables rotation via pinch gestures. Defaults to `false`. |
    | `rotateImageWithButtons` | `Bool` | Shows rotation buttons. Defaults to `false`. |
    | `showsZoomSlider` | `Bool` | Shows a zoom slider for non-pinch devices. Defaults to `false`. |
    | `zoomSensitivity` | `CGFloat` | Zoom speed. Defaults to `1.0`. |
    | `rectAspectRatio` | `CGFloat` | Aspect ratio for `.rectangle` mask. Defaults to `4:3`. |
    | `allowAspectRatioResizing` | `Bool` | Allows free resizing of aspect ratio for `.rectangle` mask. Defaults to `false`. |
    | `minAspectRatio` | `CGFloat` | Minimum aspect ratio (width/height) when resizing is enabled. Defaults to `0.1`. |
    | `maxAspectRatio` | `CGFloat` | Maximum aspect ratio (width/height) when resizing is enabled. Defaults to `10.0`. |
    | `dismissesOnCompletion` | `Bool` | If `true`, view dismisses itself after save/cancel. Defaults to `true`. |
    | `showsProgressLayer` | `Bool` | Shows progress layer during generation. Defaults to `true`. |
    | `progressLayerDelay` | `Duration` | Delay before showing progress layer. Defaults to `.zero`. |
    | `texts` | `Texts` | Custom button and instruction text. |
    | `fonts` | `Fonts` | Custom fonts for UI elements. |
    | `colors` | `Colors` | Custom colors for UI elements. |