コンテンツ ページのカスタマイズ
ContentPage は、単一ビューを表示し、画面の大部分を占めるビジュアル要素です。 この記事では、ContentPage ページ用のカスタム レンダラーを作成する方法を示します。これにより、開発者は既定のネイティブ レンダリングを、各自のプラットフォームに固有のカスタマイズでオーバーライドできるようになります。
すべての Xamarin.Forms コントロールには、ネイティブ コントロールのインスタンスを作成する各プラットフォーム用のレンダラーが付属しています。 Xamarin.Forms アプリケーションによって ContentPage
がレンダリングされると、iOS では PageRenderer
クラスがインスタンス化され、それによってネイティブの UIViewController
コントロールもインスタンス化されます。 Android プラットフォーム上では、PageRenderer
クラスによって ViewGroup
コントロールがインスタンス化されます。 ユニバーサル Windows プラットフォーム (UWP) 上では、PageRenderer
クラスによって FrameworkElement
コントロールがインスタンス化されます。 Xamarin.Forms コントロールによってマップされるレンダラーとネイティブ コントロール クラスの詳細については、「Renderer Base Classes and Native Controls」(レンダラーの基底クラスおよびネイティブ コントロール) を参照してください。
次の図に、ContentPage
と、それを実装する、対応するネイティブ コントロールの関係を示します。
レンダリング プロセスを活用して各プラットフォーム上で ContentPage
用のカスタム レンダラーを作成することで、プラットフォーム固有のカスタマイズを実装できます。 これを行うための実行プロセスは次のとおりです。
ライブ カメラのフィードと写真をキャプチャする機能を提供する CameraPage
を実装する各項目について順番に説明します。
Xamarin.Forms ページを作成する
次の XAML コード例に示すように、変更されていない ContentPage
を共有 Xamarin.Forms プロジェクトに追加できます。
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="CustomRenderer.CameraPage">
<ContentPage.Content>
</ContentPage.Content>
</ContentPage>
同様に、次のコード例に示すように、ContentPage
の分離コード ファイルも変更が加えられません。
public partial class CameraPage : ContentPage
{
public CameraPage ()
{
// A custom renderer is used to display the camera UI
InitializeComponent ();
}
}
次のコード例は、このページを C# で作成する方法を示しています。
public class CameraPageCS : ContentPage
{
public CameraPageCS ()
{
}
}
CameraPage
のインスタンスは、各プラットフォームでライブ カメラ フィードを表示するために使用されます。 コントロールのカスタマイズはカスタム レンダラーで実行されるため、CameraPage
クラスに追加の実装は必要ありません。
Xamarin.Forms ページを使用する
Xamarin.Forms アプリケーションには、必ず空の CameraPage
が表示されます。 これは、次のコード例に示すように、MainPage
インスタンスのボタンがタップされてから OnTakePhotoButtonClicked
メソッドが実行されたときに起こります。
async void OnTakePhotoButtonClicked (object sender, EventArgs e)
{
await Navigation.PushAsync (new CameraPage ());
}
このコードでは単に CameraPage
にナビゲートされます。このカスタム レンダラーによって、各プラットフォームのページの外観がカスタマイズされます。
各プラットフォーム上でページ レンダラーを作成する
カスタム レンダラー クラスを作成するプロセスは次のとおりです。
PageRenderer
クラスのサブクラスを作成します。- ネイティブ ページをレンダリングする
OnElementChanged
メソッドをオーバーライドして、ロジックを書き込み、ページをカスタマイズします。 対応する Xamarin.Forms コントロールが作成されると、OnElementChanged
メソッドが呼び出されます。 ExportRenderer
属性をページ レンダラー クラスに追加して、Xamarin.Forms ページのレンダリングに使用されるように指定します。 この属性は、Xamarin.Forms にカスタム レンダラーを登録するために使用されます。
Note
プラットフォーム プロジェクトごとにページ レンダラーを指定するかどうかは任意です。 ページ レンダラーが登録されていない場合は、ページの既定のレンダラーが使用されます。
次の図に、サンプル アプリケーション内の各プロジェクトの役割とそれらの関係を示します。
CameraPage
インスタンスはプラットフォーム固有の CameraPageRenderer
クラスによってレンダリングされます。このクラスはすべてそのプラットフォームの PageRenderer
クラスから派生しています。 この結果、次のスクリーンショットに示すように、各 CameraPage
インスタンスがライブ カメラ フィードでレンダリングされます。
PageRenderer
クラスは OnElementChanged
メソッドを公開します。このメソッドは、該当するネイティブ コントロールをレンダリングするために、Xamarin.Forms ページの作成時に呼び出されます。 このメソッドは、OldElement
および NewElement
プロパティを含む ElementChangedEventArgs
パラメーターを取得します。 これらのプロパティは、レンダラーがアタッチされていた Xamarin.Forms 要素と、レンダラーが現在アタッチされている Xamarin.Forms 要素をそれぞれ表しています。 サンプル アプリケーションでは、OldElement
プロパティが null
になり、NewElement
プロパティに CameraPage
インスタンスへの参照が含まれます。
CameraPageRenderer
クラスの OnElementChanged
メソッドのオーバーライドされたバージョンで、ネイティブ ページのカスタマイズが実行されます。 レンダリングされている Xamarin.Forms ページ インスタンスへの参照は、Element
プロパティを使用して取得することができます。
各カスタム レンダラー クラスは、レンダラーを Xamarin.Forms に登録する ExportRenderer
属性で修飾されます。 この属性では、レンダリングされる Xamarin.Forms ページの型名とカスタム レンダラーの型名という 2 つのパラメーターが使用されます。 属性の assembly
プレフィックスにより、属性がアセンブリ全体に適用されることが指定されます。
次のセクションでは、各プラットフォーム用の CameraPageRenderer
カスタム レンダラーの実装について説明します。
iOS 上でページ レンダラーを作成する
次のコード例は、iOS プラットフォーム用のページ レンダラーを示します。
[assembly:ExportRenderer (typeof(CameraPage), typeof(CameraPageRenderer))]
namespace CustomRenderer.iOS
{
public class CameraPageRenderer : PageRenderer
{
...
protected override void OnElementChanged (VisualElementChangedEventArgs e)
{
base.OnElementChanged (e);
if (e.OldElement != null || Element == null) {
return;
}
try {
SetupUserInterface ();
SetupEventHandlers ();
SetupLiveCameraStream ();
AuthorizeCameraUse ();
} catch (Exception ex) {
System.Diagnostics.Debug.WriteLine (@" ERROR: ", ex.Message);
}
}
...
}
}
基底クラスの OnElementChanged
メソッドの呼び出しによって、iOS UIViewController
コントロールがインスタンス化されます。 レンダラーが既存の Xamarin.Forms 要素にまだアタッチされておらず、カスタム レンダラーによってレンダリングされているページ インスタンスが存在する場合にのみ、ライブ カメラ ストリームがレンダリングされます。
このページは、カメラからライブ ストリームを提供する AVCapture
API と写真をキャプチャする機能を使用する一連のメソッドによってカスタマイズされます。
Android 上でページ レンダラーを作成する
次のコード例は、Android プラットフォーム用のページ レンダラーを示します。
[assembly: ExportRenderer(typeof(CameraPage), typeof(CameraPageRenderer))]
namespace CustomRenderer.Droid
{
public class CameraPageRenderer : PageRenderer, TextureView.ISurfaceTextureListener
{
...
public CameraPageRenderer(Context context) : base(context)
{
}
protected override void OnElementChanged(ElementChangedEventArgs<Page> e)
{
base.OnElementChanged(e);
if (e.OldElement != null || Element == null)
{
return;
}
try
{
SetupUserInterface();
SetupEventHandlers();
AddView(view);
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine(@" ERROR: ", ex.Message);
}
}
...
}
}
基底クラスの OnElementChanged
メソッドを呼び出すことで、Android の ViewGroup
コントロールがインスタンス化されます。これは、ビューのグループになります。 レンダラーが既存の Xamarin.Forms 要素にまだアタッチされておらず、カスタム レンダラーによってレンダリングされているページ インスタンスが存在する場合にのみ、ライブ カメラ ストリームがレンダリングされます。
このページは、カメラからライブ ストリームを提供する Camera
API と写真をキャプチャする機能を使用する一連のメソッドを呼び出すことでカスタマイズされます。それから、ライブ カメラ ストリーム UI を ViewGroup
に追加する AddView
メソッドが呼び出されます。 Android では、ビューに対してメジャーおよびレイアウト操作を実行するために OnLayout
メソッドをオーバーライドする必要もある点に注意してください。
UWP 上でページ レンダラーを作成する
次のコード例は、UWP 用のページ レンダラーを示します。
[assembly: ExportRenderer(typeof(CameraPage), typeof(CameraPageRenderer))]
namespace CustomRenderer.UWP
{
public class CameraPageRenderer : PageRenderer
{
...
protected override void OnElementChanged(ElementChangedEventArgs<Xamarin.Forms.Page> e)
{
base.OnElementChanged(e);
if (e.OldElement != null || Element == null)
{
return;
}
try
{
...
SetupUserInterface();
SetupBasedOnStateAsync();
this.Children.Add(page);
}
...
}
protected override Size ArrangeOverride(Size finalSize)
{
page.Arrange(new Windows.Foundation.Rect(0, 0, finalSize.Width, finalSize.Height));
return finalSize;
}
...
}
}
基底クラスの OnElementChanged
メソッドを呼び出すと、FrameworkElement
コントロールがインスタンス化され、ページがレンダリングされます。 レンダラーが既存の Xamarin.Forms 要素にまだアタッチされておらず、カスタム レンダラーによってレンダリングされているページ インスタンスが存在する場合にのみ、ライブ カメラ ストリームがレンダリングされます。 このページは、カメラからライブ ストリームを提供する MediaCapture
API と写真をキャプチャする機能を使用する一連のメソッドを呼び出すことでカスタマイズされます。それから、カスタマイズされたページが表示のために Children
コレクションに追加されます。
UWP 上で PageRenderer
から派生したカスタム レンダラーを実装する場合、ベース レンダラーはその処理方法を認識していないため、ページ コントロールを配置するために ArrangeOverride
メソッドも実装する必要があります。 それ以外の場合は、結果として空のページになります。 そのため、この例では、Page
インスタンスに対して ArrangeOverride
メソッドによって Arrange
メソッドが呼び出されます。
Note
UWP アプリケーションでは、カメラにアクセスできるオブジェクトを停止して破棄することが重要です。 そうしないと、デバイスのカメラにアクセスしようとする他のアプリケーションの妨げになる可能性があります。 詳細については、「Display the camera preview」(カメラ プレビューの表示) を参照してください。
まとめ
この記事では、ContentPage
ページ用のカスタム レンダラーを作成する方法について説明しました。これにより、開発者は既定のネイティブ レンダリングを、各自のプラットフォームに固有のカスタマイズでオーバーライドできるようになります。 ContentPage
は、単一ビューを表示し、画面の大部分を占めるビジュアル要素です。