LoginSignup
2
0

More than 5 years have passed since last update.

Xamarin.Formsで画像にTintColorを適用する - カスタムレンダラー編

Last updated at Posted at 2017-09-13

アイコン画像の色、変えたいことありますよね。
色ごとにアイコン画像を作るのは面倒なので、TintColor設定でいつでもどこでも変えられるようにしてみます。

ic_local_florist_black_24dp_2x.png

この花の形をした画像の色を変えてみたいと思います。

カスタムレンダラーを使いたくないという方はこちらをどうぞ。

実装

PCL

Image コントロールを継承したカスタムコントロールを作成します。
TintColorをXAMLから設定できるようにバインド可能プロパティを追加しておきます。

TintImage.cs
using Xamarin.Forms;

namespace MyApp
{
    public class TintImage : Image
    {
        public static readonly BindableProperty TintColorProperty = BindableProperty.Create(
            "TintColor", typeof(Color), typeof(TintImage), Color.Default
        );

        public Color TintColor {
            get { return (Color)GetValue(TintColorProperty); }
            set { SetValue(TintColorProperty, value); }
        }
    }
}
XAML
<?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:local="clr-namespace:MyApp"
    x:Class="MyApp.MyAppPage">

    <StackLayout VerticalOptions="Center" HorizontalOptions="Center">

        <local:TintImage Source="sample.png" />
        <local:TintImage Source="sample.png" TintColor="Red"/>
        <local:TintImage Source="sample.png" TintColor="Blue" />

    </StackLayout>

</ContentPage>

あとは各プラットフォームごとにカスタムレンダラーを作成します。

iOS

TintImageRenderer.cs
using System;
using System.ComponentModel;

using Xamarin.Forms;
using Xamarin.Forms.Platform.iOS;

using UIKit;

using MyApp;
using MyApp.iOS;

[assembly: ExportRenderer(typeof(TintImage), typeof(TintImageRenderer))]

namespace MyApp.iOS
{
    public class TintImageRenderer : ImageRenderer
    {
        protected override void OnElementChanged(ElementChangedEventArgs<Image> e)
        {
            base.OnElementChanged(e);

            if (e.NewElement != null) {
                SetTint();
            }
        }

        protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            base.OnElementPropertyChanged(sender, e);

            if (e.PropertyName == nameof(TintImage.TintColor)) {
                SetTint();
            }
        }

        protected void SetTint()
        {
            var element = (TintImage)Element;

            if (element.TintColor == Color.Default) {
                if (Control.Image != null) {
                    Control.Image = Control.Image.ImageWithRenderingMode(UIImageRenderingMode.AlwaysOriginal);
                }
                Control.TintColor = null;
            } else {
                if (Control.Image != null) {
                    Control.Image = Control.Image.ImageWithRenderingMode(UIImageRenderingMode.AlwaysTemplate);
                }
                Control.TintColor = element.TintColor.ToUIColor();
            }
        }
    }
}

Android

TintImageRenderer.cs
using System;
using System.ComponentModel;

using Xamarin.Forms;
using Xamarin.Forms.Platform.Android;

using Android.Graphics;

using MyApp;
using MyApp.Droid;

[assembly: ExportRenderer(typeof(TintImage), typeof(TintImageRenderer))]

namespace MyApp.Droid
{
    public class TintImageRenderer : ImageRenderer
    {
        /**
         * Xamarin.Forms 2.5 以降では引数なしのコンストラクタが obsolete になっているので、
         * 引数に Context をとるコンストラクタを定義します。
         */
        public TintImageRenderer(Android.Content.Context context) : base(context)
        {
        }

        protected override void OnElementChanged(ElementChangedEventArgs<Image> e)
        {
            base.OnElementChanged(e);

            if (e.NewElement != null) {
                SetTint();
            }
        }

        protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            base.OnElementPropertyChanged(sender, e);

            if (e.PropertyName == nameof(TintImage.TintColor)) {
                SetTint();
            }
        }

        protected void SetTint()
        {
            var element = (TintImage)Element;

            if (element.TintColor == Xamarin.Forms.Color.Default) {
                Control.ClearColorFilter();
            } else {
                Control.SetColorFilter(element.TintColor.ToAndroid(), PorterDuff.Mode.SrcIn);
            }
        }
    }
}

結果

各プラットフォームの Resources に画像ファイルをコピーして実行すると...

iOS

result_ios.png

Android

result_android.png

黒の単色だった画像に色がつきました。

とりあえずは以上です。

こちらを参考にしパクリました

2
0
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
0