個人的なメモ 〜Cocos Sharp 情報を中心に‥

Tomohiro Suzuki @hiro128_777 のブログです。Cocos Sharp の事を中心に書いています。 Microsoft MVP for Visual Studio and Development Technologies 2017- 本ブログと所属組織の公式見解は関係ございません。

Swift, Objective-C を Xamarin.iOS に移植する際のポイント(2) UIView.Layerの差し替え

はじめに

こんにちは、@hiro128_777です。

10月14日(土)に、Xamarin.iOS のハンズオンを開催いたします!

Xcode での開発経験がない方が、iOS の開発を Xamarin で始めてWebで情報を集めると、 Swift や Objective-C の情報はたくさん見つかりますが、Xamarin の情報は案外少ないことに気づきます。
そして、Swift や Objective-C のサンプルコードを見て、Xamarin に移植する必要が出てきますが、これは Xcode での開発経験がないと結構骨が折れる作業です。
そこで今回、Swift, Objective-C のコードを Xamarin.iOS に移植する際のポイントについてハンズオンを行うことにいたしましたので、ご興味がある方はぜひご参加下さい!

jxug.connpass.com


前回は、Swift のコードPhotoCaptureDelegate.swiftのコールバックメソッドの実装部分を移植しました。

hiro128.hatenablog.jp

今回は、PreviewView.swiftを Xamarin.iOS へ移植していきましょう。

PreviewView.swift の Xamarin.iOS への移植

では早速swiftのコードを見てみましょう。

Swift

import UIKit
import AVFoundation

class PreviewView: UIView {
    var videoPreviewLayer: AVCaptureVideoPreviewLayer {
        guard let layer = layer as? AVCaptureVideoPreviewLayer else {
            fatalError("Expected `AVCaptureVideoPreviewLayer` type for layer. Check PreviewView.layerClass implementation.")
        }
        
        return layer
    }
	
	var session: AVCaptureSession? {
		get {
			return videoPreviewLayer.session
		}
		set {
			videoPreviewLayer.session = newValue
		}
	}
	
	// MARK: UIView
	
    override class var layerClass: AnyClass {
		return AVCaptureVideoPreviewLayer.self
	}
}

今回、新しく出てきた文法は、override class var layerClass: AnyClass { return AVCaptureVideoPreviewLayer.self }です。

これをXamarin.iOSに移植するのは少々厄介です。特殊な表現をするので知識として知らないと移植できません。

通常、UIViewLayerは自動的に作成され割り当てられます。
デフォルトではLayerCALayerのインスタンスになりますが、overrideすることでCALayer派生の任意の型を使用できます。

Xamarin.iOSで同じことを実現するには、using ObjCRuntime;を追加し、CALayer派生の任意の型を返す静的メソッド、またはプロパティを作成し、[Export("layerClass")]を設定します。

具体的には下記のようになります。

C#

public static Class LayerClass
{
	[Export("layerClass")]
	get
	{
		return layerClass = layerClass ?? new Class(typeof(AVCaptureVideoPreviewLayer));
	}
}

または

[Export ("layerClass")]
public static Class GetLayerClass ()
{
    return new Class(typeof(AVCaptureVideoPreviewLayer));
}

このあたりを詳しくご理解したい方はこちらを参照してください。

あとは、そのまま移植するだけです。

using System;

using UIKit;
using Foundation;
using AVFoundation;
using ObjCRuntime;

namespace AVCapture
{
	[Register("PreviewView")]
	public class PreviewView : UIView
	{
		static Class layerClass;

		public static Class LayerClass
		{
			[Export("layerClass")]
			get
			{
				return layerClass = layerClass ?? new Class(typeof(AVCaptureVideoPreviewLayer));
			}
		}

		public AVCaptureSession Session
		{
			get
			{
				return VideoPreviewLayer.Session;
			}
			set
			{
				VideoPreviewLayer.Session = value;
			}
		}

		public AVCaptureVideoPreviewLayer VideoPreviewLayer
		{
			get
			{
				return (AVCaptureVideoPreviewLayer)Layer;
			}
		}

		public PreviewView()
			: base()
		{
		}

	}
}

layerClassの移植方法さえ知っていればあとは非常に簡単です。

今回はここまでです。