这个库实际代码很少,原理也很简单,组件内嵌入WkWebView用于html标签的字符串渲染。
本文匆匆一撇Swiftui与原生的交互代码。
入口页面
- 入口页面,作者很贴心增加了
placeholder
,用于loading的时候展示 - 组件最终高度为WebView的高度
swift
import SwiftUI
public struct RichText: View {
@State private var dynamicHeight: CGFloat = .zero
let html: String
var configuration: Configuration
var placeholder: AnyView?
public init(html: String, configuration: Configuration = .init(), placeholder: AnyView? = nil) {
self.html = html
self.configuration = configuration
self.placeholder = placeholder
}
public var body: some View {
GeometryReader { proxy in
ZStack(alignment: .top) {
WebView(width: proxy.size.width, dynamicHeight: $dynamicHeight, html: html, configuration: configuration)
if self.dynamicHeight == 0 {
placeholder
}
}
}
.frame(height: dynamicHeight)
}
}
#Preview {
RichText(html: "<h1>Goode</h1> <h1>Night!</h1>",
placeholder: AnyView(Text("waiting..")))
}
import SwiftUI
public struct RichText: View {
@State private var dynamicHeight: CGFloat = .zero
let html: String
var configuration: Configuration
var placeholder: AnyView?
public init(html: String, configuration: Configuration = .init(), placeholder: AnyView? = nil) {
self.html = html
self.configuration = configuration
self.placeholder = placeholder
}
public var body: some View {
GeometryReader { proxy in
ZStack(alignment: .top) {
WebView(width: proxy.size.width, dynamicHeight: $dynamicHeight, html: html, configuration: configuration)
if self.dynamicHeight == 0 {
placeholder
}
}
}
.frame(height: dynamicHeight)
}
}
#Preview {
RichText(html: "<h1>Goode</h1> <h1>Night!</h1>",
placeholder: AnyView(Text("waiting..")))
}
WebView
WebView是一个遵从UIViewRepresentable
协议的结构体,保存了传入配置、读取环境中的换行配置。UIViewRepresentable
用法见[0x06e-UIViewRepresentable]
swift
struct WebView {
@Environment(\.multilineTextAlignment) var alignment
@Binding var dynamicHeight: CGFloat
let html: String
let conf: Configuration
let width: CGFloat
init(width: CGFloat, dynamicHeight: Binding<CGFloat>, html: String, configuration: Configuration) {
self._dynamicHeight = dynamicHeight
self.html = html
self.conf = configuration
self.width = width
}
}
extension WebView :UIViewRepresentable {
// ....
}
struct WebView {
@Environment(\.multilineTextAlignment) var alignment
@Binding var dynamicHeight: CGFloat
let html: String
let conf: Configuration
let width: CGFloat
init(width: CGFloat, dynamicHeight: Binding<CGFloat>, html: String, configuration: Configuration) {
self._dynamicHeight = dynamicHeight
self.html = html
self.conf = configuration
self.width = width
}
}
extension WebView :UIViewRepresentable {
// ....
}
代码太长了,不再贴 https://github.com/NuPlay/RichText/blob/main/Sources/RichText/Views/Webview.swift
代码比较简单,关键点:
- 定义Webview bridge 交互, 网页加载完后通知webview更新高度
- 拦截导航操作,兼容
tel
等协议的链接