ComponentOne Information

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

Xamarin.FormsでGridViewやExcelのような行単位で色の異なる一覧を表示をする

アプリの種類やプラットフォームを問わずデータを一覧表示する要望は常にあります。
そして視認性を高める配慮として縞模様のグリッド表示をよく見かけます。請求書の明細欄であったり、タイムスケジュールを表示する看板だったり、飲食店のメニューだったりと一覧表示には欠かせない形式です。

アプリ画面でもその要望は多く、グレープシティが提供する各種データグリッドコンポーネントにもそれを実現する機能が標準で搭載されています。
モバイルアプリ用コンポーネントのXuni(ズーニー)でデータグリッド機能を提供しているFlexGridでも可能です。

FlexGridはデータソースを指定した一覧表示を得意とするGridViewタイプのUIコンポーネントです。
他の記事で紹介したように、Web APIでデータを取得し、それをデータソースに一覧を表示する機能を実現します。
ここでも、後半のカスタマイズ例として縞模様のグリッドを表示しました。

hatena.c1.grapecity.com

しかしFlexGridはデータソースを指定した一覧表示だけでなく、非接続型のグリッド表示も可能です。
非接続型はアンバウンドとも言いますが、表示するデータをデータソースの形では用意せずに、グリッドのセルを指定してデータを入れて一覧表を作る機能です。
グリッドは行(Column)と列(Row)の組み合わせで構成されているので、それぞれを座標位置のようにとらえてセルを特定し、データや属性を指定します。
この記事では、Xamarin.Formsでアプリを作成し、iOSアプリに一覧表を表示します。Androidアプリでも動作可能です。

プロジェクトの作成手順やFlexGridの組み込み方法は、前述の記事やWebサイトの解説を参照してください。

www.goxuni.com

また、今回はC#のコードですべて記述しますのでXAMLでの画面定義はFlexGridを表示する記述のみです。 プロジェクト名をXuni_QuickStartとして、Xamarin.Formsプロジェクトを新規に作成します。

UIの作成

既定で作成されたページXuni_QuickStartPage.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 = "false" : データセットの情報から列を自動的に作成しない
       IsReadOnly = "true" : 読み取り専用  
    

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

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

    <StackLayout VerticalOptions="FillAndExpand">
        <flexgrid:FlexGrid 
                x:Name="grid" 
                AutoGenerateColumns="false" 
                IsReadOnly="true">
        </flexgrid:FlexGrid>
    </StackLayout>

</ContentPage>

FlexGridにデータを設定

まずデータを表示するためのグリッドを定義します。今回作成するグリッドはヘッダーを含めて3列×6行です。 以下のイメージになります。

列1 列2
1行目 データ データ
2行目 データ データ
3行目 データ データ
4行目 データ データ
5行目 データ データ
列の作成

それではFlexGridを作成していきます。グリッドの形を作るにはまず列の定義です。
GridColumnクラスをインスタンス化して列オブジェクトを生成します。
作成した列に各定義情報を設定し、最終的にFlexGridオブジェクトに追加すれば完成です。作成する列の数だけ処理を繰り返します。

// 列オブジェクトを作成
GridColumn col = new GridColumn();
// 列ヘッダーに番号を設定
col.Header = String.Format("列 {0}",(idx + 1).ToString());
// 列ヘッダーとセルの表示位置を設定(中央に表示)
col.HeaderHorizontalAlignment = LayoutAlignment.Center;
col.HorizontalAlignment = LayoutAlignment.Center;
// 列をグリッドに追加
grid.Columns.Add(col);
行の作成

行(Row)の作成は列と同様に行オブジェクトを生成します。
GridRowクラスをインスタンス化して行オブジェクトに設定を加えます。

// 行オブジェクトを作成
GridRow row = new GridRow();
// 行をグリッドに追加
grid.Rows.Add(row);
// 行ヘッダーに番号を設定
grid.SetCellValue(GridCellType.RowHeader, row.Index, 0, rowidx + 1);

最後の行はSetCellValueメソッドを使ってセルに値を入れています。
このメソッドの第一引数にはGridCellTupe列挙型から行ヘッダーを表すRowHeaderを指定しています。これは、メソッド内部で値を入れるセルが、ヘッダーのセルなのか通常のセルなのかのセルタイプを判断するためです。

セルに値を設定

ここまでのコードでグリッドの全体像は完成しています。実行すると以下のような表示になります。
f:id:ComponentOne_JP:20161221170205p:plain
最後にこのグリッドにデータを入れて表らしくします。行を作成する途中で、作成対象となる行に含まれる列のセルにデータを設定します。まわりくどい表現ですが、つまりは「作ったセルにデータを入れる」作業です。以下のコードを行を作るループの中に追加します。

