個人的なメモ

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

DualScreen 対応の Xamarin.Forms アプリを作ってみる (3)

はじめに

こんにちは、@hiro128_777です。

とうとう iPhone 12 が発売されましたね。でも、Surface Duo も忘れないでください。Surface Duo 日本での発売はまだですが、すでに、エミュレーターで疑似体験することは可能です。

というわけで、10月27日(火)に、エミュレーターSurface Duo 対応アプリを体験するオンラインハンズオンを開催いたします!

こちらは、簡単な Surface Duo のエミュレーターで動作するマルチスクリーン対応アプリを作って体験していただけるコンテンツになっていますので、ご興味がある方はぜひご参加下さい!


csharp-tokyo.connpass.com
 

この記事は(3)ですので、最初から手順をお試しになる場合は下記の(1)からお願いします。
hiro128.hatenablog.jp

 

(2)は下記からお願いします。
hiro128.hatenablog.jp

 

今回やること

 
ViewModel と Service を紐づけてアプリを完成させます。
 

ViewModel と Service を紐づける

 
ViewModel と Service を紐づけるコードを追記していきます。

なお、このサンプルはコードをシンプルにし、Dual Screen の動作をわかりやすくするために、 DI などコードの量が増える手法はあえて省いています。
 

MasterDetailPage.xaml.cs を修正

 
// 追記の部分を追記してください。
 

        bool IsSpanned => DualScreenInfo.Current.SpanMode != TwoPaneViewMode.SinglePane;

        DetailsPage detailsPagePushed;

        MasterViewModel masterViewModel; // 追記
        DetailsViewModel detailsViewModel; // 追記

        public MasterDetailPage()
        {
            InitializeComponent();

            NavigationPage.SetHasNavigationBar(this, IsSpanned);

            detailsPagePushed = new DetailsPage();

            masterViewModel = masterPage.BindingContext as MasterViewModel; // 追記
            masterViewModel.SetupViewsAction = () => SetupViews(); // 追記

            detailsViewModel = masterViewModel.DetailsViewModel; // 追記
            detailsPagePushed.BindingContext = detailsViewModel; // 追記
            detailsPage.BindingContext = detailsViewModel; // 追記
        }

 

Master.xaml.cs を修正

 
// 追記の部分を追記してください。
 

        public Master()
        {
            InitializeComponent();

            BindingContext = new MasterViewModel(new DetailsViewModel()); // 追記
        }

 

View から確認用の マークアップ を消去

 
<!-- 確認用(後ほど消去する)ここから -->から<!-- 確認用(後ほど消去する)ここまで -->の部分を消去してください。

    <Picker
        Title="路線を選択して下さい"
        Margin="10"
        HeightRequest="60"
        FontSize="Large"
        HorizontalOptions="Fill"
        VerticalOptions="Fill"
        ItemsSource="{Binding LineItems}"
        SelectedItem="{Binding SelectedLineItem, Mode=TwoWay}"
        >
    </Picker>
    <!-- 確認用(後ほど消去する)ここから -->
    <Label FontSize="Title" TextColor="Coral" Text="Master" HorizontalOptions="CenterAndExpand">
    </Label>
    <!-- 確認用(後ほど消去する)ここまで -->
    <CollectionView
        x:Name="Stations"
        ItemsSource="{Binding StationItems}"
        SelectionMode="Single"
        SelectedItem="{Binding SelectedStationItem, Mode=TwoWay}"
        SelectionChangedCommand="{Binding SelectStationCommand}"
        >

 

Details.xaml から確認用の マークアップ を消去

 
<!-- 確認用(後ほど消去する)ここから -->から<!-- 確認用(後ほど消去する)ここまで -->の部分を消去してください。

        <Label
            BackgroundColor="White"
            FontSize="Title"
            Grid.Column="1" Grid.Row="1"
            Text="{Binding Name}"
            VerticalTextAlignment="Center"
            >
        </Label>
    </Grid>
    <!-- 確認用(後ほど消去する)ここから -->
    <Label FontSize="Title" TextColor="Coral" Text="Detail" HorizontalOptions="CenterAndExpand">
    </Label>
    <!-- 確認用(後ほど消去する)ここまで -->
    <StackLayout
        BackgroundColor="White"
        Padding="5">

 

