Open Phangg opened 1 month ago
μ±μμ λ³΄ν΅ μ΄λ° 곡μ λ₯Ό μν μνΈλ₯Ό SharePanel μ΄λΌκ³ νν ( ShareSheet ) κ·Έλ λ€λ©΄ iOS μμλ μ΄λ»κ² μ κΈ°λ₯μ μ¬μ©ν μ μμκΉ? UI λ₯Ό λ΄λΉνλ 2κ°μ§μ νλ μμν¬μμ κ°κ° μμ보μ
μ μ½λμ μ£Όμμ²λΌ ShareLink
μμ
곡μ ν μμ΄ν
(item), μμ΄ν
μ μ΄λ¦(subject)κ³Ό μ€λͺ
(message), 미리보기 μ΄λ―Έμ§ λ±(preview)μ μ€μ ν μ μμ
λν, μμ΄ν μλ νμ μ΄ μ ν΄μ Έμμ§ μμμ μ μ μμ ( 곡μλ¬Έμ μ°Έκ³ )
μ΄λ, λ§μ½ 컀μ€ν ν νμ μ 곡μ νλ €κ³ νλ€λ©΄?
Transferable
νλ‘ν μ½μ μ±ννκ³ μμ΄μΌ ν¨ ( μ λ¬ κ°λ₯ν κ°μ²΄ ) URLμ λΉλ‘―ν κΈ°λ³Έμ μΈ νμ μ 보면Transferable
νλ‘ν μ½μ μ±ννκ³ μμ
λ§μ§λ§μΌλ‘ ShareLink
λ₯Ό μ¬μ©νλ μ½λ μμ
ToolbarItem(placement: .topBarTrailing) {
// 곡μ νκΈ°
ShareLink(item: "\(user.userName)λμ κ²μκΈ", // μ€μ λ κΈμ λ₯λ§ν¬λ₯Ό 곡μ ν΄μΌνμ§λ§ μμμμ ν
μ€νΈλ§ 곡μ
subject: Text("\(post.title)"),
message: Text("\(AppLocalized.AppName) μμ κ²μκΈμ 곡μ νμ΄μ!"),
// 미리보기
preview: SharePreview(
Text("\(user.userName)λμ κ²μκΈ"),
image: Image(ViewValues.AppIcon))
) {
Image(systemName: "square.and.arrow.up")
}
}
iOS 6 λΆν° μ§μλκ³ μλ κΈ°λ₯
SharePanel ( ShareSheet ) λ₯Ό 컨νΈλ‘€
곡μλ¬Έμλ₯Ό 보면
κΈ°λ³Έμ μΈ νμ
λ€ νΉμ UIActivityItemSource
νλ‘ν μ½μ λ°λ₯΄λ μμ΄ν
μ 곡μ κ°λ₯ ν κ²μ μ μ μμ
SwiftUI μμ Transferable μ μ±νν μμ΄ν μ²λΌ, UIKit μμλ UIActivityItemSource λ₯Ό μ±νν΄μΌ ν¨
λ΄κ° μ¬μ©νλ UIActivityViewController μ½λ μμ
SwiftUI + TCA μ½λ
// MARK: - ActivityView ( SharePanel ) // UIKit μ UIActivityViewController λ₯Ό SwiftUI μ μ΄μνκΈ° μν¨ struct ActivityView: UIViewControllerRepresentable { @Bindable var store: StoreOf<SettingViewFeature>
func makeUIViewController( context: Context ) -> UIViewController { UIViewController() }
func updateUIViewController( uiViewController: UIViewController, context: Context ) { // store λ TCA μ 리λμ // var activityItem: ActivityItem? μ΄λ κ² λ³μλ₯Ό κ°μ§κ³ μμ let activityViewController = UIActivityViewController( activityItems: store.activityItem?.items ?? [], applicationActivities: store.activityItem?.activities) if store.isActivityViewPresented, uiViewController.presentedViewController == nil { uiViewController.present(activityViewController, animated: true) } activityViewController.completionWithItemsHandler = { (, , , _) in store.send(.closeActivityView) } } }
// MARK: - ActivityItem // UIActivityViewController μ activityItems μ λ€μ΄κ° ꡬ쑰체 νμ μμ± struct ActivityItem: Equatable { var items: [ActivityItemSource] // Any κ° μλ, ActivityItemSource νμ μ μ¬μ© var activities: [UIActivity]? var excludedTypes: [UIActivity.ActivityType]
static func == (lhs: ActivityItem, rhs: ActivityItem) -> Bool {
lhs.activities == rhs.activities
}
// items: `UIActivityViewController` λ₯Ό ν΅ν΄ 곡μ ν μμ΄ν
// activities: μνΈμ ν¬ν¨μν€κ³ μ νλ 컀μ€ν
`UIActivity`
init(
items: [ActivityItemSource],
activities: [UIActivity]? = nil,
excludedTypes: [UIActivity.ActivityType] = []
) {
self.items = items
self.activities = activities
self.excludedTypes = excludedTypes
}
}
```swift
// MARK: - Custom λ ActivityItemSource
// μμ΄ν
νμ
컀μ€ν
- UIActivityItemSource μ±ν
final class ActivityItemSource: NSObject, UIActivityItemSource {
private let url: URL
init(url: URL) {
self.url = url
super.init()
}
func activityViewControllerPlaceholderItem(
_ activityViewController: UIActivityViewController
) -> Any {
return url
}
func activityViewController(
_ activityViewController: UIActivityViewController,
itemForActivityType activityType: UIActivity.ActivityType?
) -> Any? {
return url
}
func activityViewController(
_ activityViewController: UIActivityViewController,
subjectForActivityType activityType: UIActivity.ActivityType?
) -> String {
return AppLocalized.fileDescription
}
func activityViewController(
_ activityViewController: UIActivityViewController,
thumbnailImageForActivityType activityType: UIActivity.ActivityType?,
suggestedSize size: CGSize
) -> UIImage? {
return UIImage(named: AppLocalized.appIcon) ?? UIImage()
}
func activityViewControllerLinkMetadata(
_ activityViewController: UIActivityViewController)
-> LPLinkMetadata? {
let metadata = LPLinkMetadata()
metadata.iconProvider = NSItemProvider(
object: UIImage(named: AppLocalized.appIcon) ?? UIImage())
metadata.title = url.lastPathComponent
let size = url.formattedFileSize()
let type = AppLocalized.fileDescription
let subtitleString = "\(type) \(size)"
metadata.originalURL = URL(fileURLWithPath: subtitleString)
return metadata
}
}
ShareLink - κ·Έλ¦° λΈλ‘κ·Έ ShareLink - appcoda κΈ UIActivityViewController - 곡μλ¬Έμ UIActivityViewController / UIActivityItemSource - 곡μλ¬Έμ UIActivityViewController - ActivityType κ΄λ ¨ UIActivityViewController - medium λΈλ‘κ·Έ UIActivityViewController - μ medium λΈλ‘κ·Έ GitHub μ½λ UIActivityViewController / Metadata - λΈλ‘κ·Έ
iOS μ SharePanel ?
SwiftUI - ShareLink
UIKit - UIActivityViewController