// 1つの行に対して列数の分だけ繰り返す
for (int colidx = 0; colidx < colSize; colidx++)
{
    // セルに表示する内容を作成
    var cellvalue = String.Format("データ {0} - {1}", (row.Index + 1), (colidx + 1));
    // セルの位置を行と列のインデックスで指定し、値を設定
    grid.SetCellValue(GridCellType.Cell, row.Index, colidx, (cellvalue));
}

このコードではヘッダーと同じSetCellValueメソッドを利用してデータセルに値を設定しています。引数にGridCellType.Cellを指定している点が異なります。
これで簡単な一覧表ができあがりました。
f:id:ComponentOne_JP:20161221170741p:plain

パフォーマンスの計測

このサンプルの冒頭部分では作成する列と行の数を定数で定義しています。

const int colSize = 3;
const int rowSize = 5;

この定義を変更すればより大きなグリッドを作成できることにお気づきだと思います。
コードを改造して簡易的にFlexGridのセル生成能力を計測してみます。
100行×1000列の表を作成するように定数を変更し、セルにデータを設定するメソッド部分も改造します。

セルに経過時間を入れることで、該当するセルがどのタイミングで作られたかがわかりますので、最後のセルの内容を見れば全体の生成時間がわかります。
セルにデータを設定する部分のコードを以下のように改造しました。

public Xuni_QuickStartPage()
{
    InitializeComponent();

    // 作成する行数と列数を定数として定義
    const int colSize = 100;
    const int rowSize = 1000;

    // ストップウォッチの作成と計測開始
    System.Diagnostics.Stopwatch stopWatch = new System.Diagnostics.Stopwatch();
    stopWatch.Start();

    // (省略)  

    }
    stopWatch.Stop();
    // 左上角のセルに合計時間を表示
}

セルの値設定部分のにデータを入れるSetCellValueメソッドの部分は以下のように変更します。

// セルに表示する内容を作成
// var cellvalue = String.Format("データ {0} - {1}", (row.Index + 1), (colidx + 1));
   var cellvalue = String.Format("{0} ms", stopWatch.ElapsedMilliseconds.ToString());

// セルの位置を行と列のインデックスで指定し、値を設定
grid.SetCellValue(GridCellType.Cell, row.Index, colidx, (cellvalue));

System.Diagnostics.Stopwatchクラスを利用して経過時間を計測し、セルにデータを設定するときに開始からの経過時間をミリ秒単位で取得しています。

また大量のデータを表示した場合に、最終のセルを表示するのは困難なので左上隅のヘッダーセル(GridCellType.TopLeft)にも最終時間を入れることにしました。

// 左上角のセルに合計時間を表示
grid.SetCellValue(GridCellType.TopLeft, 0, 0, String.Format("{0} ms", stopWatch.ElapsedMilliseconds.ToString()));  

あくまでテストなので実用性は無視し、100列×1000行の一覧表を作成してみました。
シミュレーター(iPad Air 2 - iOS 10.1)の実行例で参考値ではありますが、10万セルをおよそ1000ms台(0.9~1.0秒)で作成が完了しています。

f:id:ComponentOne_JP:20161221171720p:plain

背景色の設定

最後にカスタマイズです。
冒頭で説明したように縞模様のグリッドにしたいと思います。
こちらも実用性は無視し、季節性を考慮した配色にしてみました。
追加したコードは以下です。

// 行の背景色を設定。これがベースの背景色
grid.RowBackgroundColor = Color.FromHex("#009944");
// 偶数行の背景色を設定。一行おきに色を変える
grid.AlternatingRowBackgroundColor = Color.FromHex("#E60012");
// 列ヘッダーの背景色を設定。最上位のヘッダー行の色
grid.ColumnHeaderBackgroundColor = Color.FromHex("#D7C447");
// 列ヘッダーのみを表示する設定
grid.HeadersVisibility = GridHeadersVisibility.Column;
// グリッド線は行を区別する水平線のみ表示
grid.GridLinesVisibility = GridLinesVisibility.Horizontal;
// グリッド線の色と幅を設定
grid.GridLinesColor =Color.FromHex("#D7C447");
grid.GridLinesWidth = 2;
// データの文字色を設定
grid.TextColor = Color.White;

できあがりです。
f:id:ComponentOne_JP:20161221171755p:plain

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

GitHub - fukuchima/Xuni_FlexGrid_Unbound: Xuni FlexGrid Sample

おわりに

2016年は「Xamarin」という言葉が多くの人に届いたと思います。
実際にこの技術に触れた方も少なくありません。それにともなってXuniに関心を持っていただいた方もいらっしゃいます。
2017年は、Visual Studio 2017やVisual Studio for Macが正式に登場し、さらに快適な開発環境になっていくでしょう。

Xuniは2017年も1月、5月、9月に新バージョンをリリースする予定です。
より多くの方にご利用いただけるように進歩していきますので、どうぞよろしくお願いします。

www.goxuni.com


追記:この記事で紹介している「Xuni(ズーニー)」は、2017年7月に提供を終了し、新たに「ComponentOne Studio for Xamarin」として提供しています。

ComponentOne