以上でコードは完成です。
 

デバッグ実行し、Dual Screen でアプリが動作するか確認する

 
Dual Screen で表示させるためには以下の動画の手順でアプリをスパンしてください。

Surface Duo Span 操作
youtu.be
 

上記の動画のように、路線と駅が選択でき、時刻が表示されればサンプルアプリは完成です。
 

今回は以上です。

DualScreen 対応の Xamarin.Forms アプリを作ってみる (2)

はじめに

こんにちは、@hiro128_777です。

とうとう iPhone 12 が発表されましたね。でも、Surface Duo も忘れないでください。Surface Duo 日本での発売はまだですが、すでに、エミュレーターで疑似体験することは可能です。

というわけで、10月27日(火)に、エミュレーターSurface Duo 対応アプリを体験するオンラインハンズオンを開催いたします!

こちらは、簡単な Surface Duo のエミュレーターで動作するマルチスクリーン対応アプリを作って体験していただけるコンテンツになっていますので、ご興味がある方はぜひご参加下さい!

csharp-tokyo.connpass.com


なお、この記事は(2)ですので、最初から手順をお試しになる場合は下記の(1)からお願いします。
hiro128.hatenablog.jp



今回やること

TwoPaneViewを作成し、Surface Duo エミュレータ―上で、Master - Detail 構成のページを Dual Screen 表示できるようにします。

TwoPaneViewGridを継承しており、左右または上下に 2 つのビューを配置できるコンテナーです。

TwoPaneViewの詳細については下記公式ドキュメントをご参照ください。

docs.microsoft.com



Dual Screen に対応するには、以下の対応を行うだけであり、非常に簡単です。

  • Single Screen 用と、Dual Screen 用の "ガワ" の ContentPage を別々に用意し、それぞれのコンテンツの配置情報のみ記述する。

  • 具体的なコンテンツ(配置する UI)の XAML を用意する。

  • TwoPaneViewが 画面の表示領域のサイズによって、Single Screen 用または、Dual Screen 用 の画面を表示できるように、MinWideModeWidthMinTallModeHeightを設定します。


TwoPaneViewの Single Screen、Dual Screen の制御の詳細については下記公式ドキュメントをご参照ください。

docs.microsoft.com


これから作成するサンプルアプリの Single Screen、Dual Screen のときの構成を図に表すと以下のようになります。

Single Screen 時の構成

f:id:hiro128:20201018171513p:plain
 

Dual Screen 時の構成

f:id:hiro128:20201018171631p:plain
 

では、次にコードを書いていきましょう。 

TwoPaneView用のコンテンツページとコンテンツビューのファイル追加する

 

  1. View フォルダを追加します。
  2. 以下の4つのコンテンツページを追加します。
    1. MasterDetailPage.xaml コンテンツページ
    2. DetailsPage.xaml コンテンツページ
    3. Master.xaml コンテンツビュー
    4. Details.xaml コンテンツビュー


以下のようになればOKです。
f:id:hiro128:20201018162214p:plain


デフォルトの MainPage に設定されているMainPage.xamlを削除します。

f:id:hiro128:20201018165908p:plain
 

MasterDetailPage を MainPage として設定します。
 

App.xaml.cs
        public App()
        {
            InitializeComponent();
            MainPage = new NavigationPage(new MasterDetailPage());
        }

 

MasterDetailPage.xamlマークアップとコードを記述する

 
Single Screen 時は Master Page のコンテンツのみ表示し、Dual Screen 時は 左に Master Page のコンテンツ、右に Detail Page のコンテンツを表示します。
 

