1. PreferenceKey 偏好键的基本使用
1.1 创建偏好键的基本使用视图 PreferenceKeyBootcamp.swift
import SwiftUI
/// 偏好/首选项键
struct PreferenceKeyBootcamp: View {
@State private var text: String = "Hello, world!"
var body: some View {
NavigationView {
VStack {
SecondaryScreen(text: text)
.navigationTitle("Navigation Title")
}
}
.onPreferenceChange(CustomTitlePreferenceKey.self) { value in
if !value.isEmpty {
self.text = value
}
}
}
}
extension View{
/// 自定义标题
func customTitle(_ text: String) -> some View {
preference(key: CustomTitlePreferenceKey.self, value: text)
}
}
/// 辅助屏幕
struct SecondaryScreen: View{
let text: String
@State private var newValue: String = ""
init(text: String) {
self.text = text
}
var body: some View{
Text(text)
.onAppear {
getDataFromDatabase()
}
.customTitle(newValue)
}
private func getDataFromDatabase(){
// 模拟数据
DispatchQueue.main.asyncAfter(deadline: .now() + 2.0) {
self.newValue = "NEW value from database"
}
}
}
/// 自定义标题首选项键
struct CustomTitlePreferenceKey: PreferenceKey{
static var defaultValue: String = ""
// 换算
static func reduce(value: inout String, nextValue: () -> String) {
value = nextValue()
}
}
struct PreferenceKeyBootcamp_Previews: PreviewProvider {
static var previews: some View {
PreferenceKeyBootcamp()
}
}
1.2 效果图:
![](https://i-blog.csdnimg.cn/blog_migrate/c0da71bc20f158372c6825c2e04563be.gif)
2. GeometryPreferenceKey 几何视图偏好键来获取视图大小设置其他视图大小的使用
2.1 创建几何视图偏好键视图 GeometryPreferenceKeyBootcamp.swift
import SwiftUI
/// 几何视图 首选项/偏好键 来获取视图大小设置其他视图大小
struct GeometryPreferenceKeyBootcamp: View {
@State private var rectSize: CGSize = .zero
var body: some View {
VStack {
// 根据几何阅读器和偏好设置键 获取其他 View 大小参数,设置到此 View 的大小
Text("Hello, world!")
.frame(width: rectSize.width, height: rectSize.height)
.background(Color.blue)
//Spacer()
HStack {
Rectangle()
// 几何阅读器
GeometryReader { geo in
Rectangle()
.updateRectangleGeoSize(geo.size)
}
Rectangle()
}
.frame(height: 55)
}
.onPreferenceChange(RectangleGeometrySizePreferenceKey.self) { value in
self.rectSize = value
}
}
}
extension View{
/// 更新值
func updateRectangleGeoSize(_ size: CGSize) -> some View{
preference(key: RectangleGeometrySizePreferenceKey.self, value: size)
}
}
/// 矩形几何大小偏好键
struct RectangleGeometrySizePreferenceKey: PreferenceKey{
static var defaultValue: CGSize = .zero
//减少 下一个
static func reduce(value: inout CGSize, nextValue: () -> CGSize) {
value = nextValue()
}
}
struct GeometryPreferenceKeyBootcamp_Previews: PreviewProvider {
static var previews: some View {
GeometryPreferenceKeyBootcamp()
}
}
2.2 效果图:
![](https://i-blog.csdnimg.cn/blog_migrate/bd3742e0648be0ccf46b049111e5df7a.png)
3. ScrollViewOffsetPreferenceKey 滚动视图偏移量设置偏好键来更新标题的使用
3.1 创建滚动偏移量偏好键视图 ScrollViewOffsetPreferenceKeyBootcamp.swift
import SwiftUI
/// 首选项 / 偏好键
struct ScrollViewOffsetPreferenceKey: PreferenceKey{
static var defaultValue: CGFloat = 0
static func reduce(value: inout CGFloat, nextValue: () -> CGFloat) {
value = nextValue()
}
}
extension View{
func onScrollViewOffsetChange(action: @escaping (_ offset: CGFloat) -> Void) -> some View{
background(
GeometryReader { geo in
Text("")
.preference(key: ScrollViewOffsetPreferenceKey.self, value: geo.frame(in: .global).minY)
}
)
.onPreferenceChange(ScrollViewOffsetPreferenceKey.self) { value in
action(value)
}
}
}
/// 滚动视图偏移首选项/偏好键
struct ScrollViewOffsetPreferenceKeyBootcamp: View {
let title: String = "New title here!!!"
@State private var scrollViewOffset: CGFloat = 0
var body: some View {
ScrollView {
VStack {
titleLayer.opacity(Double(scrollViewOffset / 75.0))
.onScrollViewOffsetChange { value in
self.scrollViewOffset = value
}
contentLayer
}
.padding()
}
.overlay(Text("\(scrollViewOffset)"))
.overlay(navBarLayer.opacity(scrollViewOffset < 52 ? 1.0 : 0.0), alignment: .top)
}
}
/// 扩展类
extension ScrollViewOffsetPreferenceKeyBootcamp{
/// 文本布局
private var titleLayer: some View{
Text(title)
.font(.largeTitle)
.fontWeight(.semibold)
.frame(maxWidth: .infinity, alignment: .leading)
}
/// 内容布局
private var contentLayer: some View{
ForEach(0 ..< 30) { _ in
RoundedRectangle(cornerRadius: 10)
.fill(Color.orange.opacity(0.3))
.frame(width: 300, height: 200)
}
}
/// 导航栏布局
private var navBarLayer: some View{
Text(title)
.font(.headline)
.frame(maxWidth: .infinity)
.frame(height: 55)
.background(Color.accentColor)
}
}
struct ScrollViewOffsetPreferenceKeyBootcamp_Previews: PreviewProvider {
static var previews: some View {
ScrollViewOffsetPreferenceKeyBootcamp()
}
}
3.2 效果图:
![](https://i-blog.csdnimg.cn/blog_migrate/579572b9b8110da2cd47999f25a444ff.gif)