はじめに
サイドメニューを実装してみたので備忘録兼ねて残します。
今回はモチベーションアップ、目の保養の為にイメージ画像は綺麗なお姉ちゃんを使いました。
イメージ
実装内容
まずメニュー項目のstructを作成
ForEachで使いたいのでIdentifiableに適合させておきます。
今回、画像はSFシンボル名で設定してImage(systemName:)で呼び出すようにしておきます。
メニュータップ時の遷移は実装していないので、こんな感じで終わりにします。
struct Menu: Identifiable {
enum MenuType: String {
case myAccount = "My Account"
case setting = "Setting"
case favorite = "Favorite"
case faq = "FAQ"
case signOut = "SignOut"
var title: String { self.rawValue }
var imageName: String {
switch self {
case .myAccount: return "person.crop.circle"
case .setting: return "wrench"
case .favorite: return "star.circle"
case .faq: return "questionmark.circle"
case .signOut: return "arrow.turn.up.left"
}
}
}
var id = UUID()
var type: MenuType
}
MenuRowを作る
サイドメニューのリストに表示するRowの構造体を定義します。
Image(systemName:)
で表示する画像はデフォルトでは、少々小さいのでimageScale(.large)
にしたほうが良いようです。
struct MenuRow: View {
var image = ""
var text = ""
var body: some View {
VStack(alignment: .leading) {
HStack {
Image(systemName: image)
.imageScale(.large)
.frame(width: 32, height: 32)
Text(text)
.font(.headline)
Spacer()
}
}
}
}
MenuViewを作る
実際にサイドメニューに表示させるViewを作ります。
名前とフォロー、フォロワーあたりは雑な作りなので、いつか綺麗にします。
先に以下、MenuViewの全体象を載せます。
struct MenuView: View {
var menu = [Menu(type: .myAccount),
Menu(type: .setting),
Menu(type: .favorite),
Menu(type: .faq),
Menu(type: .signOut),]
@Binding var show: Bool
var body: some View {
HStack {
VStack(alignment: .center) {
Image("female")
.resizable()
.scaleEffect(2)
.offset(x: 0, y: 20)
.aspectRatio(5/7, contentMode: .fit)
.frame(width: 100, height: 100)
.clipShape(Circle())
.overlay(
Circle().stroke(Color.white, lineWidth: 4))
.shadow(radius: 10)
Text("Miranda Jeen")
HStack {
VStack {
Text("follow")
Text("211")
}
.padding()
VStack {
Text("follower")
Text("324")
}
.padding()
}
.padding(.vertical)
VStack(alignment: .leading) {
ForEach(menu) { item in
MenuRow(image: item.type.imageName, text: item.type.title)
}
}
Spacer()
}
.padding(.top, 20)
.padding(30)
.frame(width: ScreenSize.width/1.5)
.background(Color.blue.opacity(0.4))
.cornerRadius(20)
.animation(.default)
.offset(x: show ? 0 : -ScreenSize.width)
.onTapGesture {
self.show.toggle()
}
Spacer()
}
.padding(.top, statusBarHeight)
}
}
少し解説
表示制御
showは外部からも制御するので@Bindingをつけて定義しておきます。
@Binding var show: Bool
Imageのレイアウト調節
Image("female")
.resizable()
.scaleEffect(2)
.offset(x: 0, y: 20)
.aspectRatio(5/7, contentMode: .fit)
.frame(width: 100, height: 100)
.clipShape(Circle())
.overlay(
Circle().stroke(Color.white, lineWidth: 4))
.shadow(radius: 10)
イメージをリサイズする場合は、resizable()
をつけます。
scaleEffect
でスケールを少し拡大して、offset
で画像自体の表示位置を微調節します。
aspectRatio(5/7, contentMode: .fit)
でアスペクト比を固定した上でframe(width: 100, height: 100)
でイメージサイズを指定しています。
イメージに枠線を付ける
AppleのLandmarkのチュートリアルにあるような枠線で良かったので、そのまま使用しています。
.clipShape(Circle())
.overlay(
Circle().stroke(Color.white, lineWidth: 4))
.shadow(radius: 10)
ForEachでMenuRowを生成する
Identifiableに適合させたMenuをForEachで回して、MenuRowを生成します。
VStack(alignment: .leading) {
ForEach(menu) { item in
MenuRow(image: item.type.imageName, text: item.type.title)
}
}
サイドメニューの動作とMenuViewのレイアウトを調節する
最後にMenuView直下のHStackとその直下のVStackにレイアウトとサイドメニュー動作を追加します。
var body: some View {
HStack {
VStack(alignment: .center) {
}
....
.padding(.top, 20)
.padding(30)
.frame(width: ScreenSize.width/1.5)
.background(Color.blue.opacity(0.4))
.cornerRadius(20)
.animation(.default)
.offset(x: show ? 0 : -ScreenSize.width)
.onTapGesture {
self.show.toggle()
}
Spacer()
}
.padding(.top, statusBarHeight)
.offset(x: show ? 0 : -ScreenSize.width)
でサイドメニューが非表示状態になっている場合は、画面外の位置に待機させておくようにしています。
こうすることで出しわけることができます。
最後にHStackに対して.padding(.top, statusBarHeight)
で余白をつけて、MenuViewは完成です。
親のViewで呼び出す
これでボタンをタップしたらサイドメニューが表示されるようになりました。
struct SideMenuView: View {
@State var show = false
var body: some View {
ZStack {
Group {
Button(action: {
self.show = true
}) {
Text("show side menu")
}
}
.blur(radius: show ? 20 : 0)
MenuView(show: $show)
}
.edgesIgnoringSafeArea(.all)
}
}
サイドメニューを表示している時にメインのViewを濁したいのでblurを使っていますが、今回は、ボタンしかない真っ白名画面なので濁りませんが、つけています。
.blur(radius: show ? 20 : 0)
ソースコード
SwiftUIのレイアウト学習用のレポジトリです。
申し訳程度のものですが、ちょっとずつあげていきます。
さいごに
UIKitで実装するよりもシンプルな実装で作れました。
サイドメニューを表示するたびに綺麗なお姉さんが表示されて、癒されながら学習することができました。
こういうちょっとした目の保養って大事だなと改めて感じましたw
良かったら使ってみてください。
もっといい案あったり、ご指摘、アドバイスあればお待ちしております。
それでは最後までお読みいただきありがとうございました。