5
3

More than 1 year has passed since last update.

お題は不問!Qiita Engineer Festa 2023で記事投稿!

【SwiftUI】ぼかしのナビゲーションバー

Posted at

はじめに

実装

import SwiftUI

extension View {
    func onChangeParentScrollViewOffset(perform: @escaping (CGFloat) -> Void) -> some View {
        self.background(GeometryReader {
            Color.clear.preference(
                key: OffsetYPreferenceKey.self,
                value: $0.frame(in: .global).origin.y
            )
        }).onPreferenceChange(
            OffsetYPreferenceKey.self,
            perform: perform
        )
    }
}

struct OffsetYPreferenceKey: PreferenceKey {
    static var defaultValue = CGFloat.zero
    static func reduce(value: inout CGFloat, nextValue: () -> CGFloat) {
        value += nextValue()
    }
}
import SwiftUI

struct NavigationBlurView<T: View>: View {
    @State private var offsetY = CGFloat.zero
    
    private var title: String

    private var navigationHeight: CGFloat
    
    private var content: () -> T
    
    init(_ title: String, navigationHeight: CGFloat = 70.0, content: @escaping () -> T) {
        self.title = title
        self.navigationHeight = navigationHeight
        self.content = content
    }

    var body: some View {
        ScrollView(.vertical, showsIndicators: false) {
            content()
                .padding(.top, navigationHeight + 30)
                .onChangeParentScrollViewOffset { offsetY in
                    self.offsetY = offsetY
                }
        }
        .overlay(alignment: .top, content: navigationBar)
        .animation(.spring(), value: offsetY)
    }

    private func navigationBar() -> some View {
        ZStack(alignment: .center) {
            Color.clear.background(.ultraThinMaterial.opacity(offsetY < 0 ? 1 : 0))
                .padding(.top, -navigationHeight)
                .padding(.horizontal, -20)
                .blur(radius: 15)

            HStack(spacing: 15) {
                Text(title)
                    .font(.system(size: offsetY < 0 ? 25 : 30))
                    .fontWeight(.heavy)
                    .foregroundStyle(.white)
                    .lineLimit(1)

                Spacer()

                Button {
                } label: {
                    Image(systemName: "yensign.circle.fill")
                        .foregroundStyle(offsetY < 0 ? .white : .purple)
                }
                .padding(5)
                .background(.thickMaterial, in: RoundedRectangle(cornerRadius: 10))
                
                Button {
                } label: {
                    Image(systemName: "moon.haze.fill")
                        .foregroundStyle(offsetY < 0 ? .white : .purple)
                }
                .padding(5)
                .background(.thickMaterial, in: RoundedRectangle(cornerRadius: 10))
            }
            .frame(maxWidth: .infinity)
            .padding(.top, offsetY < 0 ? 0 : 10)
            .padding(.horizontal, 20)
        }
        .frame(height: navigationHeight, alignment: .top)
    }
}

使い方

import SwiftUI

struct ContentView: View {
    var body: some View {
        NavigationBlurView("NavigationBlur") {
            VStack(spacing: 10) {
                ForEach(0..<100) { _ in
                    Image("sample")
                        .resizable()
                        .aspectRatio(contentMode: .fit)
                        .frame(maxWidth: .infinity)
                }
            }
        }
    }
}

おわり

右側のボタンもカスタムできるようにしたらライブラリにでもしようかな、、、

5
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
3