MasterDetailPage.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:d="http://xamarin.com/schemas/2014/forms/design"
            xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
            xmlns:dualScreen="clr-namespace:Xamarin.Forms.DualScreen;assembly=Xamarin.Forms.DualScreen"
            xmlns:local="clr-namespace:XFSurfaceDuoSample2020"
            mc:Ignorable="d"
            x:Class="XFSurfaceDuoSample2020.MasterDetailPage">
    <dualScreen:TwoPaneView MinWideModeWidth="4000" MinTallModeHeight="4000">
        <dualScreen:TwoPaneView.Pane1>
            <local:Master x:Name="masterPage"></local:Master>
        </dualScreen:TwoPaneView.Pane1>
        <dualScreen:TwoPaneView.Pane2>
            <local:Details x:Name="detailsPage"></local:Details>
        </dualScreen:TwoPaneView.Pane2>
    </dualScreen:TwoPaneView>
</ContentPage>

 

MasterDetailPage.xaml.cs
using System.ComponentModel;
using System.Linq;
using Xamarin.Forms;
using Xamarin.Forms.DualScreen;
using Xamarin.Forms.Xaml;

using XFSurfaceDuoSample2020.Models;
using XFSurfaceDuoSample2020.ViewModels;

namespace XFSurfaceDuoSample2020
{
    [XamlCompilation(XamlCompilationOptions.Compile)]
    public partial class MasterDetailPage
    {
        bool IsSpanned => DualScreenInfo.Current.SpanMode != TwoPaneViewMode.SinglePane;

        DetailsPage detailsPagePushed;

        public MasterDetailPage()
        {
            InitializeComponent();
            NavigationPage.SetHasNavigationBar(this, IsSpanned);
            detailsPagePushed = new DetailsPage();
        }

        async void SetupViews()
        {
            NavigationPage.SetHasNavigationBar(this, !IsSpanned);
            NavigationPage.SetHasNavigationBar(detailsPagePushed, !IsSpanned);
            NavigationPage.SetHasNavigationBar(detailsPage, !IsSpanned);

            if (!IsSpanned)
            {
                if (!Navigation.NavigationStack.Contains(detailsPagePushed))
                    await Navigation.PushAsync(detailsPagePushed);
            }
        }

        protected override void OnAppearing()
        {
            base.OnAppearing();
            DualScreenInfo.Current.PropertyChanged += OnFormsWindowPropertyChanged;
        }

        protected override void OnDisappearing()
        {
            base.OnDisappearing();
            DualScreenInfo.Current.PropertyChanged -= OnFormsWindowPropertyChanged;
        }

        void OnFormsWindowPropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            if (e.PropertyName == nameof(DualScreenInfo.Current.SpanMode) ||
                e.PropertyName == nameof(DualScreenInfo.Current.IsLandscape))
            {
                SetupViews();
            }
        }

    }
}

 

DetailsPage.xamlマークアップとコードを記述する

 
Single Screen 時は Detail Page を表示します。Dual Screen 時は使用されません。
 

DetailsPage.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:d="http://xamarin.com/schemas/2014/forms/design"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
             xmlns:local="clr-namespace:XFSurfaceDuoSample2020"
             mc:Ignorable="d"
             x:Class="XFSurfaceDuoSample2020.DetailsPage"
             Title="Master Details"
             Padding="10,0,0,0"
             >
    <local:Details></local:Details>
</ContentPage>

 

DetailsPage.xaml.cs
using Xamarin.Forms.DualScreen;
using Xamarin.Forms.Xaml;

namespace XFSurfaceDuoSample2020
{
    [XamlCompilation(XamlCompilationOptions.Compile)]
    public partial class DetailsPage
    {
        bool IsSpanned => DualScreenInfo.Current.SpanMode != TwoPaneViewMode.SinglePane;

        public DetailsPage()
        {
            InitializeComponent();
        }

        protected override void OnAppearing()
        {
            base.OnAppearing();
            DualScreenInfo.Current.PropertyChanged += OnFormsWindowPropertyChanged;
        }

        protected override void OnDisappearing()
        {
            base.OnDisappearing();
            DualScreenInfo.Current.PropertyChanged -= OnFormsWindowPropertyChanged;
        }

        async void OnFormsWindowPropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
        {
            if(e.PropertyName == nameof(DualScreenInfo.Current.SpanMode) ||
                e.PropertyName == nameof(DualScreenInfo.Current.IsLandscape))
            {
                if (IsSpanned)
                    await Navigation.PopAsync();
            }
        }
    }
}

 
 

