読者です 読者をやめる 読者になる 読者になる

ComponentOne Information

ComponentOne Studio/Wijmo/Xuniの最新情報を公開中

Web APIで取得したオープンデータを一覧表示するXamarin.FormsアプリのUIを作成

Xuni

どのプラットフォームでも業務アプリに要求される機能がデータの一覧表示です。

デスクトップやWebアプリでデータを表示するデータグリッドUIを作成するコンポーネントに「FlexGrid」があります。モバイル開発用コンポーネントXuni(ズーニー)にも「FlexGrid」があります。モバイルデバイスの小さい画面でデータを一覧表示するのに適しているかどうかは別にして、データの一覧表示についてはよくお問い合わせをいただきます。

この記事では、Android、iOSアプリでシンプルにデータ一覧を表示する方法を解説します。 テストデータを表示する方法は、他の解説資料や製品のサンプルプロジェクトに含まれますので、ここではWebで公開されているオープンデータをAPIで取得し、FlexGridに一覧表示します。

AEDオープンデータ

今回は「AEDオープンデータプラットフォーム」に公開されているAEDの位置情報を利用しました。

同サービスに登録済みのオープンデータから、グレープシティの本社がある仙台市のデータを取得して一覧に表示します。

このサービスは公開されるデータにありがちなファイルフォーマットや形式の違いを吸収し、アプリなどから利用しやすいREST/JSON形式で提供されるWeb APIで取得できます。データも人間の目だけでなく、機械からも見やすくする必要があり、そこをうまく解決しています。

f:id:ComponentOne_JP:20161128084210p:plain AEDオープンデータプラットフォーム

CC BY 3.0

今回利用する仙台市のデータはこのURLでアクセスすると表示されます。
https://aed.azure-mobile.net/api/aedinfo/宮城県/仙台市/

Xamarin.Forms プロジェクトの準備

作成するアプリはシンプルなUIなので、Xamarin.FormsでUIもAndroid/iOSで共通化したものを作成します。 利用する開発環境は、Visual Studio(Windows)またはXamarin Studio(macOS)です。作成するソリューションは共通利用が可能なので、どちらの開発環境でも開くことができます。

記事スペースに限りがありますので、プロジェクト作成などの基本的な部分は他の解説をご参照ください。

www.goxuni.com

なお、提供しているサンプルプロジェクトはXuniのライセンスを設定済みですので、Xamarinの開発環境があればそのまま利用できます。

プロジェクトの作成の手順は以下です。

  1. Xamarin.Formsのソリューションを新規作成
    「AEDList」という名称にします

  2. NuGetサーバーから必要なパッケージをインストール
    Web APIからHttp通信でデータを取得するため以下をインストールします。

    • Microsoft.Net.Http
      • Microsoft.Bcl
      • Microsoft.Bcl.Build 2つのBCL関連パッケージは依存関係にもとづき自動でインストールされます。
    • Newtonsoft.json
      JSON形式のデータを扱うためJSON.NET(Newtosoft.json)を利用します。
  3. NuGetサーバーからXuniをインストール
    共通ライブラリ(PCL)、Android、iOSすべてのプロジェクトのパッケージに追加します。

PCLプロジェクト Androidプロジェクト iOSプロジェクト
Xuni.Forms.FlexGrid Xuni.Forms.FlexGrid Xuni.Forms.FlexGrid
Xuni.Forms.Core Xuni.Forms.Core Xuni.Forms.Core
Xuni.Forms.CollectionView Xuni.Forms.CollectionView Xuni.Forms.CollectionView
Xuni.Android.FlexGrid
Xuni.iOS.FlexGrid
Xuni.Android.Core
Xuni.iOS.Core

依存関係にあるパッケージは自動でインストールされます。 今回の場合、FlexGridを選択すれば依存するパッケージを別途選択する必要はありません。
上の表では太字斜体の「Xuni.Forms.FlexGrid」 以外は自動でインストールされます。

パッケージに最新版の提供がある場合は注意して更新してください。まとめて更新するのはお勧めできません。

  1. Xuniのライセンスを取得
    トライアル版を申請してライセンスキーを取得します

  2. ライセンスキーの設定
    PCLプロジェクトに取得したライセンスキーを保存し、ライセンスを認証するコードを設定

