こんにちはコタツです。
Xamarin Formsは本当に便利なのですが、既存に用意されているツールでは汎用性がなく困ることがあります。
今回困ったのはメニュー。
上のツールバーに置くのはあらかじめ用意されているのですが、正直使いにくいし私が求めているものと違います。
左側からすっと出てくるメニューもありますが、私はアプリでよく使われている、画面下のメニューが作りたかったわけです。
今回できたメニューはこちら↓
メニューを切り替えるとメニュー上部のViewが切り替わる設計になっています。
早速ソースを紹介します。
メニューの部品作成
画面下部のメニュー部品を作成します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 |
using System; using System.Collections.Generic; using System.Linq; using System.Text; using Xamarin.Forms; namespace ChefTownCollabo { /// <summary> /// メニューを作成します。 /// </summary> public class CMenuView : ContentView { #region 変数 /// <summary> /// メニューのレイアウト情報を保持します。 /// </summary> private Dictionary<MenuItem, StackLayout> m_MenuLayout; /// <summary> /// 現在表示中のボタン /// </summary> private MenuItem m_MenuItemState; #endregion #region コンストラクタ /// <summary> /// コンストラクト /// </summary> public CMenuView() { try { var grid = new Grid { HorizontalOptions = LayoutOptions.FillAndExpand, VerticalOptions = LayoutOptions.Center, RowDefinitions = { new RowDefinition() { Height = GridLength.Auto } }, ColumnDefinitions = { new ColumnDefinition() { Width = new GridLength(1, GridUnitType.Star) }, new ColumnDefinition() { Width = new GridLength(1, GridUnitType.Star) }, new ColumnDefinition() { Width = new GridLength(1, GridUnitType.Star) }, new ColumnDefinition() { Width = new GridLength(1, GridUnitType.Star) }, new ColumnDefinition() { Width = new GridLength(1, GridUnitType.Star) }, } }; // メニューのレイアウトを作成します。 m_MenuLayout = new Dictionary<MenuItem, StackLayout>(); StackLayout layout = null; layout = GetLayout("ChefTownCollabo.Image.icon_search_on.png", "検索"); grid.Children.Add(layout, 0, 0); m_MenuLayout.Add(MenuItem.Search, layout); layout = GetLayout("ChefTownCollabo.Image.icon_project.png", "プロジェクト"); grid.Children.Add(layout, 1, 0); m_MenuLayout.Add(MenuItem.Project, layout); layout = GetLayout("ChefTownCollabo.Image.icon_offer.png", "オファー"); grid.Children.Add(layout, 2, 0); m_MenuLayout.Add(MenuItem.Offer, layout); layout = GetLayout("ChefTownCollabo.Image.icon_talk.png", "トークルーム"); grid.Children.Add(layout, 3, 0); m_MenuLayout.Add(MenuItem.Talk, layout); layout = GetLayout("ChefTownCollabo.Image.icon_mypage.png", "マイページ"); grid.Children.Add(layout, 4, 0); m_MenuLayout.Add(MenuItem.MyPage, layout); grid.BackgroundColor = Color.FromHex("F3F3F3"); grid.Padding = new Thickness(0, 10, 0, 10); m_MenuItemState = MenuItem.Search; Content = grid; } catch(Exception err) { CErrorCtrl.SendErrorMsg(err); } } #endregion #region メソッド /// <summary> /// レイアウトを作成します。 /// </summary> /// <param name="sImagePath">画像パス</param> /// <param name="sLblName">タイトル</param> /// <returns>レイアウト</returns> private StackLayout GetLayout(string sImagePath, string sLblName) { Image img = new Image(); img.Source = ImageSource.FromResource(sImagePath); img.WidthRequest = 32; img.HeightRequest = 32; img.ClassId = sImagePath; Label lbl = new Label(); lbl.Text = sLblName; lbl.HorizontalOptions = LayoutOptions.Center; lbl.FontSize = 8; lbl.TextColor = Color.FromHex("4B4B4D"); StackLayout stack = new StackLayout(); stack.VerticalOptions = LayoutOptions.Center; stack.HorizontalOptions = LayoutOptions.FillAndExpand; stack.Children.Add(img); stack.Children.Add(lbl); stack.ClassId = "off"; var tap = new TapGestureRecognizer(); tap.Tapped += (s, e) => { MenuTap((StackLayout)s); }; stack.GestureRecognizers.Add(tap); return stack; } /// <summary> /// メニュータップ時の処理をします。 /// </summary> /// <param name="stack">レイアウト</param> private void MenuTap(StackLayout stack) { int nCount = 0; Image img = null; // メニューをOffにします。 OffMenu(); foreach (var layout in stack.Children) { if (nCount == 0) { img = (Image)layout; } if (nCount == 1) { Label lbl = (Label)layout; lbl.TextColor = Color.FromHex(CCommonModel.MAIN_COLOR); switch (lbl.Text) { case "検索": m_MenuItemState = MenuItem.Search; img.Source = ImageSource.FromResource("ChefTownCollabo.Image.icon_search_on.png"); break; case "プロジェクト": m_MenuItemState = MenuItem.Project; img.Source = ImageSource.FromResource("ChefTownCollabo.Image.icon_project_on.png"); break; case "オファー": m_MenuItemState = MenuItem.Offer; img.Source = ImageSource.FromResource("ChefTownCollabo.Image.icon_offer_on.png"); break; case "トークルーム": m_MenuItemState = MenuItem.Talk; img.Source = ImageSource.FromResource("ChefTownCollabo.Image.icon_talk_on.png"); break; case "マイページ": m_MenuItemState = MenuItem.MyPage; img.Source = ImageSource.FromResource("ChefTownCollabo.Image.icon_mypage_on.png"); break; } } nCount++; } CCommonModel.GetInstance().MainPage.MoveMenu(m_MenuItemState); } /// <summary> /// メニューボタンをOffにします。 /// </summary> private void OffMenu() { StackLayout stack = m_MenuLayout[m_MenuItemState]; int nCount = 0; Image img = null; foreach (var layout in stack.Children) { if(nCount == 0) { img = (Image)layout; } if (nCount == 1) { Label lbl = (Label)layout; lbl.TextColor = Color.FromHex("4B4B4D"); switch (lbl.Text) { case "検索": img.Source = ImageSource.FromResource("ChefTownCollabo.Image.icon_search.png"); break; case "プロジェクト": img.Source = ImageSource.FromResource("ChefTownCollabo.Image.icon_project.png"); break; case "オファー": img.Source = ImageSource.FromResource("ChefTownCollabo.Image.icon_offer.png"); break; case "トークルーム": img.Source = ImageSource.FromResource("ChefTownCollabo.Image.icon_talk.png"); break; case "マイページ": img.Source = ImageSource.FromResource("ChefTownCollabo.Image.icon_mypage.png"); break; } } nCount++; } } #endregion } } |
ソース上で指定している画像は任意で用意して配置してください。
「MenuItems」は列挙体です
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; /// <summary> /// 列挙型を管理するクラス /// </summary> namespace ChefTownCollabo { // <summary> /// メニュー項目 /// </summary> public enum MenuItem { Search, Project, Offer, Talk, MyPage, Partner } } |
メイン画面へ組み込み
ではメニューをメイン画面に組み込んでみます
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 |
using System; using System.Collections.Generic; using System.Linq; using System.Text; using Xamarin.Forms; namespace ChefTownCollabo { /// <summary> /// メイン画面を作成します。 /// </summary> public class CMainPage : ContentPage { #region メンバ変数 /// <summary> /// メイン画面レイアウト /// </summary> private StackLayout m_Main; /// <summary> /// 検索ビュー /// </summary> private ContentView m_SearchView; /// <summary> /// プロジェクトビュー /// </summary> private ContentView m_Project; /// <summary> /// オファービュー /// </summary> private ContentView m_Offer; /// <summary> /// トークビュー /// </summary> private ContentView m_Talk; /// <summary> /// メニューレイアウト /// </summary> private StackLayout m_Menu; /// <summary> /// マイページレイアウト /// </summary> private ContentView m_MyPage; #endregion #region コンストラクタ /// <summary> /// コンストラクタ /// </summary> public CMainPage() { try { CreateLayut(); } catch (Exception err) { CErrorCtrl.SendErrorMsg(err); } } #endregion #region メソッド /// <summary> /// メニューを移動します。 /// </summary> public void MoveMenu(MenuItem menuItem) { try { // レイアウトを削除します。 for (int i = 0; i < m_Main.Children.Count; i++) { m_Main.Children.RemoveAt(0); } switch (menuItem) { case MenuItem.Search: Title = "料理人"; m_Main.Children.Add(m_SearchView); break; case MenuItem.Project: Title = "プロジェクト"; if(m_Project == null) { m_Project = new CProjectView(); } m_Main.Children.Add(m_Project); break; case MenuItem.Offer: Title = "オファー"; if (m_Offer == null) { m_Offer = new COfferView(); } m_Main.Children.Add(m_Offer); break; case MenuItem.Talk: Title = "トークルーム"; if(m_Talk == null) { m_Talk = new CTalkView(); } m_Main.Children.Add(m_Talk); break; case MenuItem.MyPage: Title = "マイページ"; if (m_MyPage == null) { m_MyPage = new CMypageView(); } m_Main.Children.Add(new CMypageView()); break; } } catch (Exception err) { CErrorCtrl.SendErrorMsg(err); } } /// <summary> /// レイアウトを作成します。 /// </summary> private void CreateLayut() { // メイン画面を設定します。 m_SearchView = new CSearchView(); m_Main = new StackLayout(); m_Main.Children.Add(m_SearchView); NavigationPage.SetBackButtonTitle(this, "BACK"); Title = "料理人"; // メニューを設定します。 m_Menu = new StackLayout(); m_Menu.Children.Add(new CMenuView()); // 全体のレイアウトを編成します。 var mainLayout = new AbsoluteLayout(); mainLayout.Children.Add(m_Main); mainLayout.Children.Add(m_Menu); Content = mainLayout; SizeChanged += OnPageSizeChanged; } #endregion #region イベント /// <summary> /// 画面表示時の処理をします。 /// </summary> /// <param name="sender">イベントソース</param> /// <param name="args">イベントデータ</param> private void OnPageSizeChanged(object sender, EventArgs args) { var width = this.Width; var height = this.Height; AbsoluteLayout.SetLayoutFlags(m_Main, AbsoluteLayoutFlags.PositionProportional); AbsoluteLayout.SetLayoutBounds(m_Main, new Rectangle(0d, 0d, width, height)); AbsoluteLayout.SetLayoutFlags(m_Menu, AbsoluteLayoutFlags.PositionProportional); AbsoluteLayout.SetLayoutBounds(m_Menu, new Rectangle(0, 1, AbsoluteLayout.AutoSize, AbsoluteLayout.AutoSize)); } #endregion } } |
表示する各ページのViewは任意で作成して上記のソースから変更してください。
まとめ
今回はXamrinFormsで画面下にメニューを設置してみました。
マッチングアプリなどにはよく使われるメニューバーなので、今後もカスタマイズしていきます。