takataka430’s blog

Xamarin.Formsを中心に勉強したことのまとめを書きます

Remote Assistのモバイルアプリを使ってみた

今月の初めにDynamics 365 Remote Assistのアップデートでモバイルアプリが一般提供されましたね。

cloudblogs.microsoft.com

というわけで早速使ってみました。

Remote Assist とは

その前に、まずはRemote Assistについて説明します。
簡単にいうとTV会議に加えて、矢印や線を画面で共有することによって遠隔地にいる相手とコミュニケーションをとることが出来るツールです。
文字だけだとわかりにくいと思うので以下のリンクの「概要を見る」をクリックしてビデオを見てください。イメージしやすいと思います。

dynamics.microsoft.com

公式ドキュメントはこちら

docs.microsoft.com

Remote Assist モバイルアプリを使ってみた

利用するためにはライセンスが必要なのですが、ちょっと試すだけだったらアプリをダウンロードするだけで試すことができます。通信はできませんが、空間に矢印を置いたり線を引いたりを体験することができます。

手順としては、まずスマートフォンにアプリをダウンロードします。

Android : https://play.google.com/store/apps/details?id=com.microsoft.ramobile
iOS : https://apps.apple.com/app/id1470512565

これで準備はOKです。
アプリを起動して、試すボタンを押します。

f:id:takataka430:20191015004717p:plain:w200

以下の画像のようにカメラ越しに見ている風景に矢印を立てたり線を描いたりすることができます。

f:id:takataka430:20191015004535p:plain:w200

簡単に出来るので是非使ってみてください。

【Xamarin.Forms】TabbedPageクイックスタート

Xamarin.Formsでタブページの使い方を調べていたのですが、最初よくわからなくてつまづきました。簡単に使い始めるための方法を書きます。 ちなみに、プロジェクトを作成する際に「タブ付きフォームアプリ」をテンプレートとして選択すれば最初から使えるわけですが、今回は「空白のフォームアプリ」を選択した場合の方法を記載します。

環境

Visual Studio 2019 for Mac
Xamarin.Forms 4.1.0.555618

やり方

前提として、「空白のフォームアプリ」で新しいアプリを作成している状態を想定します。

まずは.NetStandardのプロジェクトを右クリックし、「追加」→「新しいファイルを作成」を選択します。

f:id:takataka430:20190907005526p:plain

左メニューからFormsを選択し、その中の「フォーム ContenPage XAML」を選択、名前をつけて右下の新規をクリックします。

f:id:takataka430:20190907005543p:plain

これでContentPageが2つできました(元からあったものと、新規追加したもの)。この2つをタブページによって表示の切り替えを行います。

先ほどと同様に.NetStandardのプロジェクトを右クリックし、「追加」→「新しいファイルを作成」を選択します。 左メニューからFormsを選択し、その中の「TabbedPage XAMLの追加」を選択、名前をつけて右下の新規をクリックします。

f:id:takataka430:20190907010017p:plain

作成したタブページにコードを追記して行きましょう。

<?xml version="1.0" encoding="utf-8" ?>
<TabbedPage xmlns="http://xamarin.com/schemas/2014/forms"
            xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
            x:Class="XF_TabbedPage.MyTabbedPage"
            xmlns:local="clr-namespace:XF_TabbedPage;assembly=XF_TabbedPage">
    <local:MainPage Title="FirstPage"/>
    <local:SecondPage Title="SecondPage"/>
</TabbedPage>

xmlns:local="clr-namespace:XF_TabbedPage;assembly=XF_TabbedPage"名前空間アセンブリを指定しています。
local:MainPage local:SecondPageそれぞれでタブページで表示したいページを指定しています。Titleでタブページの表示名を設定します。
MainPage SecondPageは上で作成したContentPageの名前です。)

f:id:takataka430:20191012151655g:plain

このようにタブページによってページを切り替えることができます。モバイルアプリらしくなりましたね。
是非使ってみてください。

参考:

Xamarin.Forms のタブ付きページ - Xamarin | Microsoft Docs

iOSDCに参加してきました

2019/9/5 - 9/7に開催された iOSDC2019 に参加してきました。

iosdc.jp

興味深いセッションがたくさんあってとても楽しかったです。ブログを書くまでがiOSDCなので、セッションの感想を書いていこうと思います。

普通に書くと即メモリーリーク!こんなに大変だけど、俺は Xamarin.iOS を使い続けるぜ!