Master.xamlマークアップとコードを記述する

 
Master Page のコンテンツです。
 

Master.xaml
<?xml version="1.0" encoding="utf-8" ?>
<StackLayout
    xmlns="http://xamarin.com/schemas/2014/forms"
    xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
    xmlns:d="http://xamarin.com/schemas/2014/forms/design"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d"
    x:Class="XFSurfaceDuoSample2020.Master"
    >
    <StackLayout.Resources>
        <ResourceDictionary>
            <Style TargetType="Grid">
                <Setter Property="VisualStateManager.VisualStateGroups">
                    <VisualStateGroupList>
                        <VisualStateGroup x:Name="CommonStates">
                            <VisualState x:Name="Normal" />
                            <VisualState x:Name="Selected">
                                <VisualState.Setters>
                                    <Setter
                                        Property="BackgroundColor"
                                        Value="LightSkyBlue"
                                        />
                                </VisualState.Setters>
                            </VisualState>
                        </VisualStateGroup>
                    </VisualStateGroupList>
                </Setter>
            </Style>
        </ResourceDictionary>
    </StackLayout.Resources>
    <Picker
        Title="路線を選択して下さい"
        Margin="10"
        HeightRequest="60"
        FontSize="Large"
        HorizontalOptions="Fill"
        VerticalOptions="Fill"
        ItemsSource="{Binding LineItems}"
        SelectedItem="{Binding SelectedLineItem, Mode=TwoWay}"
        >
    </Picker>
    <!-- 確認用(後ほど消去する)ここから -->
    <Label FontSize="Large" TextColor="Coral" Text="Master Page のコンテンツ" HorizontalOptions="CenterAndExpand">
    </Label>
    <!-- 確認用(後ほど消去する)ここまで -->
    <CollectionView
        x:Name="Stations"
        ItemsSource="{Binding StationItems}"
        SelectionMode="Single"
        SelectedItem="{Binding SelectedStationItem, Mode=TwoWay}"
        SelectionChangedCommand="{Binding SelectStationCommand}"
        >
        <CollectionView.ItemTemplate>
            <DataTemplate>
                <Grid
                    Padding="5"
                    >
                    <Frame Visual="Material" BorderColor="LightGray">
                        <StackLayout
                            Padding="0"
                            >
                            <Label FontSize="Title" Text="{Binding Name}">
                            </Label>
                        </StackLayout>
                    </Frame>
                </Grid>
            </DataTemplate>
        </CollectionView.ItemTemplate>
    </CollectionView>
</StackLayout>

 

Master.xaml.cs
using Xamarin.Forms;
using Xamarin.Forms.Xaml;

using XFSurfaceDuoSample2020.ViewModels;

namespace XFSurfaceDuoSample2020
{
    [XamlCompilation(XamlCompilationOptions.Compile)]
    public partial class Master : StackLayout
    {
        public Master()
        {
            InitializeComponent();
        }
    }
}

 

Details.xamlマークアップとコードを記述する

 
Detail Page のコンテンツです。
 

