記事一覧

iOSでセカンダリツールバーをカスタマイズする | Xamarin.Forms


今回はiOSでセカンダリのツールバーをカスタマイズする方法についてご紹介いたします。通常の設定方法につきましては次の記事「ToolbarItemの表示方法」をご参考ください。
通常、ツールバーのセカンダリとして設定した場合、画面の上部(ナビゲーションバーのすぐ下)に大きく表示され、デザインも悪いので邪魔な表示ととらえられがちです。セカンダリツールバーを画面下部に表示するだけでだいぶすっきりとした印象に変わります。また、画面下部に表示できたとしてもアイコンが表示できていない例をよく見かけましたので、セカンダリツールバーのアイコンも正しく表示されるコードサンプルをご紹介いたします。


iOS After
xamarin_toolbar_secondary_01.png
iOS Before
xamarin_toolbar_secondary_02.png



前提条件
・Windows10 Pro 64Bit
・Visual Studio 2015 Community Update3
・Xamarin 4.3.0.784 (NuGet Xamarin.Forms 2.3.4.224)
・macOS Sierra 10.12.4 / Xcode8.3.1 / Xamarin.iOS 10.4.0.123



1.カスタムレンダラーを作成する

iOSプロジェクトに以下の2種類のカスタムレンダラーを作成します。
作成したファイルを配置して実行するだけでセカンダリのツールバーが画面下部に移動して表示されます。

PatchedNavigationRenderer.cs
using System;
using System.Collections.Generic;
using System.Text;
using UIKit;
using System.Linq;
using CoreGraphics;
using Xamarin.Forms.Platform.iOS;
using Xamarin.Forms;

[assembly: ExportRenderer(typeof(NavigationPage), typeof(AppName.iOS.Renderer.PatchedNavigationRenderer))]

namespace AppName.iOS.Renderer
{
    public class PatchedNavigationRenderer : NavigationRenderer
    {
        public override void ViewWillAppear(bool animated)
        {
            var badBar = View.Subviews.OfType<UIToolbar>().FirstOrDefault(v => v.GetType() != typeof(UIToolbar));
            if (badBar != null)
            {
                badBar.RemoveFromSuperview();
            }
            base.ViewWillAppear(animated);
        }

        public override void ViewDidLayoutSubviews()
        {
            base.ViewDidLayoutSubviews();

            UIView[] subviews = View.Subviews.Where(v => v != NavigationBar).ToArray();
            var toolBarViews = subviews.Where(v => v is UIToolbar).ToArray();
            var otherViews = subviews.Where(v => !(v is UIToolbar)).ToArray();

            nfloat toolbarHeight = 0;

            foreach (var uIView in toolBarViews)
            {
                uIView.SizeToFit();
                uIView.Frame = new CGRect
                {
                    X = 0,
                    Y = View.Bounds.Height - uIView.Frame.Height,
                    Width = View.Bounds.Width,
                    Height = uIView.Frame.Height,
                };
                var thisToolbarHeight = uIView.Frame.Height;
                if (toolbarHeight < thisToolbarHeight)
                {
                    toolbarHeight = thisToolbarHeight;
                }
            }

            var othersHeight = View.Bounds.Height - toolbarHeight;
            var othersFrame = new CGRect(View.Bounds.X, View.Bounds.Y, View.Bounds.Width, othersHeight);

            foreach (var uIView in otherViews)
            {
                uIView.Frame = othersFrame;
            }
        }
    }
}


ToolbarRenderer.cs
using System;
using System.Collections.Generic;
using System.Text;
using System.Linq;
using System.Windows.Input;
using Xamarin.Forms.Platform.iOS;
using Xamarin.Forms;
using UIKit;
using CoreGraphics;

[assembly: ExportRenderer(typeof(Page), typeof(AppName.iOS.Renderer.ToolbarRenderer))]

namespace AppName.iOS.Renderer
{
    public class ToolbarRenderer : PageRenderer
    {
        UIToolbar _toolbar;
        List<ToolbarItem> _secondaryItems;
        readonly Dictionary<UIBarButtonItem, ICommand> _buttonCommands = new Dictionary<UIBarButtonItem, ICommand>();

        protected override void OnElementChanged(VisualElementChangedEventArgs e)
        {
            var page = e.NewElement as Page;
            if (page != null)
            {
                _secondaryItems = page.ToolbarItems.Where(i => i.Order == ToolbarItemOrder.Secondary).ToList();
                _secondaryItems.ForEach(t => page.ToolbarItems.Remove(t));
            }
            base.OnElementChanged(e);
        }

        public override void ViewWillAppear(bool animated)
        {
            if (_secondaryItems != null && _secondaryItems.Count > 0)
            {
                var tools = new List<UIBarButtonItem>();
                _buttonCommands.Clear();
                foreach (var tool in _secondaryItems)
                {
                    UIBarButtonItem button;
                    UIBarButtonSystemItem systemItem;
                    button = Enum.TryParse<UIBarButtonSystemItem>(tool.Text, out systemItem)
                        ? new UIBarButtonItem(systemItem, ToolClicked)
                        : new UIBarButtonItem(tool.Text, UIBarButtonItemStyle.Plain, ToolClicked);
                    button.Image = UIImage.FromFile(tool.Icon);     //Iconを設定
                    _buttonCommands.Add(button, tool.Command);
                    tools.Add(button);
                }

                NavigationController.SetToolbarHidden(false, animated);
                _toolbar = new UIToolbar(CGRect.Empty) { Items = tools.ToArray() };
                NavigationController.View.Add(_toolbar);
            }

            base.ViewWillAppear(animated);
        }

        void ToolClicked(object sender, EventArgs args)
        {
            var tool = sender as UIBarButtonItem;
            var command = _buttonCommands[tool];
            command.Execute(null);
        }

        public override void ViewWillDisappear(bool animated)
        {
            if (_toolbar != null)
            {
                NavigationController.SetToolbarHidden(true, animated);
                _toolbar.RemoveFromSuperview();
                _toolbar = null;
                _buttonCommands.Clear();
            }
            base.ViewWillDisappear(animated);
        }
    }
}

尚、ツールバーの設定はPCLプロジェクトで通常の設定を行うだけで表示が変更されます。



当ブログの内容をまとめた Xamarin逆引きメニュー は以下のURLからご覧になれます。
http://itblogdsi.blog.fc2.com/blog-entry-81.html


関連記事

コメント

コメントの投稿

広告

プロフィール

石河 純


著者名 :石河 純
自己紹介:素人上がりのIT技術者。趣味は卓球・車・ボウリング

IT関連の知識はざっくりとこんな感じです。
【OS関連】
WindowsServer: 2012/2008R2/2003/2000/NT4
Windows: 10/8/7/XP/2000/me/NT4/98
Linux: CentOS RedHatLinux9
Mac: macOS Sierra 10.12 / OSX Lion 10.7.5 / OSX Snow Leopard 10.6.8
【言語・データベース】
VB.net ASP.NET C#.net Java VBA
Xamarin.Forms
Oracle10g SQLServer2008R2 SQLAnywhere8/11/16
ActiveReport CrystalReport ReportNet(IBM)
【ネットワーク関連】
CCNP シスコ技術者認定
Cisco Catalyst シリーズ
Yamaha RTXシリーズ
FireWall関連
【WEB関連】
SEO SEM CSS IIS6/7 apache2

休みの日は卓球をやっています。
現在、卓球用品通販ショップは休業中です。