Windows系のあれこれ

港区の SIer で よくわからんことをしている SE みたいな人です。Xamarin 中心です。

Xamarin.Forms で iOS のナビゲーションバーに色付きアイコンを置きたい

Xamarin.Forms の NavigationBar のアイコンを設定したい場合、以下のように ToolbarItems を使ってアイコンを追加します。

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:prism="clr-namespace:Prism.Mvvm;assembly=Prism.Forms"
             prism:ViewModelLocator.AutowireViewModel="True"
             x:Class="ColorNavigationBarIcon.Views.MainPage"
             Title="MainPage">
    <ContentPage.ToolbarItems>
        <ToolbarItem Icon="Icon-Small.png"></ToolbarItem>
    </ContentPage.ToolbarItems>
  <StackLayout HorizontalOptions="Center" VerticalOptions="Center">
    <Label Text="{Binding Title}" />
  </StackLayout>
</ContentPage>

Icon-Small.png は Xamarin.Forms のプロジェクトテンプレートからプロジェクトを作成した時に勝手に追加されるこのアイコンです。
f:id:ShunsukeKawai:20170901212120p:plain

で、このアプリを実行してみると…
f:id:ShunsukeKawai:20170901220106p:plain:w300
となります。塗り潰されとる。
Apple の高尚な思想なのかなんなのか知らないですが、デフォルト単色になっちゃうみたいです。

試しに App.xaml とかのリソースでスタイルを定義して NavigationPage のテキストに色を付けてみます。

<Application.Resources>
    <ResourceDictionary>
        <Style TargetType="NavigationPage">
            <Setter Property="BarTextColor" Value="Red" />
        </Style>
    </ResourceDictionary>
</Application.Resources>

で、実行すると…
f:id:ShunsukeKawai:20170901220144p:plain:w300
赤くなります。どうやら BarTextColor に定義されてる色で塗り潰されるのかな。

あの六角形のアイコンが見たいです。

まずは Xamarin に関係なくネイティブでのやり方を調べてみます。
参考:[Swift]UIImageのレンダリングモードまとめ - Qiita
ほうほう、UIImageRenderingMode とかいうヤツがなんかしてるんだな。

ということで、iOS のプロジェクトに Rendererを追加します。
色々やった結果、以下でなんとかなりました。

using ColorNavigationBarIcon.iOS.Renderers;
using UIKit;
using Xamarin.Forms;
using Xamarin.Forms.Platform.iOS;

[assembly: ExportRenderer(typeof(ContentPage), typeof(ColorIconContentPageRenderer))]
namespace ColorNavigationBarIcon.iOS.Renderers
{
    public class ColorIconContentPageRenderer : PageRenderer
    {
        public override void ViewWillAppear(bool animated)
        {
            base.ViewWillAppear(animated);

            if (this.NavigationController == null) return;

            var items = this.NavigationController.TopViewController.NavigationItem;

            foreach (var item in items.RightBarButtonItems)
            {
                if (item.Image == null) continue;

                item.Image = item.Image.ImageWithRenderingMode(UIImageRenderingMode.AlwaysOriginal);
            }
        }
    }
}

じゃーん
f:id:ShunsukeKawai:20170901220157p:plain:w300
わーい