Details.xaml
<?xml version="1.0" encoding="UTF-8"?>
<StackLayout xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:d="http://xamarin.com/schemas/2014/forms/design"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
             mc:Ignorable="d"
             x:Class="XFSurfaceDuoSample2020.Details"
             BackgroundColor="LightGray"
             Spacing="0"
             >
    <Grid
        BackgroundColor="White"
        RowSpacing="2" ColumnSpacing="2"
        Padding="8,8,8,0"
        VerticalOptions="Center"
        >
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"></RowDefinition>
            <RowDefinition Height="Auto"></RowDefinition>
            <RowDefinition Height="*"></RowDefinition>
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="Auto"></ColumnDefinition>
            <ColumnDefinition Width="*"></ColumnDefinition>
        </Grid.ColumnDefinitions>
        <Label
            BackgroundColor="White"
            HorizontalTextAlignment="End" VerticalTextAlignment="Center"
            FontSize="Title" Text="ナンバリング :"
            >
        </Label>
        <Label
            BackgroundColor="White"
            Grid.Row="1"
            HorizontalTextAlignment="End" VerticalTextAlignment="Center"
            FontSize="Title" Text="駅名 :"
            >
        </Label>
        <Label
            BackgroundColor="White"
            FontSize="Title"
            Grid.Column="1"
            Text="{Binding SelectedStationItem.ID}"
            VerticalTextAlignment="Center"
            >
        </Label>
        <Label
            BackgroundColor="White"
            FontSize="Title"
            Grid.Column="1" Grid.Row="1"
            Text="{Binding Name}"
            VerticalTextAlignment="Center"
            >
        </Label>
    </Grid>
    <StackLayout
        BackgroundColor="White"
        Padding="5">
        <!-- 確認用(後ほど消去する)ここから -->
        <Label FontSize="Large" TextColor="Coral" Text="Detail Page のコンテンツ" HorizontalOptions="CenterAndExpand">
        </Label>
        <!-- 確認用(後ほど消去する)ここまで -->
        <CollectionView
            Margin="3"
            BackgroundColor="LightGray"
            x:Name="Stations"
            ItemsSource="{Binding TimeTableRowItems}"
            SelectionMode="None"
            >
            <CollectionView.ItemTemplate>
                <DataTemplate>
                    <StackLayout
                        BackgroundColor="LightGray"
                        Padding="1">
                        <Grid
                            BackgroundColor="LightGray"
                            HorizontalOptions="Fill"
                            VerticalOptions="Center"
                            ColumnSpacing="2"
                            Padding="2,1,2,1"
                            >
                            <Grid.RowDefinitions>
                                <RowDefinition Height="Auto"></RowDefinition>
                            </Grid.RowDefinitions>
                            <Grid.ColumnDefinitions>
                                <ColumnDefinition Width="*"></ColumnDefinition>
                                <ColumnDefinition Width="10*"></ColumnDefinition>
                            </Grid.ColumnDefinitions>
                            <Label
                                BackgroundColor="LightSkyBlue"
                                Padding="8"
                                Grid.Column="0" Grid.Row="0"
                                Text="{Binding Hour}"
                                FontSize="Large"
                                HorizontalTextAlignment="Center" 
                                VerticalTextAlignment="Center"
                                >
                            </Label>
                            <Label
                                BackgroundColor="Beige"
                                Padding="8"
                                Grid.Column="1" Grid.Row="0"
                                Text="{Binding RowText}"
                                FontSize="Large"
                                HorizontalTextAlignment="Start"
                                VerticalTextAlignment="Center"
                                >
                            </Label>
                        </Grid>
                    </StackLayout>
                </DataTemplate>
            </CollectionView.ItemTemplate>
        </CollectionView>
    </StackLayout>
</StackLayout>

 

Details.xaml.cs
using Xamarin.Forms;
using Xamarin.Forms.Xaml;

namespace XFSurfaceDuoSample2020
{
    [XamlCompilation(XamlCompilationOptions.Compile)]
    public partial class Details : StackLayout
    {
        public Details()
        {
            InitializeComponent();
        }
    }
}

 

デバッグ実行し、Single Screen、Dual Screen で表示されるか確認する。

 
Surface Duo エミュレータ―にデプロイすると、以下のように、Single Screen、Dual Screen で表示が変化します。
 

Single Screen での表示

f:id:hiro128:20201018214953p:plain
 

Dual Screen での表示

f:id:hiro128:20201018215010p:plain

 
  
Dual Screen で表示させるためには以下の動画の手順でアプリをスパンしてください。
なお、アプリのロジックはまだ実装していないので、画面が表示されるだけで、UI は反応しません。
 
Surface Duo Span 操作
youtu.be

 

続きは以下をご覧ください。
hiro128.hatenablog.jp

DualScreen 対応の Xamarin.Forms アプリを作ってみる (1)

はじめに

こんにちは、@hiro128_777です。

とうとう iPhone 12 が発表されましたね。でも、Surface Duo も忘れないでください。Surface Duo 日本での発売はまだですが、すでに、エミュレーターで疑似体験することは可能です。

というわけで、10月27日(火)に、エミュレーターSurface Duo 対応アプリを体験するオンラインハンズオンを開催いたします!

