バナーを出したい
こんな感じの記述方法で簡単に画面上部にスライドインでバナーを出したい
View
.bannerVisible(with: Binding<Bool>)
できたもの
通知バナーのようなUI作ってみたらアニメーションについてちょっとだけ理解が深まったhttps://t.co/nScc1QzTlb pic.twitter.com/55ifJxBh1y
— Yusuke Miyata (@yuskey38) December 12, 2021
作ってみた
大まかな手順はこの通りです
① Bannar表示用のModifierを作る
② ①で作ったModifierを簡単に使えるようにViewのExtensionを作成する
Modifierを作る
struct Banner: ViewModifier {
@Binding var isShow: Bool
let title: String
let icon: String
let foregroundColor: Color
let backgroundColor: Color
@State private var offset: CGFloat = -100
@State private var opacity: CGFloat = 0
func body(content: Content) -> some View {
let asyncHide = DispatchWorkItem() { hide() }
ZStack {
content
if isShow {
VStack {
bannerView
Spacer()
}
.padding()
.onTapGesture {
asyncHide.cancel()
hide()
}
.onAppear {
show()
DispatchQueue.main.asyncAfter(deadline: .now() + 4, execute: asyncHide)
}
.offset(y: offset)
}
}
}
private var bannerView: some View {
HStack {
Image(systemName: icon)
.opacity(opacity)
Text(title).bold()
.opacity(opacity)
Spacer()
}
.foregroundColor(foregroundColor)
.padding(12)
.background(backgroundColor.opacity(opacity))
.cornerRadius(8)
}
private func show() {
withAnimation(.easeInOut(duration: 0.3)) {
offset = 0
withAnimation(.easeInOut(duration: 0.45)) {
opacity = 0.75
}
}
}
private func hide() {
withAnimation(.easeInOut(duration: 0.3)) {
offset = -100
withAnimation(.easeInOut(duration: 0.2)) {
opacity = 0
self.isShow = false
}
}
}
}
.animation(_ animation:)
がiOS15.0でdeprecatedになるため、show()
やhide()
で独自でoffsetを変更することで上からバナーが出てくるアニメーションを実現しています。
バナーを表示するためにisShow
の値を変えるときに、withAnimation { isShow = true }
と記述すれば独自でoffsetを変更させる必要はないのですが、単にisShow = true
とシンプルに記述したいのでこのようにしました。
Viewのextensionを作る
extension View {
func bannerVisible(with isShown: Binding<Bool>,
title: String = "TEST",
icon: String = "star.fill",
foregroundColor: Color = .white,
backgroundColor: Color = .red) -> some View {
self.navigationBarTitleDisplayMode(.inline)
.modifier(Banner(isShown: isShown,
title: title,
icon: icon,
foregroundColor: foregroundColor,
backgroundColor: backgroundColor
)
)
}
}
ある程度バナーの色などをカスタムできるようにしました。
また,NavigationView
の中で使うとうまく画面トップにバナーが出なかったため
.navigationTitleDisplayMode(.inline)
にして期待通りに位置にバナーを表示できるようにしました。
使い方
struct ContentView: View {
@State private var isShow: Bool = false
var body: some View {
VStack {
Button(action: { isShow = true }) {
Text("バナー表示")
}
}
.bannerVisible(with: $isShow)
}
}
このようにバナーを表示したいViewの最上層のViewに.bannerVisible
を追加すれば使用できます。
参考
バナー
で検索すると広告についての記事ばかりが出てきましたが
この記事を見つけられて良かったです。
↑の記事で作成したModifierを.bannerVisible
と記述すれば使えるようにする方法を探してこの記事に辿り着きました。