www.slideshare.net Xamarin.iOSの仕組みの解説でした。Objective-Cが辛くて、楽をするためにXamarin.iOSを始めたけど、どちらにしてもObjective-Cの知識が必要なので、結局は覚えることが増えただけだったそうです・・・。ただ、Azureとの連携がやりやすいなど、扱えるようになればとても便利なので今後も楽しく使っていくとのこと。素晴らしい!

Heart of Swift(資料未公開)

Swiftは「Value Semantics」と「Protocol-Oriented Programming」という二つの概念が根幹をなしているそうです。知らなかった・・・。コレクションについてはC#だと参照型でSwiftだと値型でこれが強みになるそうです。なぜ強みになるのか、自分なりに調べてみようと思います。

iPhoneのカメラで写真撮影から現像までの技術を紐解く

iPhoneカメラのお話。カメラの歴史やレンズの話から始まり、iPhoneカメラで撮影・現像ができるアプリを作ろうという内容でした。私は普段、ソフトウェアについて勉強することが多いので、ハードウェアのお話は興味深かったです。最近はARの技術も発達してきているので、こういったことを知っておくとアプリ開発の際に役立つのではないかと思います。

すべての人のためのアクセシビリティ対応

アクセシビリティとはあらゆる人がどのような環境でもサービスにアクセスできように考慮することであり、特定の人のためのものではないそうです。例えばネットワーク環境が悪い、料理中にスマホを触れないという状況などです。iOSにはたくさんのアクセシビリティの機能があるので、少しづつアプリに追加していこうという内容でした。 アクセシビリティについても少しづつ理解を深めていこうと思います。

まとめ

様々なセッションが聞けてとても刺激になりました。できれば次回は私も発表したいなと思いました。

「JXUGC #25 最新情報アップデート&LT 大会」でLT発表してきました

8月31日に行われた「JXUGC #25 最新情報アップデート&LT 大会」にて、LTで発表を行いました。

jxug.connpass.com

今回のJXUGは昨年の12月以来の久しぶりの参加でした。せっかくなので何か発表したいと思い、LTに応募しました。
発表内容は以下の通りです。

なぜこのテーマにしたかというと、Xamarinを勉強し始めてから長い間「アプリ作りたい。でもネタがない。」という状態だったのですが、一応アプリを作れたので、こんなの作った!と発表したかったからです。シンプルなアプリなのですが、思いの外苦労することも多かったのでその知見を共有するという目的もありました。

