記事一覧

iOSのToolbarItemのスペースを調整してレイアウトを整える方法 | Xamarin.Forms

 
今回はXamarin.FormsのToolBarItemでiOSで表示された場合、余白が多すぎる件について、その対応方法をご紹介いたします。
Androidでは正常に表示されるのですが、iOS上ではかなり余分なスペースを含んで表示されるため、多くのツールバーを表示することができません。
そこで余分なスペースを取り除いて表示する方法を見つけましたが、画面描画後にアイコン変更に対応させたりと少し工夫が必要でした。

また、以前の記事「iOSでセカンダリツールバーをカスタマイズする方法」をプロジェクトに追加している場合は同じファイル内にマージして記述してください。同種のレンダラーが複数存在すると片方が正しく動作しません。



レンダラー適用後
xamarin_ios_toolbaritem_01.png
デフォルト
xamarin_ios_toolbaritem_02.png

※デフォルトはToolbarItem間のスペースが広すぎます。



前提条件
・Windows10 Pro 64Bit
・Visual Studio 2015 Community Update3
・Xamarin 4.7.9.45 (NuGet Xamarin.Forms 2.4.0.282)
・macOS Sierra 10.12.6 / Xcode9 / Xamarin.iOS 11.0.0.0



1.PageRendererを追加

iOSプロジェクトに以下のファイルを配置します。
RightBarButtonItemsに再セットする際に右からアイコンが表示されるため、page.ToolbarItemsから逆順にToolbarItemを取り出して一時保存用の配列に保存します。調整用のスペースオブジェクトを間に挟みながら一時保存用の配列から取り出したToolbarItemをUIButtonとしてセットしたものをRightBarButtonItemsに再セットすることで余分なスペースを取り除きます。その際、描画後のアイコン変更に対応する為、ToolbarItem.PropertyChangedイベントをハンドルしています。

CustomPageRenderer.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Input;
using UIKit;
using CoreGraphics;
using Xamarin.Forms;
using Xamarin.Forms.Platform.iOS;
using AppName.iOS.Renderer;
[assembly: ExportRenderer(typeof(Page), typeof(CustomPageRenderer))]

namespace AppName.iOS.Renderer
{
public class CustomPageRenderer : PageRenderer
{
List<ToolbarItem> _primaryItems;
readonly Dictionary<UIButton, ICommand> _buttonPrimaryCommands = new Dictionary<UIButton, ICommand>();

protected override void OnElementChanged(VisualElementChangedEventArgs e)
{
var page = e.NewElement as Page;
if (page != null)
{
//プライマリ
//プライマリメニューバーは(3, 2, 1)というように右から並ぶため、Order by Desc で逆に並び替える
_primaryItems = page.ToolbarItems.Where(i => i.Order == ToolbarItemOrder.Primary).OrderByDescending(r => r.Priority).ToList();
_primaryItems.ForEach(t => page.ToolbarItems.Remove(t));
}
base.OnElementChanged(e);

}

public override void ViewWillAppear(bool animated)
{
//プライマリ
if (_primaryItems != null && _primaryItems.Count > 0)
{
var tools = new List<UIBarButtonItem>();

//スペース調整を追加(その1)
UIBarButtonItem sideMarginSpaceAdjustment1 = new UIBarButtonItem();
sideMarginSpaceAdjustment1.Width = -16.0f;
tools.Add(sideMarginSpaceAdjustment1);

_buttonPrimaryCommands.Clear();
foreach (var tool in _primaryItems)
{
tool.PropertyChanged += this.ToolPropertyChanged;

//UIButtonの設定
UIButton button = new UIButton();
button.SetImage(UIImage.FromFile(tool.Icon), UIControlState.Normal);
button.SizeToFit();
button.TintColor = UIColor.White;
button.TouchDown += this.ToolPrimaryClicked;

//UIBarButtonItemの設定
UIBarButtonItem buttonItem = new UIBarButtonItem(button);
buttonItem.Title = tool.Text;
buttonItem.Style = UIBarButtonItemStyle.Plain;
buttonItem.TintColor = UIColor.White;

_buttonPrimaryCommands.Add(button, tool.Command);
tools.Add(buttonItem);

//スペース調整を追加(その2)
UIBarButtonItem sideMarginSpaceAdjustment2 = new UIBarButtonItem();
sideMarginSpaceAdjustment2.Width = -16.0f;
tools.Add(sideMarginSpaceAdjustment2);
}

var navigationItem = this.NavigationController.TopViewController.NavigationItem;
if (navigationItem != null)
{
//ツールバーを再作成
navigationItem.RightBarButtonItems = tools.ToArray(); //逆順でセットされている
}
}

base.ViewWillAppear(animated);
}

/// <summary>
/// ツールバーアイテムが変更になった場合に外観を変更する
/// </summary>
/// <param name="sender"></param>
/// <param name="args"></param>
void ToolPropertyChanged(object sender, EventArgs args)
{
var navigationItem = this.NavigationController.TopViewController.NavigationItem;
if (navigationItem != null)
{
var tool = sender as ToolbarItem;
int cnt = navigationItem.RightBarButtonItems.Count() - 1; //逆順でセットされている為、メニューアイテム数から減算する為
int index = cnt - (tool.Priority + tool.Priority / 2); //sideMarginSpaceAdjustmentを入れた分だけindexを加算する

var button = (UIButton)(navigationItem.RightBarButtonItems[index].CustomView);
if (button != null)
{
//メニューアイコンを変更
if (tool.Icon != null)
{
button.SetImage(UIImage.FromFile(tool.Icon), UIControlState.Normal);
button.SizeToFit();
}
}
//メニュータイトル文字列を変更
navigationItem.RightBarButtonItems[index].Title = tool.Text;
}
}

/// <summary>
/// プライマリメニューのコマンドを実行する
/// </summary>
/// <param name="sender"></param>
/// <param name="args"></param>
void ToolPrimaryClicked(object sender, EventArgs args)
{
var tool = sender as UIButton;
var command = _buttonPrimaryCommands[tool];
command.Execute(null);
}

/// <summary>
/// 終了処理
/// </summary>
/// <param name="animated"></param>
public override void ViewWillDisappear(bool animated)
{
if (_primaryItems != null && _primaryItems.Count > 0)
{
NavigationController.SetToolbarHidden(true, animated);
this.NavigationItem.RightBarButtonItems = null;
_buttonPrimaryCommands.Clear();
}
base.ViewWillDisappear(animated);
}
}
}

ファイルを配置するだけで簡単にツールバーを補正できます。
※ただし、アイコンに使用している画像ファイルの色までは変更されませんので、適宜画像ファイルを変更してください。





最後までお読みいただきありがとうございます。
当ブログの内容をまとめた 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

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