SIN@SAPPOROWORKSの覚書

C#を中心に、夜な夜な試行錯誤したコードの記録です。

Xamarin.Forms Mobile AppでToDoアプリを作成する(その1)

【 Xamarin 記事一覧 】

1. モバイルサービスからMobile Appsへ

f:id:furuya02:20150425084643p:plain:w200:leftf:id:furuya02:20150425084642p:plain:w200:leftMicrosoft Azureの新ポータル(2015年4月28日時点でPREVIEW版)では、従来の「モバイルサービス」が「Mobile Apps」となっています。

今回は、ちょっと気が早い?かも知れませんが・・・
新ポータルの綺麗な画面に誘われて、Xamarin.Formsで使ってみました。

現(PREVIEW)時点で・・・
・「モバイルサービス」で作成したものは、Mobile Appsから見えません・・・
・「モバイルサービス」では、サーバ側の処理をnodejsと.NETの2種類から選択できましたが、「Mobile Apps」では、.NETのみです。
・一応、モバイルサービスも残るみたいです。
「Mobile Services continue to be available as a standalone service and remain fully supported.」
http://azure.microsoft.com/en-us/documentation/articles/app-service-changes-existing-services/


2. Mobile Appの作成

以下、Mobile Appを作成する手順です。
(1)新ポータルでは、すべてのサービスは左下の(+新規)から行います。
f:id:furuya02:20150425084702p:plain:w450
(2)展開したウインドウから「Web + Mobile」>「Mobile App」と選択し「Name」の所にサービス名(ここでは「AzureToDoSample」とした)を入力します。
f:id:furuya02:20150425084716p:plain:w450
(3)続いてデータベースの設定を行います。
「PACKAGE SETTING」>「USERDATABASE」>「新しいデータベースの作成」を選択します。
ここで、「新しいデータベースの作成」ではなく「既存のデータベースの使用」を選択した場合、この先のDB関連の指定は必要なくなります。
f:id:furuya02:20150425084752p:plain:w450
(4)「名前」の所にデータベースの名前を入力し、「サーバー名」「サーバ管理者ログイン」「パスワード」を入力して「OK」「OK」で閉じていきます。
f:id:furuya02:20150425084802p:plain:w450
(5)設定が終わったら「作成」ボタンを押します。
f:id:furuya02:20150425084814p:plain:w450
(6)作成中の表示が出ますので、しばらく待ちます。(1分ぐらい?)
f:id:furuya02:20150425084822p:plain:w450
(7)出来上がると、作成したサービスを設定する画面になります。
ここで、「Add Client」を選択します。
f:id:furuya02:20150425084831p:plain:w450
(8)「Xamarin.Android」を選択し、「CREATE A NEW APP」で「DOWNLOAD」を押してひな形となるテンプレートをダウンロードします。
実は、Xamarin.Formsでプログラムを書く場合、テンプレートから使用するのは、サーバ側のMVCプロジェクトだけなので、「Windows(C#)」でも「Xamarin.iOS」でも、何をダウンロードしても関係ありませんw
f:id:furuya02:20150425084842p:plain:w450
(9)ダウンロードした、テンプレートは次のようになっています。
f:id:furuya02:20150425084853p:plain

3. Xamarin.Formsプロジェクトの作成

(1)VisualStudioで開いてみると、Xamarin.Android用のプロジェクト「AzureToDoSample」と、サーバ側のMVCプロジェクト「AzureToDoSampleService」の2つが含まれているのを確認することができます。
f:id:furuya02:20150425084908p:plain
(2)Xamarin.Android用のプロジェクトは要らないので、ばっさり削除します。
※実はXamarin.Android用のコードは、Xamarin.Formsでも利用可能なものが多いので、適当にフォルダ名を変えて置いておくと、色々吉です。
f:id:furuya02:20150425084913p:plain:w450
(3)続いて、このソリューションにXamarinFormsのプロジェクトを追加します。
ここでは、プロジェクト名を「AzureToDoSample」としました。
f:id:furuya02:20150425084924p:plain:w450
(4)プロジェクトの追加後、ソリューションに5つのプロジェクトが確認できます。(追加されたのは4つ)
AzureToDoSample(移植可能) : クラアントPCLプロジェクト
AzureToDoSample.Droid :Androidクラアントプロジェクト
AzureToDoSample.iOS :iOSクラアントプロジェクト
AzureToDoSample.WinPhone :WindowsPhone クラアントプロジェクト
AzureToDoSampleService :サーバ用MVCプロジェクト(これは、削除しないで残ったテンプレートのプロジェクト)
f:id:furuya02:20150425084932p:plain:w450

4. サーバ側MVCプロジェクトのコンパイルと登録

当初、サーバ側の構築を行います。
(1)コンパイルの後、ソリューションエクスプローラMVCプロジェクト「AzureToDoSampleService」を右クリックして「登録」を選択します。
f:id:furuya02:20150425085002p:plain:w450
(2)「Microsoft Azure Websites」を選択します。
f:id:furuya02:20150425085012p:plain:w450
(3)「既存のWebサイト」で、作成したサービスが選択できます。
サーバから検索するためには、Microsoftアカウントにサイインしている必要があります。
f:id:furuya02:20150425085020p:plain:w450
(4)「サーバー」「ユーザ名」「パスワード」など、全てがインポートされるので「発行」ボタンを押すだけです。
f:id:furuya02:20150425085027p:plain:w450


すいません、まだXamarin.Forms書いてませんが・・・
つづく・・・

5. 参考にさせて頂いたページ

Azure Mobile Apps と Mobile Services の違いについて - nnasakiのブログ
Azure App Service | ブチザッキ



【 Xamarin 記事一覧 】

Xamarin.Forms ローカルデータベース(SQLite)の利用

【 Xamarin 記事一覧 】

1. ローカルデータベース

Xamarin.Formsでは、SQLite.Netを使用することで、簡単にローカルのSQLiteデータベースが利用可能です。
今回は、このSQLite.NetをPCLで実装する方法について紹介します。

PCLで、このSQLite.Netを利用する場合、プラットフォーム固有の部分(最初の初期化)だけを、DependencyServiceで記述し、それ以外をPCLで実装する形になります。

※プラットフォーム固有の部分とは、主にデータファイルの場所を取得するあたりです。
※Xamarinのページでは、「Portable」と「Sharde」の2種類の実装方法が紹介されています。


2. NuGetパッケージのインストール

SQLite.NetはNuGetパッケージで簡単に利用が可能になっています。
「NuGet パッケージの管理」で 'SQLite.Net.PCL' で検索できます。
f:id:furuya02:20150427153746p:plain
f:id:furuya02:20150427153809p:plain

最初、うまく「SQLite.Net.Platform.Xamarin(Pratform)」が入らないな・・・と試行錯誤していたら、急にうまく行くようになって、よく見たら最終発行日が昨日になっていたw(途中で更新されたのですね)

f:id:furuya02:20150427153841p:plain
f:id:furuya02:20150427153853p:plain
f:id:furuya02:20150427153902p:plain
f:id:furuya02:20150427153909p:plain

※WindowsPhoneの場合は、'SQLite.Net-PCL'の他に依存関係から'sqlite-net-wp8 3.8.5'もインストールされます。

3. インターフェースの定義

プラットフォーム固有の部分をDependencyServiceで記述するためのインターフェースを定義します。
PCLプロジェクトにISQLite.csを追加しました。
これは、SQLiteを初期化して、SQLiteConnectionのインスタンスを取得するものです。

//ISQLite.cs
using SQLite.Net;
namespace SQLiteSample{
    public interface ISQLite{
        SQLiteConnection GetConnection();
    }
}

なお、このインターフェースの利用例は、次のようになります。

db = DependencyService.Get<ISQLite> ().GetConnection ();
db.CreateTable<T>();

4. 各プラットフォームの実装

DependencyService用に定義されたインターフェースを各プラットフォームで実装します。

iOS

iOSプロジェクトにSQLite_iOS.csを追加しました。

using System;
using System.IO;
using SQLite.Net;
using SQLite.Net.Platform.XamarinIOS;
using SQLiteSample.iOS;
using Xamarin.Forms;
[assembly: Dependency(typeof(SQLite_iOS))]
namespace SQLiteSample.iOS{
    public class SQLite_iOS : ISQLite{
        public SQLiteConnection GetConnection(){
            const string sqliteFilename = "TodoSQLite.db3"; //データベース名
            var documentsPath = Environment.GetFolderPath(Environment.SpecialFolder.Personal); //Documentsフ

ォルダ
            var libraryPath = Path.Combine(documentsPath, "..", "Library"); // ライブラリフォルダ
            var path = Path.Combine(libraryPath, sqliteFilename);//DBファイルのパス
            var plat = new SQLitePlatformIOS();
            var conn = new SQLiteConnection(plat, path);
            return conn;
        }
    }
}

Android

AndroidプロジェクトにSQLite_Droid.csを追加しました。

using System.IO;
using SQLiteSample.Droid;
using Xamarin.Forms;
[assembly: Dependency(typeof(SQLite_Android))]
namespace SQLiteSample.Droid{
    public class SQLite_Android : ISQLite{
        public SQLite.Net.SQLiteConnection GetConnection() {
            const string sqliteFilename = "TodoSQLite.db3"; //データベース名
            var documentsPath = System.Environment.GetFolderPath

(System.Environment.SpecialFolder.Personal);//Documentsフォルダ
            var path = Path.Combine(documentsPath, sqliteFilename);//DBファイルのパス
            var plat = new SQLite.Net.Platform.XamarinAndroid.SQLitePlatformAndroid();
            var conn = new SQLite.Net.SQLiteConnection(plat, path);
            return conn;
        }
    }
}

WindowsPhone

WindowsPhoneプロジェクトにSQLite_WinPhone.csを追加しました。

using System.IO;
using Windows.Storage;
using SQLite.Net;
using SQLite.Net.Platform.WindowsPhone8;
using SQLiteSample.WinPhone;
using Xamarin.Forms;
[assembly: Dependency(typeof(SQLite_WinPhone))]
namespace SQLiteSample.WinPhone {
    public class SQLite_WinPhone : ISQLite{
        public SQLiteConnection GetConnection(){
            const string sqliteFilename = "TodoSQLite.db3";//データベース名
            var path = Path.Combine(ApplicationData.Current.LocalFolder.Path, sqliteFilename);//DBファイルの

パス
            var plat = new SQLitePlatformWP8();
            var conn = new SQLiteConnection(plat, path);
            return conn;
        }
    }
}

5. データクラスとデータベースへのアクセスクラスの作成

データクラス

本サンプルのデータクラスとして、PCLプロジェクトにTodoItem.csを追加しました。

キーとなるIDのほかに、文字列を保存するText、作成日時のCreatedAt、そして、削除状態を表現するDeleteです。

using System;
using SQLite.Net.Attributes;

namespace SQLiteSample{
    public class TodoItem{
        [PrimaryKey, AutoIncrement]
        public int ID { get; set; }
        public string Text { get; set; }
        public DateTime CreatedAt { get; set; }//作成日時
        public bool Delete { get; set; }//削除フラグ(trueの時、表示しない)
    }
}

データベースへのアクセスクラス

データベースへのアクセスのための、PCLにTodoRepository.csを定義します。
実装したのは、一覧取得と、データの追加・更新だけです。

using System.Collections.Generic;
using SQLite.Net;
using Xamarin.Forms;

namespace SQLiteSample{
    class TodoRepository{
        static readonly object Locker = new object();
        readonly SQLiteConnection _db;

        public TodoRepository(){
			_db = DependencyService.Get<ISQLite> ().GetConnection ();//データベース接続
			_db.CreateTable<TodoItem>();//テーブル作成
		}
        //一覧
        public IEnumerable<TodoItem> GetItems(){
            lock (Locker){
                
                //Delete==falseの一覧を取得する(削除フラグが立っているものは対象外)
                return _db.Table<TodoItem>().Where(m => m.Delete == false);
            }
        }
        //更新・追加
        public int SaveItem(TodoItem item){
            lock (Locker){
                if (item.ID != 0){//IDが0で無い場合は、更新
                    _db.Update(item);
                    return item.ID;
                }
                return _db.Insert(item);//追加
            }
        }
    }
}

6. 画面実装とデータベースの利用

以上で、段取りは整ったので、画面とDBアクセスを実装します。
Addボタンで追加、リストのタップで削除になってます。

using System;
using Xamarin.Forms;
namespace SQLiteSample{
    public class App : Application{
        public App(){
            MainPage = new MyPage();
        }
        protected override void OnStart(){}
        protected override void OnSleep(){}
        protected override void OnResume(){}
    }
    class MyPage : ContentPage{

        readonly TodoRepository _db = new TodoRepository();

        public MyPage(){
            
            //データ表示用リストボックス
            var listView = new ListView{
                ItemsSource = _db.GetItems(),
                ItemTemplate = new DataTemplate(typeof(TextCell))
            };
            listView.ItemTemplate.SetBinding(TextCell.TextProperty, "Text");
            listView.ItemTemplate.SetBinding(TextCell.DetailProperty, new Binding("CreatedAt", stringFormat: 

"{0:yyy/MM/dd hh:mm}"));
            listView.ItemTapped += async (s, a) =>{//リストがタップされた時の処理
                var item = (TodoItem)a.Item;
                if (await DisplayAlert("削除してい宜しいですか", item.Text, "OK", "キャンセル")){
                    item.Delete = true;//削除フラグを有効にして
                    _db.SaveItem(item);//DB更新
                    listView.ItemsSource = _db.GetItems();//リスト更新
                }
            };
            //文字列入力
            var entry = new Entry{
                HorizontalOptions = LayoutOptions.FillAndExpand
            };
            //追加ボタン
            var buttonAdd = new Button{
                WidthRequest = 60,
                TextColor = Color.White,
                Text = "Add"
            };
            buttonAdd.Clicked += (s, a) =>{//追加ボタンが押された時の処理
                if (!String.IsNullOrEmpty(entry.Text)){//Entryに文字列が入力されている場合に処理する
                    var item = new TodoItem { Text = entry.Text, CreatedAt = DateTime.Now, Delete = false };
                    _db.SaveItem(item);
                    listView.ItemsSource = _db.GetItems();//リスト更新
                    entry.Text = "";
                }
            };

            Content = new StackLayout{
                Padding = new Thickness(0, Device.OnPlatform(20, 0, 0), 0, 0),
                Children = {
                    new StackLayout {
                        BackgroundColor = Color.Navy,//入力部の背景色はネイビー
                        Padding = 5,
                        Orientation = StackOrientation.Horizontal,
                        Children = {entry, buttonAdd}//Entryコントロールとボタンコントロールを横に並べる
                    },
                    listView//その下にリストボックスを置く
                }
            };
        }

    }
}

実行画面は次のとおりです。

f:id:furuya02:20150427154000p:plain:w200 f:id:furuya02:20150427154011p:plain:w200
f:id:furuya02:20150427154021p:plain:w200 f:id:furuya02:20150427154034p:plain:w200
f:id:furuya02:20150427154045p:plain:w200 f:id:furuya02:20150427154054p:plain:w200

7. WindowsPhoneの場合

以上で、Xamarin.FormsからSQLite.Netを利用する手順は終了なのですが・・・
WindowsPhoneは、デフォルトでSQLite自体がインストールされていないので、初めてのSQLiteを使用する場合は、このライブラリ自体をインストールする必要があります。そして、アプリ作成時は、このライブラリを参照に追加することになります。

以下、手順を追って説明します。

(1)ダウンロード

http://www.sqlite.org/download.html#wp8から、WindowsPhone8用のものをダウンロードします。
f:id:furuya02:20150427154449p:plain

(2)インストール

ダウンロードした、vsixファイルを実行して、インストールします。
f:id:furuya02:20150427154440p:plain

(3)VisualStudio再起動

参照の一覧に表示するためにVisualStudioの再起動が必要です。

(4)参照追加

WindowsPhoneプロジェクトの参照の追加で「SQLite for Windows Phone」を追加します。
f:id:furuya02:20150427154458p:plain
f:id:furuya02:20150427154510p:plain

8. 参考にさせて頂いたページ

Xamarin.AndroidでSQLiteを使う - かずきのBlog@hatena
Working with a Local Database - Xamarin


↓サンプルはここに置きました。github.com



【 Xamarin 記事一覧 】

Xamarin.Forms 画面のサイズを取得する

【 Xamarin 記事一覧 】

コンストラクタでは、サイズが取得できない

次のようなコードを書くと、もれなくサイズの取得に失敗します。
単純にContentPageのサイズ(WidthとHeight)を表示しているだけですが、綺麗に-1になってしまっています。

using Xamarin.Forms;
namespace App1{
    public class App : Application{

        public App(){
            MainPage = new MyPage();
        }
        protected override void OnStart(){}
        protected override void OnSleep(){}
        protected override void OnResume(){}
    }

    class MyPage : ContentPage {

        public MyPage() {
            Content = new Label{ //ラベル1つ配置する
                HorizontalOptions = LayoutOptions.Center,//左右中央に配置
                VerticalOptions = LayoutOptions.Center,//上下中央に配置
                Text = string.Format("Width={0} Height={1}", Width, Height) //ContentPage.Width,ContentPage.Heightプロパティを表示する
            };
        }
    }
}

Android iOS WindowsPhone
f:id:furuya02:20150425053553p:plain:w200 f:id:furuya02:20150425053550p:plain:w200 f:id:furuya02:20150425053552p:plain:w200
-1 * -1 -1 * -1 -1 * -1

OnSizeAllocated

解決方法の1つとして、ContentPageのサイズが取得できてから、使用するという方法があります。
Width,Heightプロパティの値が変化した時点で、OnSizeAllocatedメソッドが呼ばれるので、これをオーバライドする方法です。
まー、この例の場合は、プロパティ値をバインディングした方が手っ取り早いですが・・・

using Xamarin.Forms;
namespace App1{
    public class App : Application{

        public App(){
            MainPage = new MyPage();
        }
        protected override void OnStart(){}
        protected override void OnSleep(){}
        protected override void OnResume(){}
    }

    class MyPage : ContentPage {

        private Label _label = new Label() { //クラス変数とする
            HorizontalOptions = LayoutOptions.Center,//左右中央に配置
            VerticalOptions = LayoutOptions.Center,//上下中央に配置
        };

        public MyPage() {
            Content = _label; //ラベル1つ配置する
        }

        protected override void OnSizeAllocated(double width, double height) {
            base.OnSizeAllocated(width, height);

            label.Text = string.Format("Width={0} Height={1}", Width, Height);//ContentPage.Width,ContentPage.Heightプロパティを表示する
        }
    }
}

下のように、サイズが表示されているのが確認できます。

Android iOS WindowsPhone
f:id:furuya02:20150425053811p:plain:w200 f:id:furuya02:20150425053812p:plain:w200 f:id:furuya02:20150425053814p:plain:w200
320 * 496 320 * 568 480 * 768


コンストラクタの前にサイズを確保する

どうしても、コンストラクタの時点でサイズが欲しい場合・・・
それは、もうAppクラスがインスタンス化される前に、確保するしかありません。

思い切って、Appクラスのコンストラクタを引数ありにして、ディスプレイのサイズを取得するように変更します。

※ここで、ターゲットがContentPageのサイズでなく、ディスプレイのサイズになっていることをご了承下さい。
ContentPageが画面いっぱいに構成されているアプリという前提です。

using Xamarin.Forms;
namespace App1{
    public class App : Application{
        public int ScreenWidth { get; private set; } //スクリーンサイズ(幅)
        public int ScreenHeight { get; private set; }//スクリーンサイズ(高さ)

        public App(int w,int h){
            // パラメータで初期化
            ScreenHeight = h;
            ScreenWidth = w;

            MainPage = new MyPage();
        }
        protected override void OnStart(){}
        protected override void OnSleep(){}
        protected override void OnResume(){}
    }

    class MyPage : ContentPage {

        public MyPage() {
            
            Content = new Label{
                HorizontalOptions = LayoutOptions.Center,
                VerticalOptions = LayoutOptions.Center,
                Text = string.Format("Width={0} Height={1}", ((App)Application.Current).ScreenWidth,((App)Application.Current).ScreenHeight)
            };
        }
    }
}

コンストラクタが引数ありになったので、当然、このままではコンパイルできません。
各プラットフォームで、コンストラクタを生成している部分をいじります。

Android

Androidでは、MainActivity.csを修正します。
Resources.DisplayMetrics.WidthPixels(HeightPixels)でデバイスの実サイズ(dip)を取得し、これをResources.DisplayMetrics.Densityでピクセルに変換しています。

画面サイズを取得して、これをコンストラクタの引数とします。

using Android.App;
using Android.Content.PM;
using Android.OS;
using Xamarin.Forms;
using Xamarin.Forms.Platform.Android;

namespace App1.Droid{
    [Activity(Label = "App1", Icon = "@drawable/icon", MainLauncher = true, ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation)]
    public class MainActivity : FormsApplicationActivity{
        protected override void OnCreate(Bundle bundle){
            base.OnCreate(bundle);

            Forms.Init(this, bundle);
            //スクリーンのサイズを取得する
            var w = (int)(Resources.DisplayMetrics.WidthPixels / Resources.DisplayMetrics.Density);
            var h = (int)(Resources.DisplayMetrics.HeightPixels / Resources.DisplayMetrics.Density);

            
            LoadApplication(new App(w,h));//スクリーンサイズをパラメータにしてAppクラスを生成する
            //LoadApplication(new App());//引数なしはエラーとなる
        }
    }
}

iOS

iOSでは、AppDelegate.csを修正します。
UIScreen.MainScreen.Bounds.Width(Height)で画面サイズを取得して、これをコンストラクタの引数とします。

using Foundation;
using UIKit;

namespace App1.iOS{

    [Register("AppDelegate")]
    public partial class AppDelegate : global::Xamarin.Forms.Platform.iOS.FormsApplicationDelegate{
        public override bool FinishedLaunching(UIApplication app, NSDictionary options){
            global::Xamarin.Forms.Forms.Init();

            //スクリーンのサイズを取得する
            var w = (int)UIScreen.MainScreen.Bounds.Width;
            var h = (int)UIScreen.MainScreen.Bounds.Height;

            LoadApplication(new App(w,h));//スクリーンサイズをパラメータにしてAppクラスを生成する
            //LoadApplication(new App()); //引数なしはエラーとなる
            return base.FinishedLaunching(app, options);
        }
    }
}

WindowsPhone

WindowsPhoneでは、MainPage.xaml.csを修正します。
Application.Current.Host.Content.ActualWidth(ActualHeight)で画面サイズを取得して、これをコンストラクタの引数とします。


using Microsoft.Phone.Controls;
using Xamarin.Forms;
using Xamarin.Forms.Platform.WinPhone;
using Application = System.Windows.Application;

namespace App1.WinPhone{
    public partial class MainPage : FormsApplicationPage{
        public MainPage(){
            InitializeComponent();
            SupportedOrientations = SupportedPageOrientation.PortraitOrLandscape;
            Forms.Init();
            
            //スクリーンのサイズを取得する
            var w = (int)Application.Current.Host.Content.ActualWidth;
            var h = (int)Application.Current.Host.Content.ActualHeight; 
            LoadApplication(new App1.App(w,h));//スクリーンサイズをパラメータにしてAppクラスを生成する
            //LoadApplication(new App1.App());//引数なしはエラーとなる
        }
    }
}


下のように、サイズが表示されているのが確認できます。
ただし、AndroidとWindowsPhoneでは、高さが微妙に違うので注意が必要です。
対象としている領域が違うのが原因です。

Android iOS WindowsPhone
f:id:furuya02:20150425054040p:plain:w200 f:id:furuya02:20150425053812p:plain:w200 f:id:furuya02:20150425054041p:plain:w200
320 * 521 320 * 568 480 * 800



【 Xamarin 記事一覧 】

Xamarin.Forms MasterBehaviorについて

【 Xamarin 記事一覧 】

MasterBehavior

MasterBehaviorとは、Xamarin.Forms 1.3で、MasterDetailPageに新しく追加されたプロパティです。

f:id:furuya02:20150422012224p:plain

このプロパティは、列挙型になっており、Masterページ(通常メニュー的に左側に表示されるビュー)の隠れ具合を制御しています。
f:id:furuya02:20150422012250p:plain

  • Split  常時表示
  • f:id:furuya02:20150422012255p:plain
  • Popover 隠れる
  • f:id:furuya02:20150422012300p:plain
  • SplitOnPortrait 縦の時、常時表示
  • f:id:furuya02:20150422012304p:plain
  • SplitOnLandscape 横の時、常時表示
  • f:id:furuya02:20150422012308p:plain
  • Default(SplitOnLandscapeと同じ)
  • f:id:furuya02:20150422012312p:plain

なお、このオプションは、iPadなど大きなディスプレイの端末の時だけ機能し、iPhoneの場合は、常に隠れる動作(MasterBehavior.Popoverと同等)となります。
また、Ver1.3では、ちょっとバグがあるような記載があったのVer1.4で動作確認しました。

PM> Get-Package
Id                             Version              Description/Release Notes                                
--                             -------              -------------------------                                
WPtoolkit                      4.2013.08.16         Windows Phone toolkit provides ...
Xamarin.Android.Support.v4     19.0.2               C# bindings for android support library v4.
Xamarin.Forms                  1.4.2.6355           Build native UIs for iOS, Android, and Windows Phone ..

動作

Popover

メニューが隠れる動作は、つぎのような感じです。
f:id:furuya02:20150422012318g:plain

Slpit

メニューが常時表示する動作は、つぎのような感じです。
f:id:furuya02:20150422012336g:plain

コード

使用したコードを参考までに

using System;
using System.Linq;
using Xamarin.Forms;

namespace App1{
    public class App : Application{
        public App(){
            MainPage = new MyPage();
        }

        protected override void OnStart(){}

        protected override void OnSleep(){}

        protected override void OnResume(){}
    }

    class MyPage : MasterDetailPage{
        public MyPage() {

            MasterBehavior = MasterBehavior.Split;
            
            var ar = Enumerable.Range(0, 20).Select(n => "Items-" + n).ToList();
            var listView = new ListView {
                ItemsSource = ar,
                BackgroundColor = Color.Transparent,
            };
            listView.ItemSelected += (s, a) => SetDetailPage(a.SelectedItem.ToString());

            Master = new ContentPage{
                BackgroundColor = Color.Teal,
                Title = "TEST",//Maserページでは、Titleが設定されていないと動作できない
                Padding = new Thickness(0, Device.OnPlatform(20, 0, 0), 0, 0),
                Content = listView,
            };
            SetDetailPage(ar[0]);
        }

        void SetDetailPage(string title) {
            Detail = new NavigationPage(new DetailPage(title)){
                BarBackgroundColor = Color.Silver,//上部の背景色
            };
            try{ //MasterBehavior.Split等でIsPresentedをfalseにしようとすると例外となる
                IsPresented = false;
            }catch (Exception ex) {
                DisplayAlert("Exception",ex.Message, "OK");
            }
        }
    }

    class DetailPage : ContentPage{
        public DetailPage(string title){
            Content = new Label{
                Text = title,
                HorizontalOptions = LayoutOptions.Center,
                VerticalOptions = LayoutOptions.Center
            };
        }
    }
}

【 Xamarin 記事一覧 】

Xamarin.Forms Ver1.3以降の機能について

【 Xamarin 記事一覧 】

Ver1.3以降の機能を利用したサンプルアプリ

先日、「第4回 JXUG Conference with dotNetConf 2015 Japan」でお話させて頂いた時の資料です。

昨年末アップデートされた Xamarin 1.3と最近の1.4で利用可能になった新機能を利用して、Twitterクライアント風のアプリを作成してみたので、その説明です。

f:id:furuya02:20150419045039j:plain

以下は、サンプルアプリで使用してみた新機能です。

App Lifecycle OnStart,OnSleep,OnResume (1.3)
 Properties Dictionary (1.3)
Styles (1.3)
Behaviors (1.3)
Triggers (1.3)
Font (1.3)
ListView context actions (1.3)
 pull to refresh (1.4)
 headers and footers (1.4)
 row separator (1.4)
 Scroll (1.3)

ちなみに、使用している翻訳機能「Microsoft Translator 」は、WebAPIですが、言語のFromとToを指定するパラメータがあって、Toだけ指定すると、英語に限らずうまく扱ってくれるようです。

f:id:furuya02:20150419045435p:plain:w200f:id:furuya02:20150419045437p:plain:w200f:id:furuya02:20150419045434p:plain:w200

↓サンプルコードはこちらです。github.com


関係ありませんが・・・

知る人ぞ知る「日米商事」ちょっと寄ってきました。
全てのジャンルが揃うわけではありませんが、ここで見つけたら、個別売りでは恐らく最安値では無いでしょうか。
(微妙に、系列の違うものが多数あるので、分かってる人にお勧め)
f:id:furuya02:20150419051235j:plainf:id:furuya02:20150419051237j:plainf:id:furuya02:20150419051239j:plainf:id:furuya02:20150419051240j:plainf:id:furuya02:20150419051241j:plainf:id:furuya02:20150419051243j:plainf:id:furuya02:20150419051244j:plain

↓これは、別のお店ですが・・・・思わず買いそうになったアヒル隊長
f:id:furuya02:20150419051824j:plain


【 Xamarin 記事一覧 】

Xamarin.FormsでWebビューを使用するには?

【 Xamarin 記事一覧 】

BuildInsiderで連載されている「Xamarin逆引きTips」に寄稿させて頂きました。

Xamarin.FormsでWebビューを使用するには? - Build Insider

使用したコードは、下記にあります。

furuya02/XamarinTips.WebViewSample · GitHub




【 Xamarin 記事一覧 】

Xamarin.Forms 「ARC Welder」を使用してChromeブラウザで動作させて見た

【 Xamarin 記事一覧 】


ARC Welder

 昨日(2015年4月3日)、GoogleからAndroidアプリをChromeで動作させるというニュースがありました。
 ARCとは「Android Runtime for Chrome」の頭文字であり、Androidが使うAPIをラップして、ChromeブラウザまたはChrome OSで動かすランタイムとの事。まだ、ベータ版という事ですが・・・Xamarin.Formsで作成したAPKがうまく動作するかどうか試してました。
http://japanese.engadget.com/2015/04/02/google-android-chrome-arc-welder-apk/
f:id:furuya02:20150405104214p:plain

Xamarin.Formsのプロジェクト

結論から言ってしまうと、アプリのアイコンを設定して、リリースビルドすれば、証明書のあるパッケージは、問題なく動作するようです。

アイコン設定

プロジェクトテンプレートのデフォルトでは、アイコンが無いため、「ARC Welder」で「Launch App」時にエラーが発生してしまいます。
f:id:furuya02:20150405104224p:plain
ERROR: Required badging "icon" not found in package.

デバッグビルド

Xamarinのデバッグビルドは、高速化のため、「共有ランタイム(Shared Runtime)」などがリンクされていないのが原因だと思います。

証明書

証明書が無いパッケージでは、「Launch App」まで行けますが、実行時にcrashします。
f:id:furuya02:20150405104250p:plain

作業手順

それでは、実際に行った手順を順に紹介してみたいと思います。
(1)プロジェクトは、「Blank App (Xamarin.Forms Portable)」テンプレートを使用します。
f:id:furuya02:20150405104259p:plain
(2)構成マネージャで「Release」に変更します。
f:id:furuya02:20150405104304p:plain
(3)Androidプロジェクトのプロパティで、アイコンを設定します。
f:id:furuya02:20150405104309p:plain
(4)「ARC Welder」をインストールします。
https://chrome.google.com/webstore/detail/arc-welder/emfinbmielocnlhgmfkkmkngdoccbadn
f:id:furuya02:20150405104314p:plain
(5)インストールが完了すると、「chrome://extensions」で利用可能になります。
f:id:furuya02:20150405104320p:plain
(6)初回起動時に、作業ディレクトリの指定があるので、適当なフォルダを指定します。
f:id:furuya02:20150405104325p:plain:w200
(7)「Add your APK」で、Releaseビルドの証明書がある方を選択します。(App1/App1.Droid/bin/Release/App1.Droid-Signed.apk)
f:id:furuya02:20150405104332p:plain
(8)Orientationで「Portrait」、Form Factorで「Phone」を選択して「Launch App」を押します。
f:id:furuya02:20150405104339p:plain
(9)起動が確認できます。
f:id:furuya02:20150405104346p:plain
(10)「Launch App」で成功したアプリは、「拡張機能」の一覧に入り、次からは、ここから起動できます。
f:id:furuya02:20150405104351p:plain


Xamarin.Forms.Maps

試しに、Xamarin.Forms.Mapsを起動してみましたが、「Play開発者サービスの入手」をクリックするとクラッシュしましたw
f:id:furuya02:20150405104958p:plain:w200

【 Xamarin 記事一覧 】