思えば一年前のJXUG(初心者歓迎XamarinのLT会!Xamarin入門者の集い #4)でLTをした時に、「オリジナルアプリを作ることが今後の目標」と言いました。今回の発表でその目標は達成できたのかーと思います。

今後も勉強続けてネタを見つけて発表したいと思います。聞いていただいた皆さん、ありがとうございました。

Write Code Every Dayを始めてみた

「Write Code Every Day」とは文字通り毎日コードを書こうという試みです。

【参考】 Write Code Every Day - Speaker Deck

自分もやってみたいと思ったので始めてみました。 なぜ始めたかというと、プライベートでもコードを書く習慣を身に付けたいと思ったからです。

しかし、私は毎日何かをやるのが苦手な人です。そこで自分流のルールを考えてみました。意識したのは、完全に止めてしまわないように、とにかくハードルを下げることです。

その1:意味のないコードでもOKとする

例えばコメントで何か書くとか、不要なコードを削るとか、そういうのでもOKとしました。その方が毎日気軽な気持ちでやる気になれます。

その2:続かなくてもあまり気にしない

仮に忙しかったり寝てしまったりしてその日にコードを書けなかったとしても「しょうがない、次から頑張ろう」とすぐに切り替えるようにしています。変に気にしても落ち込んでしまうので・・・

その3:進捗を見てうっとりする

これが一番重要かもしれません。「おお、できてるじゃん!!」と自分の進捗を見ることで次の日もやろうと思えます。

効果は?

毎日コードを書く、というのは残念ながらまだできていません。しかし、始める前に比べると家でコードを書く頻度は明らかに増えました。

実際の進捗

以下のような感じです。(始めたのは今年の7月です)

f:id:takataka430:20190819224258p:plain

書いてない日も結構多いですが・・・始める前に比べて明らかに頻度が増えていますね。 今後は毎日書いてプッシュするようになりたいです。

というわけで、こんな感じでコツコツ続けていきたいと思います。

Swift愛好会の開発合宿に参加してきました

2019/7/6 - 7/7にSwift愛好会とKotlin愛好会合同の開発合宿が開催されました。

love-swift.connpass.com

love-kotlin.connpass.com

前々からSwiftを使ったモバイルアプリ開発をやりたいと思っていたのですが、家では誘惑が多く、勉強が進まなかったので「自分を追い込もう!!」と思って参加しました。

場所

土善旅館

www.dozenryokan.com

こちらの旅館は開発合宿プランというのがあって、宿泊部屋とは別に開発部屋が用意されます。設備に関しても各自が利用するモニターや、LTを行うためのプロジェクターもあり、とても充実していました。机上にある電源タップは差込口が回転する大変便利なものだったのもよかったです。あと、人をダメにするクッションがあるので寝ながら開発することもできました笑

f:id:takataka430:20190707233310j:plain:w300
電源タップ

合宿の内容

まず到着したら各自が自己紹介、その後各々開発を行います。どんなことをやるかは自分で決めていいので自分のペースで進められます。
合宿の最後に談義というものがあります。これは時間制限が特に設定されていないLTのようなもので、ここで合宿の成果を発表しました。

開発中はお酒とお菓子が出ました。最高の環境でした・・・。

f:id:takataka430:20190707234434j:plain
飲みながら開発!

合宿での個人目標

今回の合宿の私の目標は「SwiftでTodoアプリを作成すること」でした。普段はXamarinを使っているので、Swiftは初心者です。まずはTodoアプリを作ってみようと思いました。
iPhoneアプリを作っている過程で「Kotlinも使いたいなあ」と思ったので、Kotlinを使ったAndroidアプリでHello, World的なこともやってみました。

今回の合宿で最初の一歩を踏み出せたので、今後はオリジナルアプリの開発をしていきたいです!!

まとめ

二日間でSwift、Kotlinの両方を使うことができ、とても勉強になりました。Xamarinだけでなく、今後はネイティブの勉強をやっていこうと思います。
あとはただ勉強するのではなく、「こんなものを作りたい」と思うアプリを作ることを目的にする方が知識が身につきやすいことを合宿で実感したので、まずは何を作りたいかを考えるようにしたいと思います。

とても楽しかったので次回も参加したいです!

【Xamarin.Forms】CheckBoxをListView内で利用して複数選択する(実装編)

前回の記事では複数選択する方法を書きました。

takataka430.hatenablog.com

今回の記事ではチェックを入れた要素を削除する機能を実装してみたいと思います。

*この記事内での「編集モード」はチェックボックスと削除ボタンが表示されている状態を意味します。

コード

画面(MainPage.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:CheckBox" 
             x:Class="CheckBox.MainPage">
    <StackLayout>
        <StackLayout Orientation="Horizontal">
            <!-- チェックした要素を削除するボタン -->
            <Button x:Name="DeleteButton"
                    Text="削除"
                    Clicked="Delete_clicked"
                    TextColor="Red"
                    IsVisible="false"/>
            <!-- 削除ボタンとCheckBoxを非表示にする -->
            <Button x:Name="BackButton"
                    Text="戻る"
                    Clicked="Back_clicked"
                    IsVisible="false"/>
            <!-- 削除ボタンとCheckBoxを表示する -->
            <Button x:Name="EditButton"
                    Text="編集"
                    Clicked="Handle_Clicked"
                    HorizontalOptions="EndAndExpand"/>
        </StackLayout>
        
        <ListView x:Name="list">
            <ListView.ItemTemplate>
                <DataTemplate>
                    <ViewCell>
                        <Grid>
                            <!-- 2行1列のグリッドを作成 -->
                            <Grid.ColumnDefinitions>
                                <!-- チェックボックスを表示する領域 -->
                                <ColumnDefinition Width="30"/>
                                <ColumnDefinition Width="*"/>
                            </Grid.ColumnDefinitions>
                            <CheckBox IsChecked="{Binding IsChecked}"
                                      IsVisible="{Binding EditMode}"
                                      Grid.Column="0"/>
                            <Label Text="{Binding Name}"
                                   Grid.Column="1"
                                   VerticalOptions="Center"/>
                        </Grid>
                    </ViewCell>
                </DataTemplate>
            </ListView.ItemTemplate>
        </ListView>
    </StackLayout>
</ContentPage>

  

コードビハインド(MainPage.Xaml.cs)

using System;
using System.Collections.ObjectModel;
using System.ComponentModel;
using Xamarin.Forms;

namespace CheckBox
{
    // Learn more about making custom code visible in the Xamarin.Forms previewer
    // by visiting https://aka.ms/xamarinforms-previewer
    [DesignTimeVisible(true)]
    public partial class MainPage : ContentPage
    {
        //編集モードかどうかの状態を保持
        private bool IsEditMode = false;

        //ListView表示用のコレクション
        private ObservableCollection<Person> person = new ObservableCollection<Person>
        {
            new Person{Name = "A"},
            new Person{Name = "B"},
            new Person{Name = "C"},
            new Person{Name = "D"},
            new Person{Name = "E"},
        };

        public MainPage()
        {
            InitializeComponent();

            //ListViewの要素を指定
            list.ItemsSource = person;
        }

        void Handle_Clicked(object sender, EventArgs e)
        {
            ChangeMode();
        }

        //チェックしたListViewの要素を削除
        private async void Delete_clicked(object sender, EventArgs e)
        {
            bool isDelete = await DisplayAlert("削除の確認", "選択した項目を削除してよいですか?", "削除する", "キャンセル");
            if (isDelete)
            {
                var itemNumber = person.Count;

                //personコレクションと中身が同じコレクションを新たに作成
                var itemCollection = new ObservableCollection<Person>(person);

                //チェックが入っている要素を削除 
                for (int i = 0; i < itemNumber; i++)
                {
                    var item = itemCollection[i];
                    if (item.IsChecked)
                    {
                        person.Remove(item);
                    }
                }
            }
        }
        
        private void Back_clicked(object sender, EventArgs e)
        {
            ChangeMode();
        }

        //編集モードの切り替えのためのメソッド
        private void ChangeMode()
        {
            IsEditMode = !IsEditMode;
            DeleteButton.IsVisible = IsEditMode;
            BackButton.IsVisible = IsEditMode;
            EditButton.IsVisible = !IsEditMode;

            foreach (var a in person)
            {
                a.EditMode = IsEditMode;

                if (!IsEditMode)
                {
                    a.IsChecked = false;
                }
            }
        }
    }

    //変更通知がいくようにしないとObservableCollectionの要素内のプロパティが変更されても画面に反映されない
    public class Person : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;

        private string name;
        public string Name
        {
            get { return this.name; }
            set
            {
                if (name != value)
                {
                    this.name = value;
                    PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Name)));
                }
            }
        }

        private bool isChecked;
        public bool IsChecked
        {
            get { return this.isChecked; }
            set
            {
                if (isChecked != value)
                {
                    this.isChecked = value;
                    PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(IsChecked)));
                }
            }
        }

        private bool editMode;
        public bool EditMode
        {
            get { return this.editMode; }
            set
            {
                if (editMode != value)
                {
                    this.editMode = value;
                    PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(EditMode)));
                }
            }
        }
    }
}