こちらは、簡単な Surface Duo のエミュレーターで動作するマルチスクリーン対応アプリを作って体験していただけるコンテンツになっていますので、ご興味がある方はぜひご参加下さい!


csharp-tokyo.connpass.com


今回から数回 DualScreen 対応の Xamarin.Forms アプリを作る方法をご紹介します。

今回の内容の詳しい手順は、下記公式ドキュメントにもあります。
なお、サンプルのソリューションを準備しましたので、より詳しい手順を追って、実際に触って試していただけるようにしました。


docs.microsoft.com


エミュレーターのインストール

MacWindows それぞれの方法をまとめてありますので、以下の記事をご参照ください。

サンプルのソリューション

以下より取得してください。
github.com


XFSurfaceDuoSample2020/start-long/XFSurfaceDuoSample2020.slnを開ます。


SDK のインストール

NuGet パッケージ マネージャーで Xamarin.Forms.DualScreen を検索し、ソリューションのそれぞれのプロジェクトに、 Xamarin.Forms と同じバージョンの Xamarin.Forms.DualScreen パッケージをインストールします。

f:id:hiro128:20201013230011p:plain


MainActivity クラスの変更

 

属性の変更

Android プロジェクトの MainActivity クラスの ConfigurationChanges 属性を確認し、属性が足りなければ変更します。

ConfigurationChanges を設定することで、構成の変更が発生した場合にシステムによってアクティビティが再起動されなくなります。また、発生時の処理のコードを記述することもできます。

詳しくは、以下の公式ドキュメントをご参照ください。

docs.microsoft.com


以下の属性が設定されていることを確認してください。

ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation | ConfigChanges.ScreenLayout | ConfigChanges.SmallestScreenSize | ConfigChanges.UiMode

 

以下のようになります。

    [Activity(Label = "XFSurfaceDuoSample2020", Icon = "@mipmap/icon", Theme = "@style/MainTheme", MainLauncher = true, 
        ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation | ConfigChanges.UiMode | ConfigChanges.ScreenLayout | ConfigChanges.SmallestScreenSize 
    )]
    public class MainActivity : global::Xamarin.Forms.Platform.Android.FormsAppCompatActivity

 

DualScreenService の初期化

次に、DualScreenService を初期化します。

OnCreate メソッドの LoadApplication(new App()); の直上に以下の初期化メソッド呼び出しを追加します。

// Initialize DualScreen Service
Xamarin.Forms.DualScreen.DualScreenService.Init(this);

 

以下のようになります。

            Xamarin.Essentials.Platform.Init(this, savedInstanceState);
            global::Xamarin.Forms.Forms.Init(this, savedInstanceState);

            // Initialize DualScreen Service
            Xamarin.Forms.DualScreen.DualScreenService.Init(this);

            LoadApplication(new App());
        }

 


エミュレータ―上でデバッグ実行

ビルドし、 (Android 10.0 - API 29) を選択し、デバッグ実行できれば成功です。

Mac

f:id:hiro128:20201013225904p:plain


Windows

f:id:hiro128:20201013225949p:plain



デプロイが完了し、以下のようになれば成功です。

f:id:hiro128:20201013232449p:plain


続きは以下をご覧ください。
hiro128.hatenablog.jp

Visual Studio 2019 (Windows) で Surface Duo エミュレーターを使用してみる

はじめに

こんにちは、@hiro128_777です。

いよいよ、Surface Duo が発売になりますね。自分も買って試してみたいですが、残念ながらまだ、日本での発売は発表されていません。

でも、とりあえず早く触ってみたいという方は「Surface Duo エミュレーター」なら今すぐ試せます。

というわけで、Visual Studio 2019 で Surface Duo エミュレーターを使用してみました。

Microsoft Docs に手順がありますが、画像が無くわかりにくいので、画像付きでご説明します。


SDK のインストール

以下のように、API 29 の SDK をインストールします。 

f:id:hiro128:20200920211006p:plain


f:id:hiro128:20200920211022p:plain


f:id:hiro128:20200920211039p:plain


Surface Duo エミュレーターのセットアップ

以下のページを開いて、記載の手順通り「Surface Duo SDK プレビューリリース」から、ダウンロードページにアクセスして、インストーラーをダウンロードしてください。

