
TabViewってのを使うとタブが使えるって聞いたけど実際やってみると味気もないゴミみたいなものができました。 もうちょっと、っぽい感じにしたいので色々調べて見て手探りでやってみました。
TabViewを使うって聞いたんだけど…
タブを実装するには、TabViewってのを使って、タブをタップするとどのファイルを読み込むのかを指定してみたいなことが書いてあったので、いったん以下みたいなコードを読みながら書いてみた
struct ContentView: View {
init() {
UITabBar.appearance().backgroundColor = UIColor(red: 190/255, green: 190/255, blue: 190/255, alpha: 1.0)
}
var body: some View {
TabView(){
label_test()
.tabItem {
Image(systemName: "sun.max")
Text("sun")
}
label_test2()
.tabItem {
Image(systemName: "gear")
Text("gear")
}
}
}////some view
}
で、できたのが以下のだっさい画面
確かに切り替わりますし、タブなんですけど、何といっていいのか。
例えばですけど、真ん中あたりにカメラのボタンみたいなのがあって…。
で、ちょっと上にはみ出した、このボタンは特別なボタンみたいな感じというか…
凸 みたいな配置というかね。
そんな、ただ並んだだけというダサい感じじゃなく、せめてもっとみたいな。
他の皆様はどうやって作ってるのだろうか、色々調べて、できたものを記録しておきます。
LINEはどんな感じだったっけ
ただ並んでるだけの部分もおしゃれですね。上の方に私が作ったゴミとは大違いです。
ポイントとしては、右上に+のボタンが目立つようにおいてありますね。
今回私は、その+ボタンはつくらず、真ん中のVoomボタンを大きく目立つように、さらに位置をずらして、このボタンから、このアプリは始まるんだみたいなノリで作ってみたいと思います。
あと画像を使おうと思ったのですが、おしゃれな画像を持っていないので、iOSの標準だかなんだかしらないですけど、システムアイコンみたいなものを使って頑張ろうと思います。
どのアイコンを使うかを考える
使えるsystemIconは、https://developer.apple.com/design/resources/ から名前を調べましたよ。
左から
1.ホーム (house.fill)
2.検索 (magnifyingglass)
3.通知 (bell)
4.設定 (wrench.and.screwdriver)
真ん中にメインボタンとしてカメラ(camera.circle.fill)を配置することをゴールにしたいと思います。
ViewRouterを作る
現在、どのタブを選択しているのか?というパラメータを司る部分を作ります。
で、今回切り替える項目は5つなので、パラメータに設定できるのは5種類のみなので、enum型で作成します。
// ViewRouter.swift として作成
///ObservableObjectプロトコルらしい。中身に@Publishedで指定した変数を一括で監視してくれるとか。
///デフォルトはPageの.homeにしておく。
class ViewRouter: ObservableObject {
@Published var currentPage: Page = .home
}
//今回選択する5種類の名前。5種類しかないのだからそれ以外を選択できないようにしたいのでenum
enum Page {
case home
case search
case notification
case settings
case camera
}
ボタンを表示するやつを作る
ボタンのアイコン名と、一緒に表示するテキストを指定すると、組み合わさって表示される構造体を作りますよ。
※LINEのメニューバーを見ると、家のアイコンとホームって文字がセットになってる。しかも選択中だと服地になったりする。この機能を作成したい。
///TabBarIcon.swift として作成
struct TabBarIcon: View {
///作ったViewRouterのcurrentPageを使います。
///変更を与えたと同時に他へ反映させるために@StateObjectとしてウォッチします。
@StateObject var viewRouter: ViewRouter
///現在どのページを選択してるか?をenumのPageの範囲で
let selected:Page
///アイコンの横と、縦、指定するアイコン、タブの名前 を指定できるようにしておくことで汎用性をもたせる
let width,height:CGFloat
let systemIconName,tabName:String
var body: some View {
VStack{
Image(systemName:systemIconName)
.resizable()
.aspectRatio(contentMode:.fit)
.frame(width:width,height:height)
.padding(.top,15)
.onTapGesture{
///アイコン画像をタップした際の処理
viewRouter.currentPage=selected
}
Text(tabName)
Spacer()
}
.padding(.horizontal, 4)
///もし、描画する画像が現在選択中である場合、黒。それ以外は灰色に色をつける
.foregroundColor(viewRouter.currentPage == selected ? .black : .gray)
}
}
作ったTabBarIconにアイコンを5種類指定して、水平方向に並べてみる
最初の方に選んだアイコン
home ホーム(house.fill)
search 検索(magnifyingglass)
notification 通知(bell)
settings 設定 (wrench.and.screwdriver)
で、真ん中は文字を入れない状態でカメラを設定したいので、ひとまず上の4つを並べてみます。
真ん中に置きたいカメラは少し大きめにするので、並べる4つは、横幅の1/6ぐらいのサイズ指定で並べてみます。
ここからは、メインのContentView.swift に書き込んでいきます。
////ContentView.swift にて
GeometryReader{geometry in
VStack{
Spacer()
HStack{
TabBarIcon(viewRouter:viewRouter,selected:.home,width:geometry.size.width/6,height:geometry.size.height/24,systemIconName:"house.fill",tabName:"ホーム")
TabBarIcon(viewRouter:viewRouter,selected:.search,width:geometry.size.width/6,height:geometry.size.height/24,systemIconName:"magnifyingglass",tabName:"検索")
TabBarIcon(viewRouter:viewRouter,selected:.notification,width:geometry.size.width/6,height:geometry.size.height/24,systemIconName:"bell",tabName:"通知")
TabBarIcon(viewRouter:viewRouter,selected:.settings,width:geometry.size.width/6,height:geometry.size.height/24,systemIconName:"wrench.and.screwdriver",tabName:"設定")
}
.frame(width:geometry.size.width,height:geometry.size.height/10)
.background(Color("TabBarBackground").shadow(radius:2))
}
.edgesIgnoringSafeArea(.bottom)
}
で、できたのがこれ
真ん中に、目立つカメラボタン的なものを追加したい
5種類、全部TabBarIconでいこうと思ったけど、真ん中のメインで使うボタン的なものは、アイコンの下に文字をつけたくないし、タブを切り替えるためのボタンでもないので、4つのボタンを並べた真ん中あたりに、そのままベダ書きでボタンを追加してみます。
////ContentView.swift にて
GeometryReader{geometry in
VStack{
Spacer()
HStack{
TabBarIcon(viewRouter:viewRouter,selected:.home,width:geometry.size.width/6,height:geometry.size.height/24,systemIconName:"house.fill",tabName:"ホーム")
TabBarIcon(viewRouter:viewRouter,selected:.search,width:geometry.size.width/6,height:geometry.size.height/24,systemIconName:"magnifyingglass",tabName:"検索")
ZStack{
Circle()
.foregroundColor(Color.white)
.frame(width:geometry.size.width/6,height:geometry.size.height/6)
.shadow(radius:4)
Image(systemName:"camera.circle.fill")
.resizable()
.aspectRatio(contentMode:.fit)
.frame(width:geometry.size.width/6,height:geometry.size.height/6)
.foregroundColor(Color(red: 0/255, green: 185/255, blue: 0/255, opacity: 1.0))
.onTapGesture{
}
}
////本来並ぶところを、縦にずらす
.offset(y:-geometry.size.height/20)
TabBarIcon(viewRouter:viewRouter,selected:.notification,width:geometry.size.width/6,height:geometry.size.height/24,systemIconName:"bell",tabName:"通知")
TabBarIcon(viewRouter:viewRouter,selected:.settings,width:geometry.size.width/6,height:geometry.size.height/24,systemIconName:"wrench.and.screwdriver",tabName:"設定")
}
.frame(width:geometry.size.width,height:geometry.size.height/10)
.background(Color("TabBarBackground").shadow(radius:2))
}
.edgesIgnoringSafeArea(.bottom)
}////geometory
真ん中のZStackの部分を追加しました。
色はLINEカラーを当ててみました。
で、できたのがこれ
色々調整してみました。むしろテキストがいらない気がしてきたので
TabBarIconから、Text部分をカット
ボタン位置は適当に移動させてみて、つくったのがこれ