Handling cancel button in SwiftUI PhotoPicker (inline)

Using the new inline PhotosPicker style in iOS 17, it isn't made clear how to handle the cancel button's input, and i cannot seem to find an answer in the documentation.

PhotosPicker(
    "Select picture",
    selection: $selected,
    selectionBehavior: .default,
    photoLibrary: .shared()
)
.photosPickerStyle(.inline)

Does anybody have a solution or is this a bug that needs to be fixed?

Answered by Engineer in 756440022

If you don't need the "Cancel" button, you can hide it using .photosPickerDisabledCapabilities(.selectionActions).

If you want to dismiss the picker when "Cancel" button is tapped, you can observe changes to $selected binding and check if it is empty.

Usually, .inline style is used with .continuous selection behavior, .photosPickerDisabledCapabilities(.selectionActions) and .photosPickerAccessoryVisibility(.hidden).

Accepted Answer

If you don't need the "Cancel" button, you can hide it using .photosPickerDisabledCapabilities(.selectionActions).

If you want to dismiss the picker when "Cancel" button is tapped, you can observe changes to $selected binding and check if it is empty.

Usually, .inline style is used with .continuous selection behavior, .photosPickerDisabledCapabilities(.selectionActions) and .photosPickerAccessoryVisibility(.hidden).

I'm also having this issue. In the app I'm working on, the PhotosPicker is contained .inline in a thin View wrapper without any additional UI and the wrapper View is presented as a sheet. I would really appreciate to have the default Cancel button working with our .sheet presentation. But it's not. Any hints how to do that?

If you want to dismiss the picker when "Cancel" button is tapped, you can observe changes to $selected binding and check if it is empty.

Observing the changes like below doesn't get triggered when Cancel is tapped:

PhotosPicker(
  selection: $viewModel.selection,
  maxSelectionCount: 1,
  selectionBehavior: .default,
  matching: .images,
  preferredItemEncoding: .current,
  photoLibrary: .shared()
) {
  Text("Select Photos")
}
.photosPickerStyle(.inline)
.photosPickerAccessoryVisibility(.hidden, edges: .bottom)
.onChange(of: viewModel.selection, { oldValue, newValue in
    print(oldValue)
    print(newValue)
})

I don't see any documentation that lets us add custom functionality to the Cancel or Add buttons when the PhotosPicker is presented inline.

I built this as a workaround.

NavigationStack {
                
                PhotosPicker("Choose Photos", selection: $pickerItems)
.photosPickerStyle(.inline)                    .photosPickerDisabledCapabilities(.selectionActions)  
.photosPickerAccessoryVisibility(.hidden, edges: .vertical)
.toolbar {
                        
ToolbarItem(placement: .topBarLeading) {                                                        Button("Cancel") {}   
}

ToolbarItem(placement: .topBarTrailing) {
Button("Add") {}
.bold()   
}
}
}

The NavStack is just so we can access the nav toolbar at the top.

If you're presenting this inline as a sheet, you can dismiss it from inside the Buttons.

Handling cancel button in SwiftUI PhotoPicker (inline)
 
 
Q