docs.microsoft.com


インストーラーを起動して Surface Duo エミュレーターをインストールします。

f:id:hiro128:20200922161026p:plain


Surface Duo エミュレーター の起動スクリプトの確認

Android SDK のインストールパスをカスタマイズしている場合、以下の手順で、Surface Duo エミュレーターの起動スクリプトの設定を確認します。 (Android SDK のインストールパスがデフォルトの場合、変更の必要はありません。)

docs.microsoft.com


Surface Duo エミュレーターを起動します。

以下のページの手順の通り、スタートメニューから Surface Duo Emulator for Visual Studio を起動します。

docs.microsoft.com

f:id:hiro128:20200920211425p:plain


起動すると以下のようになります。

f:id:hiro128:20200922160530p:plain


早速アプリをビルドして実行してみましょう

以下にビルドしてすぐデプロイできるサンプルアプリを準備しました。

github.com


Visual Studio 2019 で XFSurfaceDuoSample2020/finish/XFSurfaceDuoSample2020.sln を開き、ビルドして、(実行中のデバイスの一覧で) (Android 10.0 - API 29) を選択し、デバッグ実行します。

f:id:hiro128:20200920211443p:plain



以下の動画の通り、デプロイされアプリが動きます。
なお、Dual Screen で表示させるためには以下の動画の手順でアプリをスパンしてください。

youtu.be


今回は、以上です。

.NET MAUI について今わかっている事を整理しました

MAUI とは

.NET Multi-platform App UI
の略称です。

 

MAUI ってどんなもの?

  • マルチプラットフォームのネイティブ UI ライブラリ
  • モバイルとデスクトップの複数のデバイスにデプロイ可能
  • 単一のプロジェクト、単一のコードベースを使用する
  • Xamarin.Forms の進化版
  • .NET MAUI および新しいモバイル SDK は、.NET 6 と一緒にリリースされる予定です。なお、2020年末にプレビューの予定です。

※ つまり、残念ながら .NET 5 での .NET Core と Mono の統合は延期され、.NET 6 での統合になったということになります…

MAUI のゴール

  • アプリのパフォーマンスを向上させる
  • 簡単にコントロールを拡張できるようにする
  • 簡単にコントリビュートできるようにする
  • Model-View-Update(MVU)と Blazor のアプリパターンを提供する

 

マイルストーン

 

対応プラットフォーム

   Xamarin.Forms        .NET MAUI    
Android API 19 以降 API 21 以降
iOS iOS 9 から iOS 15 まで iOS 10 以降
Linux Community Community
macOS Community Microsoft
Tizen Samsung Samsung
Windows UWP Microsoft WPF Community Microsoft

特長

   Xamarin.Forms        .NET MAUI    
Renderers BindableObject に密結合 疎結合
コア依存なし
スリムレンダラー
App Models MVVM
RxUI
MVVM
RxUI
MVU
Blazor
Single Project ×
Multi-targeting ×
Multi-window ×

 

対応 .NET、プロジェクト形式など

   Xamarin.Forms        .NET MAUI    
対応 .NET Xamarin.iOS
Xamarin.Android
Mono
.NET Framework
その他
.NET 6 以降
取得方法 NuGet & Visual Studio Installer dotnet CLI
プロジェクト形式 SDK 形式 SDK 形式
dotnet CLI 対応 ×

 

開発環境

   Xamarin.Forms        .NET MAUI    
Visual Studio 2019
Visual Studio 2019 for Mac
Visual Studio Code ×

 

MVUの採用

MAUI では、新しいアプリパターンである、MVU が採用される予定です。.NET Blog に、コードのサンプルも提示されていましたが、現在、議論中のため、具体的なコードは提示いたしません。
 

MVUの特長

同じく、.NET Blog によると、MVU には以下の特長があるとのことです。

  • データと状態の管理のフローが一方向になる
  • 必要な変更のみを適用することで UI を迅速に更新できる
  • ホットリロードに最適である

 
 

