EDIT: удален весь код и ссылки на UIButton
.
Спасибо @Matteo_Pacini за ответ на на этот вопрос за показ нам эту технику. Как и в случае с его ответом (и комментарием), (1) это грубо по краям и (2) я не уверен, что именно так Apple хочет, чтобы мы использовали UIViewControllerRepresentable
, и я очень надеюсь, что они обеспечат лучшее SwiftUI
( «SwiftierUI»?) Замена в будущей бете.
Я вложил много работы в UIKit
, потому что хочу, чтобы это выглядело хорошо на iPad, где для всплывающего окна требуется sourceView
. Реальный трюк заключается в отображении (SwiftUI) View
, который получает UIActivityViewController
в иерархии представления и запускает present
из UIKit
.
Мне нужно было представить одно изображение, чтобы поделиться им, поэтому все нацелено в этом направлении. Допустим, у вас есть изображение, хранящееся как переменная @State
- в моем примере это изображение называется vermont.jpg , и да, для этого все жестко закодировано.
Сначала создайте класс UIKit
типа `UIViewController для представления поповера общего ресурса:
class ActivityViewController : UIViewController {
var uiImage:UIImage!
@objc func shareImage() {
let vc = UIActivityViewController(activityItems: [uiImage!], applicationActivities: [])
vc.excludedActivityTypes = [
UIActivity.ActivityType.postToWeibo,
UIActivity.ActivityType.assignToContact,
UIActivity.ActivityType.addToReadingList,
UIActivity.ActivityType.postToVimeo,
UIActivity.ActivityType.postToTencentWeibo
]
present(vc,
animated: true,
completion: nil)
vc.popoverPresentationController?.sourceView = self.view
}
}
Основные вещи;
- Вам нужна «обертка»
UIViewController
, чтобы иметь возможность present
вещей.
- Вам нужно
var uiImage:UIImage!
, чтобы установить activityItems
.
Далее, заверните это в UIViewControllerRepresentable
:
struct SwiftUIActivityViewController : UIViewControllerRepresentable {
let activityViewController = ActivityViewController()
func makeUIViewController(context: Context) -> ActivityViewController {
activityViewController
}
func updateUIViewController(_ uiViewController: ActivityViewController, context: Context) {
//
}
func shareImage(uiImage: UIImage) {
activityViewController.uiImage = uiImage
activityViewController.shareImage()
}
}
Следует отметить только две вещи:
- Создание
ActivityViewController
для возврата до ContentView
- Создание
shareImage(uiImage:UIImage
) для его вызова.
Наконец, у вас есть ContentView
:
struct ContentView : View {
let activityViewController = SwiftUIActivityViewController()
@State var uiImage = UIImage(named: "vermont.jpg")
var body: some View {
VStack {
Button(action: {
self.activityViewController.shareImage(uiImage: self.uiImage!)
}) {
ZStack {
Image(systemName:"square.and.arrow.up").renderingMode(.original).font(Font.title.weight(.regular))
activityViewController
}
}.frame(width: 60, height: 60).border(Color.black, width: 2, cornerRadius: 2)
Divider()
Image(uiImage: uiImage!)
}
}
}
Обратите внимание, что есть жесткое кодирование и (тьфу) принудительное развертывание uiImage
вместе с ненужным использованием @State
. Это происходит потому, что я планирую использовать `UIImagePickerController рядом, чтобы связать все это вместе.
Примечания здесь:
- Создание экземпляра
SwiftUIActivityViewController
и использование shareImage
в качестве действия кнопки.
- С его помощью можно также отображать кнопки. Не забывайте, что даже
UIViewControllerRepresentable
действительно считается SwiftUI View
!
Измените имя изображения на то, которое у вас есть в вашем проекте, и это должно сработать. Вы получите центрированную кнопку 60x60 с изображением под ней.