これで準備が整いました。プロジェクト構成は以下のようになります。 f:id:ComponentOne_JP:20161128095656p:plain

データモデルを作成

取得するAEDデータを扱うためのクラスを作成します。取得可能なデータを単純に列挙したものを作成します。

  1. PCLプロジェクトにAEDListModel.csを新規作成

  2. AEDListModelクラスの作成 前述のWebサイトに、AEDデータのフォーマットが記載されています。 それを転用しAEDListModelクラスを作成します。 すべてstring型の定義です。

public string Id { get; set; }                      //-- ID
public string LocationName { get; set; }            //-- 場所_地名【名称】
public string Perfecture { get; set; }              //-- 構造化住所_都道府県
public string City { get; set; }                    //-- 構造化住所_市区町村
public string AddressArea { get; set; }             //-- 構造化住所_町名
public string Latitude { get; set; }                //-- 緯度経度座標系_緯度
public string Longitude { get; set; }               //-- 緯度経度座標系_経度
public string FacilityId { get; set; }              //-- 公共設備_ID
public string FacilityName { get; set; }            //-- 公共設備_名称
public string FacilityPlace { get; set; }           //-- 公共設備_設置場所【設置場所】※受付横とか
public string ScheduleDayType { get; set; }         //-- 公共設備_利用可能時間【利用可能時間】
public string ScheduleDayStartTime { get; set; }    //--  開始時間
public string ScheduleDayEndTime { get; set; }      //--  終了時間
public string AccessAvailabilityOfPad { get; set; } //-- 公共設備_建物内外【建物内外】
public string FacilityUser { get; set; }            //-- 公共設備_利用者【利用制限】
public string FacilityNote { get; set; }            //-- 公共設備_補足【補足】
public string DayOfInstallation { get; set; }       //-- 公共設備_設置日
public string PhotoOfAedUrl { get; set; }           //-- 公共設備_写真URL【写真】
public string Url { get; set; }                     //-- 公共設備_ホームページ【ホームページ】
public string FacilityOwner { get; set; }           //-- 公共設備_設置者【設置者】
public string FacilityOperater { get; set; }        //-- 公共設備_管理者
public string ContactPoint { get; set; }            //-- 公共設備_連絡先【連絡先】
public string ContactTelephone { get; set; }        //--  連絡先_電話番号
public string ContactExtension { get; set; }        //--  連絡先_内線番号
public string TypeOfPad { get; set; }               //-- AED_パッド種類
public string ExpiryDate { get; set; }              //-- AED_有効期限
public string ExpiryDateOfPads { get; set; }        //-- AED_パッド有効期限
public string ExpiryDateOfBatteries { get; set; }   //-- AED_バッテリ有効期限
public string TypeOfDefibrillator { get; set; }     //-- AED_タイプ
public string ModelNumber { get; set; }             //-- AED_モデルナンバー
public string SerialNumber { get; set; }            //-- AED_シリアルナンバー
public string Source { get; set; }                  //-- メタデータ_情報源
public string DateOfUpdatingInformation { get; set; } //-- 更新日時

Web API からデータを取得

  1. PCLプロジェクト(AEDList)にWebData.csを新規作成

  2. データ取得用のメソッドを作成 RESTで取得できるデータなので、httpclientを作成してデータを取得します。
    取得するデータ(ここでは仙台市のデータ)のAPIを文字列で指定しています。

  3. 取得したデータをJSON.NET を利用して、デシリアライズを行い、元のデータ形式で取得します。

  4. httpのアクセスは非同期で実行するので、async/awaitを利用した記述になります。 AEDDetaModelの形式データをListとして結果を返します

using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Threading.Tasks;
using Newtonsoft.Json;

namespace AEDList
{
    public class WebData
    {
        public List<AEDListModel> AEDList;
        // 仙台のAEDデータ
        public string AED_URL = "https://aed.azure-mobile.net/api/aedinfo/%E5%AE%AE%E5%9F%8E%E7%9C%8C/%E4%BB%99%E5%8F%B0%E5%B8%82/";
        // データを取得するメソッド
        public async Task<List<AEDListModel>> AsyncGetWebAPIData()
        {
            // Listの作成
            AEDList = new List<AEDListModel>();
            // HttpClientの作成 
            HttpClient httpClient = new HttpClient();
            // 非同期でAPIからデータを取得
            Task<string> stringAsync = httpClient.GetStringAsync(AED_URL);
            string result = await stringAsync;
            // JSON形式のデータをデシリアライズ
            AEDList = JsonConvert.DeserializeObject<List<AEDListModel>>(result);

            // List でデータを返す
            return AEDList;
        }
    }
}

UIの作成

既定で作成されたページAEDListPage.xamlを改造し、一覧を表示する画面をXAMLで記述します。

名前空間の設定
FlexGridを利用するための名前空間の定義を追加します。

xmlns:flexgrid = "clr-namespace:Xuni.Forms.FlexGrid;assembly=Xuni.Forms.FlexGrid"

Paddingの設定
iOSアプリでは上部のステータスバーに表示が重なってしまうので隙間を設けます。 Deviceクラスを利用するとOSごとの値を設定可能です。

<ContentPage.Padding>
     <OnPlatform 
        x:TypeArguments="Thickness" 
        iOS ="0, 20, 0, 0" 
        Android ="0, 0, 0, 0"/>
</ContentPage.Padding>

ContentPageの記述
初期値で設置済みをLabelを削除し、FlexGridを記述します データを表示するだけなので設定もシンプルに行います。設定内容を解説します。

 AutoGenerateColumns = "true" : 接続したデータセットの情報から列を自動的に作成
 IsReadOnly = "true" : 読み取り専用  
 SelectionMode = "None" : 表示のみに限定しセルや行の選択は行わない  

記述した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:flexgrid = "clr-namespace:Xuni.Forms.FlexGrid;assembly=Xuni.Forms.FlexGrid"
    xmlns:local="clr-namespace:AEDList" 
    x:Class="AEDList.AEDListPage">

    <ContentPage.Padding>
            <OnPlatform x:TypeArguments="Thickness" 
                  iOS="0, 20, 0, 0" 
                  Android="0, 0, 0, 0"/>
    </ContentPage.Padding>

    <Grid VerticalOptions="FillAndExpand">
        <flexgrid:FlexGrid x:Name="grid" 
        AutoGenerateColumns="true" 
        IsReadOnly="true" 
        SelectionMode="None">
        </flexgrid:FlexGrid>
    </Grid>

</ContentPage>

FlexGridにデータを設定

Web APIから取得したデータをFlexGridに設定します。コードは前項で作成したXAMLのPartialクラスであるAEDListPage.csに記述します。データを取得するためのメソッドを非同期で実行するようにします。

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

namespace AEDList
{
    public partial class AEDListPage : ContentPage
    {
        public AEDListPage()
        {
            InitializeComponent();
            // データセットのインスタンスを引数にして呼び出し
            getData(new WebData());
        }
        // 非同期でデータ取得のメソッドを実行するメソッド
        async void getData(WebData webDS)
        {
            List<AEDListModel> AEDlist;
            try
            {
                // 取得したデータをListに設定
                AEDlist = await webDS.AsyncGetWebAPIData();
                // FlexGridのItemSourceにListを設定
                grid.ItemsSource = AEDlist;
            }
            // エラー表示処理
            catch (System.Exception ex)
            {
                await DisplayAlert("Error", ex.Message.ToString(), "OK");
            }

        }
    }
}

アプリの実行

ここまでの内容で、iOS(左側)Android(右側)、の各アプリを実行した結果が以下です。 AEDデータとして取得したデータが一覧形式で表示されています。

f:id:ComponentOne_JP:20161125182713p:plain

表示のカスタマイズ

ここまででシンプルなデータ一覧表示ができあがりました。次に各種設定を変更し、見た目を変更してみます。

表示対象のデータを選択

すべてのデータを表示していたので、データ種類の数だけ列が作成されました。 あらかじめ列を定義し、その列に表示するデータを接続することで表示対象データを限定することができます。

AEDListPage.xamlの内容を書き換えて列を定義するために、まずAutoGenerateColumnsFalseに変更します。これで定義した列のみ表示されるようになります。