Xamarin.Forms はどうなるの…

  • Xamarin.Forms の次のメジャーバージョンは2020年9月頃になる予定
  • .NET 6 での .NET MAUI のリリースを通じて引き続き更新されます。
  • その後、Xamarin.Forms は 12 か月間は従来同様メンテナンスされます。(つまり 12か月後以降にはメンテナンスが終了し、製品の終焉を迎えることになりりそうです…)

 

 

本日は以上です。

Visual Studio for Mac で Surface Duo エミュレーターを使用してみる

はじめに

こんにちは、@hiro128_777です。

いよいよ、Surface Duo が発売になりますね。自分も買って試してみたいですが、残念ながらまだ、日本での発売は発表されていません。

でも、とりあえず早く触ってみたいという方は「Surface Duo エミュレーター」なら今すぐ試せます。

というわけで、Visual Studio for MacSurface Duo エミュレーターを使用してみました。

Microsoft Docs に手順がありますが、画像が無くわかりにくいので、画像付きでご説明します。


SDK のインストール

以下のように、API 29 の SDK をインストールします。 

f:id:hiro128:20200906141054p:plain

f:id:hiro128:20200906141116p:plain


Surface Duo エミュレーター のセットアップ

以下のページを開いて、記載の手順通り「Surface Duo SDK プレビューリリース」から、ダウンロードページにアクセスして、dmg イメージをダウンロードしてください。

docs.microsoft.com


上記のページの手順通り、dmg をマウントして、からターミナルで解凍したフォルダに移動します。

f:id:hiro128:20200906141155p:plain

f:id:hiro128:20200906141210p:plain


Surface Duo エミュレーター の起動スクリプトの確認

Android SDK のインストールパスをカスタマイズしている場合、以下の手順で、Surface Duo エミュレーターの起動スクリプトの設定を確認します。 (Android SDK のインストールパスがデフォルトの場合、変更の必要はありません。)

docs.microsoft.com


Surface Duo エミュレーターを起動します。

以下のページの手順の通り、起動スクリプトを実行して、Surface Duo エミュレーターを起動します。

docs.microsoft.com


Surface Duo エミュレーターディレクトリーで

./run_vs.sh

Surface Duo エミュレーターが起動します。

f:id:hiro128:20200906150835p:plain

f:id:hiro128:20200906150903p:plain


早速アプリをビルドして実行してみましょう

以下にビルドしてすぐデプロイできるサンプルアプリを準備しました。

github.com


Visual Studio for MacXFSurfaceDuoSample2020/finish/XFSurfaceDuoSample2020.sln を開き、ビルドして、(実行中のデバイスの一覧で) (Android 10.0 - API 29) を選択し、デバッグ実行します。

f:id:hiro128:20200906150931p:plain



以下の動画の通り、デプロイされアプリが動きます。
なお、Dual Screen で表示させるためには以下の動画の手順でアプリをスパンしてください。

youtu.be


今回は、以上です。

Microsoft Docs 「Objective-C 開発者向けの C# 入門書」

はじめに

こんにちは、@hiro128_777です。
Microsoft Docs の Xamarin.iOS のカテゴリでぜひとも読んでいただきたい記事をご紹介します。

docs.microsoft.com


この記事は、「Objective-C 開発者向けの C# 入門書」というタイトルですが、Xamarin.iOSObjective-C の関係性を理解するのにとても役立ちます。こちらを理解しておくことで、Xamarin.iOS でのハマりどころを理解することができるので、是非、一読していただきたいです。

その中でも、特に重要な部分をピックアップしました。


Objective-C との相互運用

docs.microsoft.com


Xamarin.iOS は単なる、Objective-C の wrapper ではありません。お互いに相互運用できるようになっています。相互運用についての解説です。

プロトコルインターフェイス

docs.microsoft.com


Objective-CプロトコルC#インターフェイスとの違いを説明しています。 どちらも目的は同じですが、微妙な違いがあります。違いについての解説です。この知識は、Objective-CC# に移植する時に特に重要です。


セレクターと名前付きパラメーター

docs.microsoft.com


セレクターのエコシステムをどのように C# の世界で利用するかについて説明しています。Xamarin.iOS ではイベントの代わりにセレクターを使用することも多いので、とても重要な内容です。

本日は以上です。