Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationEventAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
4
Help us understand the problem. What are the problem?

More than 3 years have passed since last update.

@sudachi808

Xamarin.Formsで背景色をグラデーション表示 - NControl編

前回はカスタムレンダラーを使用しましたが、やはりXamarin.Formsではできるだけネイティブコードを書きたくないので、カスタムレンダラー無しでやってみたいと思います。

NControl というクロスプラットフォームの2D描画パッケージを使うとグラデーションを描画できるっぽいです(実際の描画は依存パッケージである NGraphics が担当)。

パッケージ追加

ソリューション内の各プロジェクト(PCL/iOS/Android)に、下記のパッケージを追加します。

  • NControl
  • NControl.Controls

nuget.png

初期化

NControl の初期化コードを追加します。

iOS

AppDelegate.cs
using System;
using System.Collections.Generic;
using System.Linq;

using Foundation;
using UIKit;

using NControl.iOS; // <-- 追加

namespace MyApp.iOS
{
    [Register("AppDelegate")]
    public partial class AppDelegate : global::Xamarin.Forms.Platform.iOS.FormsApplicationDelegate
    {
        public override bool FinishedLaunching(UIApplication app, NSDictionary options)
        {
            global::Xamarin.Forms.Forms.Init();
            NControlViewRenderer.Init();    // <-- 追加

            LoadApplication(new App());

            return base.FinishedLaunching(app, options);
        }
    }
}

Android

MainActivity.cs
using System;

using Android.App;
using Android.Content;
using Android.Content.PM;
using Android.Runtime;
using Android.Views;
using Android.Widget;
using Android.OS;

using NControl.Droid;   // <-- 追加

namespace MyApp.Droid
{
    [Activity(Label = "MyApp.Droid", Icon = "@drawable/icon", Theme = "@style/MyTheme", MainLauncher = true, ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation)]
    public class MainActivity : global::Xamarin.Forms.Platform.Android.FormsAppCompatActivity
    {
        protected override void OnCreate(Bundle bundle)
        {
            TabLayoutResource = Resource.Layout.Tabbar;
            ToolbarResource = Resource.Layout.Toolbar;

            base.OnCreate(bundle);

            global::Xamarin.Forms.Forms.Init(this, bundle);
            NControlViewRenderer.Init();    // <-- 追加

            LoadApplication(new App());
        }
    }
}

実装

GradientView.cs
using System;

using Xamarin.Forms;

using NControl.Abstractions;
using NControl.Controls;
using NGraphics;

namespace MyApp
{
    public class GradientView : NControlView
    {
        public GradientView()
        {
            DrawingFunction = (canvas, rect) =>
            {
                var brush = new LinearGradientBrush(
                    NGraphics.Point.Zero,
                    NGraphics.Point.OneY,
                    this.StartColor.ToNColor(),
                    this.EndColor.ToNColor()
                );
                canvas.FillRectangle(rect, brush);
            };
        }

        protected void OnColorChanged()
        {
            this.Invalidate();
        }

        public static readonly BindableProperty StartColorProperty = BindableProperty.Create(
            "StartColor", typeof(Xamarin.Forms.Color), typeof(GradientView), Xamarin.Forms.Color.Default,
            propertyChanged: (bindable, oldValue, newValue) => ((GradientView)bindable).OnColorChanged()
        );

        public static readonly BindableProperty EndColorProperty = BindableProperty.Create(
            "EndColor", typeof(Xamarin.Forms.Color), typeof(GradientView), Xamarin.Forms.Color.Default,
            propertyChanged: (bindable, oldValue, newValue) => ((GradientView)bindable).OnColorChanged()
        );

        public Xamarin.Forms.Color StartColor {
            get { return (Xamarin.Forms.Color)GetValue(StartColorProperty); }
            set { SetValue(StartColorProperty, value); }
        }

        public Xamarin.Forms.Color EndColor {
            get { return (Xamarin.Forms.Color)GetValue(EndColorProperty); }
            set { SetValue(EndColorProperty, 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">

    <local:GradientView StartColor="Olive" EndColor="Teal" />

</ContentPage>

結果

iOS

result_ios.png

Android

result_android.png

できました。
カスタムレンダラーと比べると簡単な感じがしますね。

3色のグラデーション

3色でもグラデーションできます。

GradientView.cs
using System;

using Xamarin.Forms;

using NControl.Abstractions;
using NControl.Controls;
using NGraphics;

namespace MyApp
{
    public class GradientView : NControlView
    {
        public GradientView()
        {
            DrawingFunction = (canvas, rect) =>
            {
                LinearGradientBrush brush;

                if (this.MidColor != Xamarin.Forms.Color.Default) {
                    brush = new LinearGradientBrush(
                        NGraphics.Point.Zero,
                        NGraphics.Point.OneY,
                        this.StartColor.ToNColor(),
                        this.MidColor.ToNColor(),
                        this.EndColor.ToNColor()
                    );
                } else {
                    brush = new LinearGradientBrush(
                        NGraphics.Point.Zero,
                        NGraphics.Point.OneY,
                        this.StartColor.ToNColor(),
                        this.EndColor.ToNColor()
                    );
                }

                canvas.FillRectangle(rect, brush);
            };
        }

        protected void OnColorChanged()
        {
            this.Invalidate();
        }

        public static readonly BindableProperty StartColorProperty = BindableProperty.Create(
            "StartColor", typeof(Xamarin.Forms.Color), typeof(GradientView), Xamarin.Forms.Color.Default,
            propertyChanged: (bindable, oldValue, newValue) => ((GradientView)bindable).OnColorChanged()
        );

        public static readonly BindableProperty MidColorProperty = BindableProperty.Create(
            "MidColor", typeof(Xamarin.Forms.Color), typeof(GradientView), Xamarin.Forms.Color.Default,
            propertyChanged: (bindable, oldValue, newValue) => ((GradientView)bindable).OnColorChanged()
        );

        public static readonly BindableProperty EndColorProperty = BindableProperty.Create(
            "EndColor", typeof(Xamarin.Forms.Color), typeof(GradientView), Xamarin.Forms.Color.Default,
            propertyChanged: (bindable, oldValue, newValue) => ((GradientView)bindable).OnColorChanged()
        );

        public Xamarin.Forms.Color StartColor {
            get { return (Xamarin.Forms.Color)GetValue(StartColorProperty); }
            set { SetValue(StartColorProperty, value); }
        }

        public Xamarin.Forms.Color MidColor {
            get { return (Xamarin.Forms.Color)GetValue(MidColorProperty); }
            set { SetValue(MidColorProperty, value); }
        }

        public Xamarin.Forms.Color EndColor {
            get { return (Xamarin.Forms.Color)GetValue(EndColorProperty); }
            set { SetValue(EndColorProperty, 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">

    <local:GradientView StartColor="Olive" MidColor="Red" EndColor="Teal" />

</ContentPage>

iOS

result_ios_2.png

Android

result_android_2.png

若干不自然な感じもしなくはないですが、使いようによっては効果があるのではないでしょうか。

カスタムレンダラーを書かなくても、代わりにやってくれる便利なパッケージを使うと簡単に実装できますね。

とりあえずは以上です。

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
4
Help us understand the problem. What are the problem?