1. Basic use of PreferenceKey preference key
1.1 Create a basic usage view of the preference key PreferenceKeyBootcamp.swift
import SwiftUI
/// Preferences/Preferences key
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{
/// Custom title
func customTitle(_ text: String) -> some View {
preference(key: CustomTitlePreferenceKey.self, value: text)
}
}
/// Auxiliary screen
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(){
// simulate data
DispatchQueue.main.asyncAfter(deadline: .now() + 2.0) {
self.newValue = "NEW value from database"
}
}
}
/// Custom title preference key
struct CustomTitlePreferenceKey: PreferenceKey{
static var defaultValue: String = ""
// Conversion
static func reduce(value: inout String, nextValue: () -> String) {
value = nextValue()
}
}
struct PreferenceKeyBootcamp_Previews: PreviewProvider {
static var previews: some View {
PreferenceKeyBootcamp()
}
}
1.2 Rendering:
2. GeometryPreferenceKey The geometry view preference key is used to obtain the view size and set other view sizes
2.1 Create geometry view preference key view GeometryPreferenceKeyBootcamp.swift
import SwiftUI
/// Geometry View Preferences/Preferences key to get the view size and set other view sizes
struct GeometryPreferenceKeyBootcamp: View {
@State private var rectSize: CGSize = .zero
var body: some View {
VStack {
// Get other View size parameters based on the geometry reader and preference keys, and set them to the size of this View
Text("Hello, world!")
.frame(width: rectSize.width, height: rectSize.height)
.background(Color.blue)
//Spacer()
HStack {
Rectangle()
// Geometry reader
GeometryReader { geo in
Rectangle()
.updateRectangleGeoSize(geo.size)
}
Rectangle()
}
.frame(height: 55)
}
.onPreferenceChange(RectangleGeometrySizePreferenceKey.self) { value in
self.rectSize = value
}
}
}
extension View{
/// Update value
func updateRectangleGeoSize(_ size: CGSize) -> some View{
preference(key: RectangleGeometrySizePreferenceKey.self, value: size)
}
}
/// Rectangular geometry size preference key
struct RectangleGeometrySizePreferenceKey: PreferenceKey{
static var defaultValue: CGSize = .zero
//Reduce next
static func reduce(value: inout CGSize, nextValue: () -> CGSize) {
value = nextValue()
}
}
struct GeometryPreferenceKeyBootcamp_Previews: PreviewProvider {
static var previews: some View {
GeometryPreferenceKeyBootcamp()
}
}
2.2 Rendering:
3. ScrollViewOffsetPreferenceKey uses the scroll view offset to set the preference key to update the title
3.1 Create a scroll offset preference key view ScrollViewOffsetPreferenceKeyBootcamp.swift
import SwiftUI
/// Preferences / Preference Keys
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)
}
}
}
/// Scroll view offset preferences/preference keys
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 class
extensionScrollViewOffsetPreferenceKeyBootcamp{
/// Text layout
private var titleLayer: some View{
Text(title)
.font(.largeTitle)
.fontWeight(.semibold)
.frame(maxWidth: .infinity, alignment: .leading)
}
/// Content layout
private var contentLayer: some View{
ForEach(0 ..< 30) { _ in
RoundedRectangle(cornerRadius: 10)
.fill(Color.orange.opacity(0.3))
.frame(width: 300, height: 200)
}
}
/// Navigation bar layout
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 Rendering: