美文网首页
SwiftUI框架详细解析 (二十一) —— 基于SwiftUI

SwiftUI框架详细解析 (二十一) —— 基于SwiftUI

作者: 刀客传奇 | 来源:发表于2021-01-07 22:06 被阅读0次

版本记录

版本号 时间
V1.0 2021.01.07 星期四

前言

今天翻阅苹果的API文档,发现多了一个框架SwiftUI,这里我们就一起来看一下这个框架。感兴趣的看下面几篇文章。
1. SwiftUI框架详细解析 (一) —— 基本概览(一)
2. SwiftUI框架详细解析 (二) —— 基于SwiftUI的闪屏页的创建(一)
3. SwiftUI框架详细解析 (三) —— 基于SwiftUI的闪屏页的创建(二)
4. SwiftUI框架详细解析 (四) —— 使用SwiftUI进行苹果登录(一)
5. SwiftUI框架详细解析 (五) —— 使用SwiftUI进行苹果登录(二)
6. SwiftUI框架详细解析 (六) —— 基于SwiftUI的导航的实现(一)
7. SwiftUI框架详细解析 (七) —— 基于SwiftUI的导航的实现(二)
8. SwiftUI框架详细解析 (八) —— 基于SwiftUI的动画的实现(一)
9. SwiftUI框架详细解析 (九) —— 基于SwiftUI的动画的实现(二)
10. SwiftUI框架详细解析 (十) —— 基于SwiftUI构建各种自定义图表(一)
11. SwiftUI框架详细解析 (十一) —— 基于SwiftUI构建各种自定义图表(二)
12. SwiftUI框架详细解析 (十二) —— 基于SwiftUI创建Mind-Map UI(一)
13. SwiftUI框架详细解析 (十三) —— 基于SwiftUI创建Mind-Map UI(二)
14. SwiftUI框架详细解析 (十四) —— 基于Firebase Cloud Firestore的SwiftUI iOS程序的持久性添加(一)
15. SwiftUI框架详细解析 (十五) —— 基于Firebase Cloud Firestore的SwiftUI iOS程序的持久性添加(二)
16. SwiftUI框架详细解析 (十六) —— 基于SwiftUI简单App的Dependency Injection应用(一)
17. SwiftUI框架详细解析 (十七) —— 基于SwiftUI简单App的Dependency Injection应用(二)
18. SwiftUI框架详细解析 (十八) —— Firebase Remote Config教程(一)
19. SwiftUI框架详细解析 (十九) —— Firebase Remote Config教程(二)
20. SwiftUI框架详细解析 (二十) —— 基于SwiftUI的Document-Based App的创建(一)

源码

1. Swift

首先看下工程组织结构

下面就是源码了

1. MemeMakerApp.swift
import SwiftUI

@main
struct MemeMakerApp: App {
  var body: some Scene {
    DocumentGroup(newDocument: MemeMakerDocument()) { file in
      ContentView(document: file.$document)
    }
  }
}
2. MemeMakerDocument.swift
import SwiftUI
import UniformTypeIdentifiers

extension UTType {
  static let memeDocument = UTType(exportedAs: "com.raywenderlich.MemeMaker.meme")
}

struct MemeMakerDocument: FileDocument {
  var meme: Meme

  init(imageData: Data? = nil, topText: String = "Top Text", bottomText: String = "Bottom Text") {
    self.meme = Meme(imageData: imageData, topText: topText, bottomText: bottomText)
  }

  static var readableContentTypes: [UTType] { [.memeDocument] }

  init(configuration: ReadConfiguration) throws {
    guard let data = configuration.file.regularFileContents else {
      throw CocoaError(.fileReadCorruptFile)
    }
    meme = try JSONDecoder().decode(Meme.self, from: data)
  }

  func fileWrapper(configuration: WriteConfiguration) throws -> FileWrapper {
    let data = try JSONEncoder().encode(meme)
    return .init(regularFileWithContents: data)
  }
}
3. MemeTextField.swift
import SwiftUI

struct MemeTextField: View {
  @Binding var text: String

  var body: some View {
    TextField(text, text: $text)
      .multilineTextAlignment(.center)
      .lineLimit(nil)
      .foregroundColor(.black)
      .font(Font.system(size: 25, weight: .bold))
      .textCase(.uppercase)
  }
}

struct MemeTextField_Previews: PreviewProvider {
  static var previews: some View {
    MemeTextField(text: .constant("This is some Text"))
  }
}
4. ContentView.swift
import SwiftUI

struct ContentView: View {
  @Binding var document: MemeMakerDocument

  var body: some View {
    MemeEditor(meme: $document.meme)
  }
}

