Created
March 7, 2025 16:19
-
-
Save Chronos2500/66d1b18fda49a5c0c83485ab1f9fc321 to your computer and use it in GitHub Desktop.
Revisions
-
Chronos2500 created this gist
Mar 7, 2025 .There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,77 @@ import SwiftUI //自作パッケージの切り出しなので変数名がめちゃくちゃです //詳しくはこれの実装を見てください https://github.com/Chronos2500/CustomNavigationTitle struct ContentView: View { var body: some View { NavigationStack{ ScrollView { Color.blue.frame(height: 200) .titleVisibilityAnchor() Text("サンプルページ") .frame(maxWidth: .infinity,alignment: .center) } .scrollAwareTitle() } } } struct BoundsPreferenceKey: PreferenceKey { typealias Value = Anchor<CGRect>? static let defaultValue: Value = nil static func reduce(value: inout Value, nextValue: () -> Value) { guard let newValue = nextValue() else { return } value = newValue } } extension View { public func titleVisibilityAnchor() -> some View { self.anchorPreference( key: BoundsPreferenceKey.self, value: .bounds ) { anchor in anchor } } } private struct ScrollAwareTitleModifier: ViewModifier { @State var isShowNavigationTitle = false func body(content: Content) -> some View { content .backgroundPreferenceValue(BoundsPreferenceKey.self) { anchor in GeometryReader { proxy in if let anchor = anchor { let scrollFrame = proxy.frame(in: .local).minY let itemFrame = proxy[anchor] let isVisible = (itemFrame.maxY + 22) > scrollFrame DispatchQueue.main.async{ if isVisible { isShowNavigationTitle = false } else if !isVisible { isShowNavigationTitle = true } } } return Color.clear } } .toolbarBackgroundVisibility(.hidden, for: .navigationBar) .toolbar { ToolbarItem(placement: .topBarTrailing) { Image(systemName: "xmark.circle.fill") .imageScale(.large) .foregroundStyle(isShowNavigationTitle ? .blue : .red) .animation(.easeIn(duration: 0.15), value: isShowNavigationTitle) } } } } extension View { public func scrollAwareTitle() -> some View { modifier(ScrollAwareTitleModifier()) } }