Swift初心者がSwiftUIのみでページメニューもどきを作ってみた。

ニュース系のアプリ等は大体画面上部にタブメニューがありますが、そのタブメニューを実装するのに外部ライブラリでは、XLPagerTabStripPageMenuがあるので、そのライブラリを使用する方が良いのかもしれませんが、Swift習得するための一歩としてSwiftUIのみでページメニューもどきを作ってみました。

目 次

  1. 参考とした記事と本
  2. 開発環境
  3. ページメニューもどき実装内容
  4. 全体ソース
  5. ソースコードDownload
  6. 最近購入したコスパが良かったもの

1. 参考とした記事と本

2. 開発環境

  • iMac(Late2012)
  • macOS Catalina(10.15.7)
  • Xcode 12.4
  • Swift 5.3.2
  • 使用外部ライブラリ なし

3. ページメニューもどき実装内容

簡単に書くと下記のことをしております。

  1. 画面上部に横スクロールビューを配置。(ScrollView)
  2. 横スクロールビュー内にボタンを3つ作成する。
  3. 横スクロールビューの下部全体を切り替えするビューとする。
  4. 切り替えするビューを3つ作成する。
  5. ボタンをタップすると文字等を強調表示して画面を切り替える。

※尚、ボタンやビューの部分をそれぞれ増やしていくことでメニューを増やしていくことは出来ますが冗長になってしまいます。

スクリーンショット

4. 全体ソース

全体ソースですが動くことを大前提に作りましたのでかなり無駄が多いソースになっております。
表示するメニュー(ボタン)を増やしていくと、その分コード量も増えていくので実際のアプリに実装するのには全く向いていません。
クラス化したら使えるかもしれませんが、管理人の力量が付いたらやってみるかもしれません。
ほんの少しでも参考になれば嬉しいです。(^^)

<div class="hcb_wrap">
<pre class="prism line-numbers lang-swift" data-lang="Swift"><code>//
//  ContentView.swift
//  PageMenuView
//
//  Created by Assy on 2021/10/03.
//

import SwiftUI

struct ContentView: View {
    
    //列挙体(画面遷移する画面を作成、ここでは3つ)
    enum display {
        case first
        case second
        case third
    }
    
    //表示する画面の初期値
    @State var displayMode = display.first
    
    //ページメニューのボタンとViewを紐付けするプロパティ
    @State var page1 = true
    @State var page2 = false
    @State var page3 = false
    
    var body: some View {
        
        VStack {
            ScrollView (.horizontal, showsIndicators: false){
                HStack{
                    
                    //1つ目のボタン
                    Button(action: {
                        displayMode = display.first
                        self.page1 = true
                        self.page2 = false
                        self.page3 = false
                        
                    }) {
                        if page1 == true {
                            SelectedMenu("ページ1")
                        } else if page1 == false {
                            unSelectedMenu("ページ1")
                        }
                    }
                    
                    //2つ目のボタン
                    Button(action: {
                        displayMode = display.second
                        self.page1 = false
                        self.page2 = true
                        self.page3 = false
                    }) {
                        if page2 == true {
                            SelectedMenu("ページ2")
                        } else if page2 == false {
                            unSelectedMenu("ページ2")
                        }
                    }
                    
                    //3つ目のボタン
                    Button(action: {
                        displayMode = display.third
                        self.page1 = false
                        self.page2 = false
                        self.page3 = true
                    }) {
                        if page3 == true {
                            SelectedMenu("ページ3")
                        } else if page3 == false {
                            unSelectedMenu("ページ3")
                        }
                    }
                }
            }
        }
        
        Spacer()
        
        //条件分岐で画面を切り替え
        if displayMode  == display.first {
            FirstView(viewMode: $page1)
        } else if displayMode == display.second {
            SecondView(viewMode: $page2)
        } else if displayMode == display.third {
            ThirdView(viewMode: $page3)
        }
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

//選択ボタンの表示
struct SelectedMenu : View{
    let menu:String
    
    init(_ text:String){
        self.menu = text
    }
    
    var body: some View{
        Text(self.menu)
            .foregroundColor(Color.white)
            .fontWeight(.heavy)
            .padding(.horizontal, 15)
            .padding(.vertical, 5)
            .background(Color.red)
            .clipShape(Capsule())
    }
}

//非選択ボタンの表示
struct unSelectedMenu : View{
    let menu:String
    
    init(_ text:String){
        self.menu = text
    }
    
    var body: some View{
        Text(self.menu)
            .foregroundColor(Color.white)
            .padding(.horizontal, 10)
            .padding(.vertical, 2)
            .background(Color.blue)
            .clipShape(Capsule())
    }
}

//画面1
struct FirstView: View {
    @Binding var viewMode: Bool
    var body: some View {
        Text("FirstView")
        Spacer()
    }
}

//画面2
struct SecondView: View {
    @Binding var viewMode: Bool
    var body: some View {
        Text("SecondView")
        Spacer()
    }
}

//画面3
struct ThirdView: View {
    @Binding var viewMode: Bool
    var body: some View {
        Text("ThirdView")
        Spacer()
    }
}</code></pre>
</div>

5. ソースコードDownload

一応ソースコード(Xcodeプロジェクト)のダウンロードは下記ボタンから。

6. おまけ:最近購入したコスパが良かったもの

スマホ連携の体重計を¥1599で購入したんですが、iOS用の専用アプリを開いて体重計に乗るだけで体重や体脂肪等の計測が出来て保存も出来て、更にはiOSのヘルスケアアプリとも連動するというスグレモノ。
国内メーカーだと、3倍以上の金額するのでかなりコスパが良いかと。
久しぶりに良い買い物したなあ。

体重計 体脂肪 体組成計 高精度 体重/筋肉量/BMIなど20項健康測定可能 強化ガラス採用 iOS/Androidアプリで健康管理 Bluetooth対応 ヘルスケア同期 日本語対応&取扱説明書付き
Previous post ソースコードをシンタックスハイライトするWordPressプラグイン Highlighting Code Block
Next post SwiftとSwiftUIとXcodeとmac0Sのバージョン対応表

コメントを残す