ฉันต้องการให้ผู้ใช้สามารถแชร์ตำแหน่งได้ แต่ฉันไม่รู้วิธีแสดง UIActivityViewController ใน Swift UI
การดำเนินการขั้นพื้นฐานของUIActivityViewControllerในSwiftUIเป็น
import UIKit
import SwiftUI
struct ActivityViewController: UIViewControllerRepresentable {
var activityItems: [Any]
var applicationActivities: [UIActivity]? = nil
func makeUIViewController(context: UIViewControllerRepresentableContext<ActivityViewController>) -> UIActivityViewController {
let controller = UIActivityViewController(activityItems: activityItems, applicationActivities: applicationActivities)
return controller
}
func updateUIViewController(_ uiViewController: UIActivityViewController, context: UIViewControllerRepresentableContext<ActivityViewController>) {}
}
และนี่คือวิธีการใช้งาน
struct MyView: View {
@State private var isSharePresented: Bool = false
var body: some View {
Button("Share app") {
self.isSharePresented = true
}
.sheet(isPresented: $isSharePresented, onDismiss: {
print("Dismiss")
}, content: {
ActivityViewController(activityItems: [URL(string: "https://www.apple.com")!])
})
}
}
ปัจจุบันเป็นสิ่งที่เกิดขึ้นเพียงครั้งเดียว .sheet จะแสดงเป็นแผ่นงาน แต่การนำขึ้นมาอีกครั้งจากมุมมองเดิมจะมีข้อมูลเก่า การแสดงแผ่นงานในภายหลังเหล่านั้นจะไม่ทริกเกอร์ตัวจัดการความสมบูรณ์ โดยทั่วไป makeUIViewController ถูกเรียกเพียงครั้งเดียวซึ่งเป็นวิธีเดียวที่จะรับข้อมูลเพื่อแชร์ไปยัง UIActivityViewController updateUIViewController ไม่มีวิธีอัปเดตข้อมูลใน activityItems ของคุณหรือรีเซ็ตคอนโทรลเลอร์เนื่องจากไม่สามารถมองเห็นได้จากอินสแตนซ์ของ UIActivityViewController
โปรดทราบว่ามันใช้ไม่ได้กับ UIActivityItemSource หรือ UIActivityItemProvider การใช้สิ่งเหล่านี้ยิ่งแย่ลง ค่าตัวยึดตำแหน่งไม่แสดง
ฉันแฮ็กข้อมูลเพิ่มเติมและตัดสินใจว่าปัญหาในการแก้ปัญหาของฉันอาจเป็นแผ่นงานที่กำลังนำเสนอแผ่นงานอื่นและเมื่อแผ่นหนึ่งหายไปอีกแผ่นก็อยู่
วิธีทางอ้อมในการให้ ViewController ทำการนำเสนอเมื่อปรากฏขึ้นทำให้มันใช้งานได้สำหรับฉัน
class UIActivityViewControllerHost: UIViewController {
var message = ""
var completionWithItemsHandler: UIActivityViewController.CompletionWithItemsHandler? = nil
override func viewDidAppear(_ animated: Bool) {
share()
}
func share() {
// set up activity view controller
let textToShare = [ message ]
let activityViewController = UIActivityViewController(activityItems: textToShare, applicationActivities: nil)
activityViewController.completionWithItemsHandler = completionWithItemsHandler
activityViewController.popoverPresentationController?.sourceView = self.view // so that iPads won't crash
// present the view controller
self.present(activityViewController, animated: true, completion: nil)
}
}
struct ActivityViewController: UIViewControllerRepresentable {
@Binding var text: String
@Binding var showing: Bool
func makeUIViewController(context: Context) -> UIActivityViewControllerHost {
// Create the host and setup the conditions for destroying it
let result = UIActivityViewControllerHost()
result.completionWithItemsHandler = { (activityType, completed, returnedItems, error) in
// To indicate to the hosting view this should be "dismissed"
self.showing = false
}
return result
}
func updateUIViewController(_ uiViewController: UIActivityViewControllerHost, context: Context) {
// Update the text in the hosting controller
uiViewController.message = text
}
}
struct ContentView: View {
@State private var showSheet = false
@State private var message = "a message"
var body: some View {
VStack {
TextField("what to share", text: $message) Button("Hello World") { self.showSheet = true } if showSheet { ActivityViewController(text: $message, showing: $showSheet)
.frame(width: 0, height: 0)
}
Spacer()
}
.padding()
}
}
ตามของ Tikhonovรหัสต่อไปนี้ได้เพิ่มการแก้ไขเพื่อให้แน่ใจว่าแผ่นกิจกรรมถูกปิดอย่างถูกต้อง (หากไม่นำเสนอแผ่นงานในภายหลัง)
struct ActivityViewController: UIViewControllerRepresentable {
var activityItems: [Any]
var applicationActivities: [UIActivity]? = nil
@Environment(\.presentationMode) var presentationMode
func makeUIViewController(context: UIViewControllerRepresentableContext<ActivityViewController>) -> UIActivityViewController {
let controller = UIActivityViewController(activityItems: activityItems, applicationActivities: applicationActivities)
controller.completionWithItemsHandler = { (activityType, completed, returnedItems, error) in
self.presentationMode.wrappedValue.dismiss()
}
return controller
}
func updateUIViewController(_ uiViewController: UIActivityViewController, context: UIViewControllerRepresentableContext<ActivityViewController>) {}
}
คุณสามารถลองย้ายUIActivityViewControllerไปSwiftUIที่ดังนี้:
struct ActivityView: UIViewControllerRepresentable {
let activityItems: [Any]
let applicationActivities: [UIActivity]?
func makeUIViewController(context: UIViewControllerRepresentableContext<ActivityView>) -> UIActivityViewController {
return UIActivityViewController(activityItems: activityItems,
applicationActivities: applicationActivities)
}
func updateUIViewController(_ uiViewController: UIActivityViewController,
context: UIViewControllerRepresentableContext<ActivityView>) {
}
}
แต่แอปจะขัดข้องเมื่อคุณพยายามแสดง
ฉันพยายาม: Modal, และPopoverNavigationButton
ในการทดสอบ:
struct ContentView: View {
var body: some Body {
EmptyView
.presentation(Modal(ActivityView()))
}
}
SwiftUIมันดูเหมือนจะไม่จะใช้งานได้จาก
ตอนนี้ใช้งานได้แล้ว
.sheet(isPresented: $isSheet, content: { ActivityViewController() }
.presentation เลิกใช้งานแล้ว
ใช้สไตล์ iOS 13 ทั้งหน้าจอ
ฉันต้องการแนะนำการใช้งานอื่นที่ดูเป็นธรรมชาติมากกว่า (ความสูงครึ่งหน้าจอโดยไม่มีช่องว่างด้านล่างสีขาว)
import SwiftUI
struct ActivityView: UIViewControllerRepresentable {
var activityItems: [Any]
var applicationActivities: [UIActivity]? = nil
@Binding var isPresented: Bool
func makeUIViewController(context: Context) -> ActivityViewWrapper {
ActivityViewWrapper(activityItems: activityItems, applicationActivities: applicationActivities, isPresented: $isPresented) } func updateUIViewController(_ uiViewController: ActivityViewWrapper, context: Context) { uiViewController.isPresented = $isPresented
uiViewController.updateState()
}
}
class ActivityViewWrapper: UIViewController {
var activityItems: [Any]
var applicationActivities: [UIActivity]?
var isPresented: Binding<Bool>
init(activityItems: [Any], applicationActivities: [UIActivity]? = nil, isPresented: Binding<Bool>) {
self.activityItems = activityItems
self.applicationActivities = applicationActivities
self.isPresented = isPresented
super.init(nibName: nil, bundle: nil)
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func didMove(toParent parent: UIViewController?) {
super.didMove(toParent: parent)
updateState()
}
fileprivate func updateState() {
guard parent != nil else {return}
let isActivityPresented = presentedViewController != nil
if isActivityPresented != isPresented.wrappedValue {
if !isActivityPresented {
let controller = UIActivityViewController(activityItems: activityItems, applicationActivities: applicationActivities)
controller.completionWithItemsHandler = { (activityType, completed, _, _) in
self.isPresented.wrappedValue = false
}
present(controller, animated: true, completion: nil)
}
else {
self.presentedViewController?.dismiss(animated: true, completion: nil)
}
}
}
}
struct ActivityViewTest: View {
@State private var isActivityPresented = false
var body: some View {
Button("Preset") {
self.isActivityPresented = true
}.background(ActivityView(activityItems: ["Hello, World"], isPresented: $isActivityPresented))
}
}
struct ActivityView_Previews: PreviewProvider {
static var previews: some View {
ActivityViewTest()
}
}
FWIW - ให้การปรับปรุงคำตอบเล็กน้อยซึ่งรวมถึงการนำไปใช้งานสำหรับUIActivityItemSource. โค้ดทำให้ง่ายขึ้นสำหรับความกะทัดรัดโดยเฉพาะเกี่ยวกับผลตอบแทนเริ่มต้นitemForActivityTypeและactivityViewControllerPlaceholderItemต้องส่งคืนประเภทเดียวกันเสมอ
ActivityViewController
struct ActivityViewController: UIViewControllerRepresentable {
var activityItems: [Any]
var shareable : ActivityShareable?
var applicationActivities: [UIActivity]? = nil
func makeUIViewController(context: UIViewControllerRepresentableContext<ActivityViewController>) -> UIActivityViewController {
let controller = UIActivityViewController(activityItems: activityItems, applicationActivities: applicationActivities)
controller.modalPresentationStyle = .automatic
return controller
}
func updateUIViewController(_ uiViewController: UIActivityViewController, context: UIViewControllerRepresentableContext<ActivityViewController>) {}
func makeCoordinator() -> ActivityViewController.Coordinator {
Coordinator(self.shareable)
}
class Coordinator : NSObject, UIActivityItemSource {
private let shareable : ActivityShareable?
init(_ shareable: ActivityShareable?) {
self.shareable = shareable
super.init()
}
func activityViewControllerPlaceholderItem(_ activityViewController: UIActivityViewController) -> Any {
guard let share = self.shareable else { return "" }
return share.getPlaceholderItem()
}
func activityViewController(_ activityViewController: UIActivityViewController, itemForActivityType activityType: UIActivity.ActivityType?) -> Any? {
guard let share = self.shareable else { return "" }
return share.itemForActivityType(activityType: activityType)
}
func activityViewController(_ activityViewController: UIActivityViewController, subjectForActivityType activityType: UIActivity.ActivityType?) -> String {
guard let share = self.shareable else { return "" }
return share.subjectForActivityType(activityType: activityType)
}
}
}
ActivityShareable
protocol ActivityShareable {
func getPlaceholderItem() -> Any
func itemForActivityType(activityType: UIActivity.ActivityType?) -> Any?
/// Optional
func subjectForActivityType(activityType: UIActivity.ActivityType?) -> String
}
extension ActivityShareable {
func subjectForActivityType(activityType: UIActivity.ActivityType?) -> String {
return ""
}
}
คุณสามารถส่งข้อมูลอ้างอิงสำหรับActivityViewControllerหรือข้อมูลอ้างอิงได้UIActivityViewControllerแต่รู้สึกว่าไม่จำเป็น
มีไลบรารีชื่อ SwiftUIX ที่มี wrapper สำหรับUIActivityViewController. ดูโครงร่างสั้น ๆ ของวิธีการนำเสนอโดย.sheet()ควรวางไว้ที่ใดที่หนึ่งในไฟล์var body: some View {}.
import SwiftUIX
/// ...
@State private var showSocialsInviteShareSheet: Bool = false
// ...
.sheet(isPresented: $showSocialsInviteShareSheet, onDismiss: {
print("Dismiss")
}, content: {
AppActivityView(activityItems: [URL(string: "https://www.apple.com")!])
})
อาจจะไม่แนะนำ แต่มันง่ายมากและรหัสสองบรรทัดในการแบ่งปันข้อความ
Button(action: {
let shareActivity = UIActivityViewController(activityItems: ["Text To Share"], applicationActivities: nil)
UIApplication.shared.windows.first?.rootViewController?.present(shareActivity, animated: true, completion: nil)
}) {
Text("Share")
}
ขอบคุณสำหรับคำตอบที่เป็นประโยชน์ในชุดข้อความนี้
ผมพยายามแก้stale dataปัญหา ปัญหาจากการไม่ใช้งานupdateUIViewControllerในUIViewControllerRepresentable. SwiftUI โทรmakeUIViewControllerเพียงครั้งเดียวเพื่อสร้างตัวควบคุมมุมมอง วิธีupdateUIViewControllerนี้รับผิดชอบในการเปลี่ยนแปลงมุมมองคอนโทรลเลอร์ตามการเปลี่ยนแปลงของมุมมอง SwiftUI
เนื่องจากUIActivityViewControllerไม่อนุญาตให้เปลี่ยนแปลงactivityItemsและapplicationActivitiesฉันใช้ตัวควบคุมมุมมองกระดาษห่อหุ้ม UIViewControllerRepresentableจะอัปเดต Wrapper และ Wrapper จะสร้างใหม่UIActivityViewControllerตามความจำเป็นเพื่อทำการอัปเดต
ด้านล่างรหัสของฉันเพื่อติดตั้งปุ่ม "แชร์" ในแอปพลิเคชันของฉัน โค้ดได้รับการทดสอบบน iOS 13.4 เบต้าซึ่งได้แก้ไขข้อบกพร่องของ SwiftUI หลายอย่าง - ไม่แน่ใจว่าใช้ได้กับรุ่นก่อนหน้า
struct Share: View {
var document: ReaderDocument // UIDocument subclass
@State var showShareSheet = false
var body: some View {
Button(action: {
self.document.save(to: self.document.fileURL, for: .forOverwriting) { success in
self.showShareSheet = true
}
}) {
Image(systemName: "square.and.arrow.up")
}.popover(isPresented: $showShareSheet) {
ActivityViewController(activityItems: [ self.document.text, self.document.fileURL,
UIPrintInfo.printInfo(), self.printFormatter ])
.frame(minWidth: 320, minHeight: 500) // necessary for iPad
}
}
var printFormatter: UIPrintFormatter {
let fontNum = Preferences.shared.readerFontSize.value
let fontSize = ReaderController.readerFontSizes[fontNum < ReaderController.readerFontSizes.count ? fontNum : 1]
let printFormatter = UISimpleTextPrintFormatter(text: self.document.text)
printFormatter.startPage = 0
printFormatter.perPageContentInsets = UIEdgeInsets(top: 72, left: 72, bottom: 72, right: 72)
return printFormatter
}
}
struct ActivityViewController: UIViewControllerRepresentable {
var activityItems: [Any]
var applicationActivities: [UIActivity]? = nil
@Environment(\.presentationMode) var presentationMode
func makeUIViewController(context: UIViewControllerRepresentableContext<ActivityViewController>)
-> WrappedViewController<UIActivityViewController> {
let controller = WrappedViewController(wrappedController: activityController)
return controller
}
func updateUIViewController(_ uiViewController: WrappedViewController<UIActivityViewController>,
context: UIViewControllerRepresentableContext<ActivityViewController>) {
uiViewController.wrappedController = activityController
}
private var activityController: UIActivityViewController {
let avc = UIActivityViewController(activityItems: activityItems, applicationActivities: applicationActivities)
avc.completionWithItemsHandler = { (_, _, _, _) in
self.presentationMode.wrappedValue.dismiss()
}
return avc
}
}
class WrappedViewController<Controller: UIViewController>: UIViewController {
var wrappedController: Controller {
didSet {
if (wrappedController != oldValue) {
oldValue.removeFromParent()
oldValue.view.removeFromSuperview()
addChild(wrappedController)
view.addSubview(wrappedController.view)
wrappedController.view.frame = view.bounds
}
}
}
init(wrappedController: Controller) {
self.wrappedController = wrappedController
super.init(nibName: nil, bundle: nil)
addChild(wrappedController)
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func loadView() {
super.loadView()
view.addSubview(wrappedController.view)
wrappedController.view.frame = view.bounds
}
}
Jana Duggar เปิดใจเกี่ยวกับการค้นหาความรักของเธอ นี่คือทุกสิ่งที่เธอพูดเกี่ยวกับหัวข้อและกรอบเวลา 5 ปีสำหรับการแต่งงาน
เมื่อเร็ว ๆ นี้ แซม ฮิวแฮน นักแสดงจากเรื่อง 'Outlander' ได้เปิดเผยสิ่งที่เขาจะทำจากกองถ่ายเพื่อระลึกถึงเจมี เฟรเซอร์ บทบาทที่ทำให้เขากลายเป็นดารา
'She Loves You' เขียนขึ้นในหนึ่งชั่วโมง บันทึกเสียงในหนึ่งวัน และเป็นเพลงของ The Beatles ที่มีการแสดงที่ดีที่สุดเพลงหนึ่งในอาชีพของพวกเขา
Dolly Parton และคุณย่า Bessie มีความสัมพันธ์พิเศษ คุณยายพาร์ตันป่วยหนัก แต่นั่นไม่ได้ทำให้ดอลลี่หยุดแกล้งเธอ
คุณอาจคิดว่าไม้โอ๊คหรือฮิคคอรีเป็นไม้ที่แข็ง แต่เมื่อต้องพูดถึงไม้ที่แข็งที่สุดในโลกแล้ว พวกมันกลับไม่ใกล้เคียงเลย
มหาสมุทรเต็มไปด้วยความงาม แต่ก็ซ่อนสิ่งมีชีวิตใต้ท้องทะเลที่น่ากลัวที่สุดบางชนิดไว้เช่นกัน สัตว์เหล่านี้หลายชนิดซ่อนตัวอยู่ใต้ผิวน้ำอันมืดมิด ในโลกใต้ทะเลลึกอันแสนกดดันและมืดมิด
หากคุณกำลังต่อสู้กับศัตรูหรือกำลังเตรียมตัวสำหรับโหมด PvP การรู้ถึงการเสริมพลังดาบที่ดีที่สุดใน Minecraft จะช่วยให้คุณได้เปรียบอย่างมาก การเสริมพลังดาบจะช่วยให้คุณสร้างความเสียหายได้มากขึ้น เพิ่มจำนวนม็อบที่ดรอป และเพิ่มความทนทานของดาบ
เมื่อผู้คนพูดถึงประเทศสังคมนิยม พวกเขามักจะนึกถึงการควบคุมโดยรัฐบาลอย่างเต็มรูปแบบโดยไม่มีกรรมสิทธิ์ส่วนบุคคล แต่ในทางปฏิบัติ เศรษฐกิจแบบสังคมนิยมมีความหลากหลายอย่างมาก
“เด็ก” โผล่รับเชิญดาราดังพร้อมข่าวร้าย
RAV4 นี้อ้างว่าอยู่ในสภาพที่ดีเยี่ยมและมีไว้สำหรับการเล่นเก้าอี้ดนตรี
ภาพจากโดรนจับภาพนักดับเพลิงที่กำลังพยายามดับไฟ
Eyes of Wakanda เชื่อมโยงโดยตรงกับ MCU พร้อมอัปเดตเกี่ยวกับ X-Men '97, What If..., Daredevil และอีกมากมาย
Ava Gardner แต่งงานกับ Mickey Rooney และ Frank Sintra และเธอยังคบหาดูใจกับดาราฮอลลีวูดอีกหลายคน ต่อไปนี้คือประวัติการออกเดทของ Ava Gardner
จอห์น คลีส แต่งงานกับเจนนิเฟอร์ เวด ภรรยาของเขาในปี 2012 นี่คือทุกสิ่งที่คุณต้องรู้เกี่ยวกับเจนนิเฟอร์ เวด ภรรยาของจอห์น คลีส
Michael C. Hall แต่งงานกับ Morgan Macgregor ภรรยาของเขาตั้งแต่ปี 2016 นี่คือทุกสิ่งที่คุณต้องการทราบเกี่ยวกับภรรยาของ Michael C. Hall
Mena Suvari แต่งงานกับ Michael Hope สามีของเธอมาตั้งแต่ปี 2018 นี่คือทุกสิ่งที่ควรรู้เกี่ยวกับสามีของ Mena Suvari
มันทำให้ฉันประหลาดใจ ทันใดนั้นมันก็เกิดขึ้นบ่อยๆ มันอยู่กลางทางอีกครั้ง <ไม่ ไม่ใช่คนในมหาสมุทรแปซิฟิก คุณเป็นสีน้ำตาลแดง คนที่งานคาร์นิวัล> ทุกพาดหัวข่าวดัง…..
ในปี 2022 ด้วยการเปิดตัว GPT-3 ทักษะการเขียนดูเหมือนจะมีความสำคัญน้อยลง ด้วย AI คนที่เขียนไม่ดีก็สามารถสร้างพนักงานที่มีคุณภาพได้เช่นกัน
ในโลกที่เปลี่ยนแปลงอย่างรวดเร็วและการแข่งขันในปัจจุบัน อาชีพของคนๆ หนึ่งมีบทบาทสำคัญในการเติบโตส่วนบุคคล ความมั่นคงทางการเงิน และความพึงพอใจในชีวิตโดยรวม อย่างไรก็ตาม ผู้คนจำนวนมากพบว่าตัวเองติดอยู่ในวงจรของความเมื่อยล้าและความไม่พอใจอย่างไม่หยุดยั้ง ค่อยๆ สูญเสียชีวิตการทำงานไป
เมื่อสัปดาห์ที่แล้วฉันสังเกตเห็นข่าวประชาสัมพันธ์ที่เผยแพร่ผ่าน PressGazette (เว็บไซต์ข่าวของสื่ออังกฤษ) บทความประกาศว่า Acast ซึ่งเป็นบริษัทโฮสติ้งและโฆษณาพอดคาสต์ของ Scandi จะเป็นผู้นำกลุ่มผู้เผยแพร่ "อาจมีอิทธิพลมากที่สุด" ในพอดคาสต์