えっ！？XamarinでSwiftUI触れるんですか！？

# はじめに

初めましての方が多いと思います。
＠nao-aと申します。
　
この記事は「Xamarin Advent Calendar 2020」の14日目になります。

みなさんはXamarinはもちろんのこと、SwiftUIについてもご存知だと思います。

私はどちらもあまりよくは知らないのですが、今回、このアドベントカレンダーに参加するに当たって、何かいいネタが無いかな、と探っていたところ、[Xamarin.SwiftUI](https://github.com/chkn/Xamarin.SwiftUI)というものに突き当たりましたので、そちらを試してみた記事となります。

注意点として、**Xamarin.SwiftUIはまだPre-Releaseなプロダクトです。**実開発での使用は執筆時自転では非常に厳しい印象を受けました。今後の開発に期待したいです。

なお、本記事で作成した内容は以下のリポジトリに配置しております
https://github.com/cocoalix/Xamarin.SwiftUI.Sample

# 動作環境

- macOS 11.0.1 BigSur
- VisualStudio for Mac 8.8.3
- Xamarin.SwiftUIはC#9を要求されます
- その他
    - 私は ソリューションの作成から iOS > 単一ビューアプリ ... といった選択でソリューションを作成しました
    - Xamarin.Fromsについては私はそこまで詳しくありませんので試しておりません (Xamarin.Macならほんのちょっと。。。)
        - (なお、本当はXamarin.Macで試したかったのですが、NSHostingControllerが実装されていない為、対応できませんでした。。。)
    - その他、詳しいことはXamarin.SwiftUIのReadme.mdなどを参照してください

# 事前準備

まず、プロジェクトを作成します
プロジェクトを作成したら、Xamarin.SwiftUIを以下の工程を実施します

1. プロジェクト > NuGetパッケージの管理 を選択
2. 左上の「nuget.org」となっているコンボボックスから、「ソースの構成」を選択
![スクリーンショット 2020-12-12 16.46.42.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/507143/d0208c62-8417-1717-2657-025979e81acd.png)
3. 「NuGetパッケージの管理」ウィンドウが表示されるので、右下の「追加」を選択
4. 「パッケージソースを追加する」ダイアログが表示されるので、以下設定を行う
    - 名前: 任意 (今回は「pkgs.dev.azure.com」としております)
    - 場所: 
 https://pkgs.dev.azure.com/alcorra/Xamarin.SwiftUI/_packaging/master/nuget/v3/index.json
5. ダイアログ右下の「ソースの追加」を選択する
![スクリーンショット 2020-12-12 16.47.12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/507143/747d91d5-c243-85a7-72b2-900dd498244c.png)
6. 左上のコンボボックスを先ほど設定した名前のものに変更する
7. 左下の「プレリリースパッケージを表示する」にチェックを入れる
8. Xamarin.SwiftUIが項目に出てくるので、それにチェックを入れる
9. 右下の「パッケージの追加」を選択する
![スクリーンショット 2020-12-12 16.47.28.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/507143/3c0587e9-0c1f-b96c-06e0-13fdfa920eab.png)

# HelloView (公式サンプルをそのまま扱えるか検証してみる)

[ソースはこちら](https://github.com/cocoalix/Xamarin.SwiftUI.Sample/tree/step1-hello-view)

まず、Sampleとしてリポジトリにアップされているコードがきちんと動くのかどうかを検証します

以下の新しいソースを追加します

```HelloView.cs
	public partial record HelloView : View
	{
		readonly State<int> clicks = new(0);

		public View Body =>	Button($"Clicked {clicks.Value} times", () => clicks.Value++);
	}
```

次に、ViewControllerを以下のように変えます

```ViewController.cs
    // このアトリビュートを入れます
    [DesignTimeVisible(true)]
    // 継承元は UIHostingViewController に変更します
    public partial class ViewController : UIHostingViewController
    {
        // このコンストラクタを追加します / baseには先ほどのHelloViewのインスタンスを指定
        public ViewController() : base(new HelloView())
        {
        }

        public ViewController(IntPtr handle) : base(handle)
        {
        }

        public override void ViewDidLoad()
        {
            base.ViewDidLoad();
            // Perform any additional setup after loading the view, typically from a nib.
        }

        public override void DidReceiveMemoryWarning()
        {
            base.DidReceiveMemoryWarning();
            // Release any cached data, images, etc that aren't in use.
        }

        // こちらも追加します
        [Export("awakeAfterUsingCoder:")]
        public ViewController AwakeAfterUsingCoder(NSCoder coder)
            => new ViewController();
    }
```

## こんな感じで動きます

![1.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/507143/9beacf70-0ce0-8691-9427-994c8e30aa74.gif)

# 複数ビューを扱えるか検証してみる

[ソースはこちら](https://github.com/cocoalix/Xamarin.SwiftUI.Sample/tree/step2-show-two-controls)

ViewControllerを以下のように変えます

```HelloView.cs
	public partial record HelloView : View
	{
		readonly State<int> clicks = new(0);

		public View Body => ViewBuilder.BuildBlock<Button<Text>, Text>(
			Button($"Clicked {clicks.Value} times",
				() => clicks.Value++
			), new Text("Test")
		);
	}
```

## こんな感じで動きます

![2.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/507143/3583dc10-aa5c-706a-71d8-db9abecdd612.gif)

# 現時点でできないこと (私がわかる範囲で)

- Xamarin.SwiftUIで使用できるコントロールはおそらくButtonとTextコントロールのみとなります => 他のコントロールを記述できません
- 複数のコントロールを配置したビューを作成するのはちょっと難しいです (`ViewBuilder.BuildBlock`の記述をネストさせていかないとならなさそう。。。)
- その他、背景の変更 (`SwiftUI.View.Background`) や透明度の変更 (`.Opacity()`) などができそうでしたが、試したところうまく動作させることができませんでした。。。
- 前述の通り、Xamarin.Macで使用しようとしましたが、私にはひとまずできませんでした。。(NSHostingControllerが無いため) (ただ、ドキュメントによると実装できるらしい。。。？ので、まだ検証の余地はあるかもしれません)

# まとめ

- C#9でSwiftUIを記述する試みが始まっている
- もちろん、まだ開発中なので実開発での使用は厳しい、今後に期待
    - 実リリースされた場合、Xamarin.Macの開発がいい感じに楽になりそう。。。！

最後まで閲覧いただき、ありがとうございました。