では動きを見てましょう。

f:id:takataka430:20190704232629g:plain:w200

うまく動きました!

実装の失敗例

しかし、削除機能を実装するのに結構苦労しました・・・。何かの参考になるかと思い、失敗した実例をご紹介したいと思います。(Delete_clickedイベントの「チェックが入っている要素を削除 」というコメントがある所の処理です)

失敗1

「繰り返しだからforeachだろう」と思って以下のようなコードにしてみました。

foreach (var item in person)
{
      if (item.IsChecked)
      {
          person.Remove(item);
      }
}

これだとエラーになります。調べてみると、どうやらforeach内でコレクションの追加、削除などはできないようです。こういった処理をしたい場合はfor文を使うといいみたいです。

失敗2

for文を利用して以下のように実装してみました。

for (int i = 0; i < person.Count; i++)
{
       var item = person[i];
       if (item.IsChecked)
       {
           person.Remove(item);
       }
}

これはうまく動くこともありますが、動きが変になります。例えば全ての要素にチェックを入れて削除しようとしても中途半端に残ってしまいます。

これはfor文の中でコレクションの要素の数が変わってしまうためです。person.Countは削除するたびに減少しますし、person[i]は意図した要素が選択されません。これを解決するため、上のコードではpersonと全く同じ別のコレクションを作成しました。
ところでこの方法であってるんでしょうか・・・?あまり自信がないので、修正点あったら教えてください。

  
以上、一例として削除機能を実装してみました。是非皆さんも使ってみてくださいね。それでは!