AutoGenerateColumns="false" 

次に表示対象の列をそれぞれ定義します。列幅はスターサイズ機能を利用して"*"を表示します。

スターサイズはスター(*:アスタリスク)を指定することで、グリッド全体が表示される領域を表示する列で自動的に分割する方式です。画面を横向きにした場合にも、列幅を自動調整して表示します。例えばWidth="0.5*を指定した場合、他の列の半分の幅で対象列が表示されるように調整されます。

<flexgrid:FlexGrid.Columns>
  <flexgrid:GridColumn Binding="LocationName" Header="場所名" Width="*"/>
  <flexgrid:GridColumn Binding="Perfecture" Header="都道府県" Width="0.5*"/>
  <flexgrid:GridColumn Binding="City"  Header="市区町村" Width="0.5*"/>
  <flexgrid:GridColumn Binding="AddressArea"  Header="所在地" Width="*"/>
  <flexgrid:GridColumn Binding="FacilityPlace"  Header="設置場所" Width="*"/>
</flexgrid:FlexGrid.Columns>
行ヘッダー、グリッド線の消去

ヘッダーやグリッド線の表示を制御できます。
* GridLinesVisibility="None" : グリッド線を非表示
* HeadersVisibility="Column" :列ヘッダーのみ表示(行ヘッダーを非表示)

行の背景色を変更

データ一覧では偶数行、奇数行で色を変える表示方式をよく見かけます。AlternatingRowBackgroundColorプロパティに設定した色で奇数行が表示します。
偶数行を変更する場合は、行の背景色であるRowBackgroundColorプロパティを設定します。つまり行全体に設定した背景色で表示し、奇数行だけを変更することになります。

<flexgrid:FlexGrid x:Name="grid" 
    AutoGenerateColumns="false" 
    IsReadOnly="true" 
    SelectionMode="None"
    GridLinesVisibility="None" 
    HeadersVisibility="Column" 
    AlternatingRowBackgroundColor="#F1D7E0">
</flexgrid:FlexGrid>

これらをカスタマイズして実行した結果が以下です。データグリッド風のUIからリストビュー風のUIになったと思います。

f:id:ComponentOne_JP:20161125183025p:plain

横表示にした時にもすべての列が表示されています。

f:id:ComponentOne_JP:20161125183310p:plain

OSごとの設定変更

上図を見てお気づきと思いますが、AndroidとiOSでは異なる列幅で表示されています。これはOSやデバイスによるUI表現の差が現れているものです。
前述のXAMLのPaddingを設定した時のように、C#のコードでもAndroid、iOSを判断して異なる設定にできます。

// OSごとに設定を変更
// iOSの場合
Device.OnPlatform(iOS: () =>
  {
    // 値の同じ上下のセルを結合して表示
    // 結合の許可
    grid.AllowMerging = Xuni.Forms.FlexGrid.GridAllowMerging.Cells;
    // 都道府県名が同じの場合は結合
    grid.Columns["Perfecture"].AllowMerging = true;
  },
    // Androidの場合
    Android: () =>
    {
    // 列幅を数値で設定
    grid.Columns["Perfecture"].Width = 80;
    grid.Columns["City"].Width = 80;
    // 行の背景色を設定
    grid.RowBackgroundColor = Color.FromHex("#8e8e93");
    grid.AlternatingRowBackgroundColor = Color.FromHex("#a4c639");

});

OSごとに表示を変更した例です。わかりやすく色を変えました。実際には表示サイズや位置などの調整に利用できます。

f:id:ComponentOne_JP:20161125183756p:plain

このサンプルをベースに各種カスタマイズして、各種データ一覧を作成できます。また、APIで取得したAEDデータには今回利用しなかった項目も含まれます。それらを利用して機能を加えていくのも良いでしょう。

サンプルプロジェクトは以下で公開しています。サンプルプロジェクト用のライセンスも含まれているのでXamarinの環境でそのまま開くことができます。

ADList.zip(91.7 KB)

FlexGridのカスタマイズ手法などは、Webサイトの技術情報やナレッジベースでも解説していますのでご覧ください。

www.goxuni.com

ComponentOne