struct ContentView_Previews: PreviewProvider {
  static var previews: some View {
    ContentView(document: .constant(MemeMakerDocument()))
  }
}
5. Meme.swift
import Foundation

struct Meme: Codable {
  var imageData: Data?
  var topText: String
  var bottomText: String
}
6. ImageLayer.swift
import SwiftUI

struct ImageLayer: View {
  @Binding var imageData: Data?

  var body: some View {
    NSUIImage.image(fromData: imageData ?? Data())
      .resizable()
      .aspectRatio(contentMode: .fit)
  }
}

struct ImageLayer_Previews: PreviewProvider {
  // swiftlint:disable:next force_unwrapping
  static let imageData = NSUIImage(named: "AppIcon")!.data

  static var previews: some View {
    ImageLayer(imageData: .constant(imageData))
      .previewLayout(.fixed(width: 100, height: 100))
  }
}
7. TextLayer.swift
import SwiftUI

struct TextLayer<ImageContent: View>: View {
  @Binding var meme: Meme
  let imageContent: () -> ImageContent

  var body: some View {
    ZStack(alignment: .bottom) {
      ZStack(alignment: .top) {
        imageContent()
        MemeTextField(text: $meme.topText)
      }

      MemeTextField(text: $meme.bottomText)
    }
  }
}

struct TextLayer_Previews: PreviewProvider {
  @State static var meme = Meme(
    imageData: nil,
    topText: "Top Text Test",
    bottomText: "Bottom Text Test"
  )

  static var previews: some View {
    TextLayer(meme: $meme) {
      Text("IMAGE")
        .frame(height: 100)
    }
  }
}
8. UIImagePicker.swift
import SwiftUI

struct UIImagePicker: UIViewControllerRepresentable {
  class Coordinator: NSObject, UINavigationControllerDelegate, UIImagePickerControllerDelegate {
    let parent: UIImagePicker

    init(_ parent: UIImagePicker) {
      self.parent = parent
    }

    func imagePickerController(
      _ picker: UIImagePickerController,
      didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey: Any]
    ) {
      if let uiImage = info[.originalImage] as? UIImage {
        parent.image = uiImage
      }

      parent.presentationMode.wrappedValue.dismiss()
    }
  }

  @Environment(\.presentationMode) var presentationMode
  @Binding var image: UIImage?

  func makeCoordinator() -> Coordinator {
    Coordinator(self)
  }

  func makeUIViewController(
    context: UIViewControllerRepresentableContext<UIImagePicker>
  ) -> UIImagePickerController {
    let picker = UIImagePickerController()
    picker.delegate = context.coordinator
    return picker
  }

  func updateUIViewController(
    _ uiViewController: UIImagePickerController,
    context: UIViewControllerRepresentableContext<UIImagePicker>
  ) {
  }
}
9. NSUIImage_iOS.swift
import UIKit
import SwiftUI

public typealias NSUIImage = UIImage

extension NSUIImage {
  var data: Data? {
    return self.pngData()
  }

  static func image(fromData data: Data) -> Image {
    return Image(uiImage: UIImage(data: data) ?? UIImage())
  }
}
10. MemeEditor_iOS.swift
import SwiftUI

struct MemeEditor: View {
  @Binding var meme: Meme
  @State var showingImagePicker = false
  @State private var inputImage: NSUIImage?

  func loadImage() {
    guard let inputImage = inputImage else { return }
    meme.imageData = inputImage.data
  }

  var body: some View {
    TextLayer(meme: $meme) {
      Button {
        showingImagePicker = true
      } label: {
        if meme.imageData != nil {
          ImageLayer(imageData: $meme.imageData)
        } else {
          Text("Add Image")
            .foregroundColor(.white)
            .padding()
            .background(Color("rw-green"))
            .cornerRadius(30)
            .padding(.vertical, 50)
        }
      }
    }
    .sheet(isPresented: $showingImagePicker, onDismiss: loadImage) {
      UIImagePicker(image: self.$inputImage)
    }
  }
}

struct MemeEditor_Previews: PreviewProvider {
  @State static var meme = Meme(
    imageData: nil,
    topText: "Top Text Test",
    bottomText: "Bottom Text Test"
  )

  static var previews: some View {
    MemeEditor(meme: $meme)
  }
}

后记

本篇主要讲述了基于SwiftUIDocument-Based App的创建,感兴趣的给个赞或者关注~~~

相关文章

网友评论

      本文标题:SwiftUI框架详细解析 (二十一) —— 基于SwiftUI

      本文链接:https://www.haomeiwen.com/subject/wgmtaktx.html