Created
March 7, 2025 16:19
-
-
Save Chronos2500/66d1b18fda49a5c0c83485ab1f9fc321 to your computer and use it in GitHub Desktop.
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 characters
| 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()) | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment