1. 導(dǎo)航欄組件的尺寸
public struct HDSizeHook: PreferenceKey, ViewModifier {
public static var defaultValue: CGSize = .zero
public static func reduce(value: inout CGSize, nextValue: () -> CGSize) {
value = nextValue()
}
@Binding var value: CGSize
@State var sValue: CGSize = .zero
var onChanged: ((CGSize) -> Void)?
public init(value: Binding<CGSize>) {
self._value = value
}
public init(_ changed: @escaping (CGSize) -> Void) {
self._value = .constant(.zero)
self.onChanged = changed
}
public func body(content: Content) -> some View {
content.background(
GeometryReader { rp in
Color.clear
.preference(key: HDSizeHook.self, value: rp.size)
.onPreferenceChange(HDSizeHook.self) { value in
self.value = value
onChanged?(value)
}
}
)
}
}
2. 各組件的布局方法
public struct HDNavigationView<Content>: View where Content: View {
@State var maxItemWidth: CGFloat = 0
let content: () -> Content
var title: String = ""
var leftItems: () -> AnyView = {
AnyView(
Image(.back)
.padding(.horizontal, 15)
.padding(.vertical, 10)
.background(Color(.kTheme239()))
.onTapGesture {
Router.pop()
}
)
}
var rightItems: () -> AnyView = {
AnyView(EmptyView())
}
public init(@ViewBuilder content: @escaping () -> Content) {
self.content = content
}
public var body: some View {
GeometryReader { proxy in
VStack(spacing: 0) {
HStack(spacing: 0) {
HStack {
leftItems()
}
.modifier(HDSizeHook{ value in
maxItemWidth = max(maxItemWidth, value.width)
})
.frame(minWidth: maxItemWidth, alignment: .leading)
Spacer()
Text(title)
.multilineTextAlignment(.center)
Spacer()
HStack {
rightItems()
}
.modifier(HDSizeHook{ value in
maxItemWidth = max(maxItemWidth, value.width)
})
.frame(minWidth: maxItemWidth, alignment: .trailing)
}
.frame(width: proxy.size.width, height: 44)
.background(Color(.kTheme239()).edgesIgnoringSafeArea(.top))
.foregroundColor(.white)
.font(.system(size: 18))
content()
}
}
}
public func navigationTitle(_ title: String) -> Self {
var view = self
view.title = title
return view
}
public func navigationLeftItems<LeftContent>(@ViewBuilder items: @escaping () -> LeftContent) -> Self where LeftContent: View {
var view = self
view.leftItems = {
AnyView(items())
}
return view
}
public func navigationRightItems<RightContent>(@ViewBuilder items: @escaping () -> RightContent) -> Self where RightContent: View {
var view = self
view.rightItems = {
AnyView(items())
}
return view
}
}