異なるサイズの項目を表示する方法 (HTML)
[ この記事は、Windows ランタイム アプリを作成する Windows 8.x および Windows Phone 8.x 開発者を対象としています。Windows 10 向けの開発を行っている場合は、「最新のドキュメント」をご覧ください]
ListView は、既定で、一覧の各項目に同じサイズを割り当てます。グリッド レイアウトを使うと、項目を複数のセルに拡張することにより、この動作を変更し、異なるサイズの項目を表示できます。
理解しておく必要があること
テクノロジ
必要条件
- 基本的な ListView オブジェクトを作成および使用できることを前提としています。ListView コントロールの概要については、「クイック スタート: ListView の追加」をご覧ください。
手順
ListView のセルとサイズ指定について
コードを取り上げる前に、ListView が項目のサイズ指定をどのように処理するかを説明します。
ListView は、既定で、セルに含まれる各項目に同じサイズのセルを割り当てます。すべて同じサイズの項目を含む ListView を次に示します。
次に、1 つのセルを強調表示した状態の同じ ListView を示します。
セルのサイズは、ListView の最初の項目のサイズによって決まります。ListView に含まれる項目のサイズの異なる場合も、最初の項目のサイズに基づいてセルのサイズが割り当てられます。そのため、1 つだけ他の項目よりも大きい場合は、その項目が ListView の他の項目のサイズに合うようにクリップされます。
この動作は、セル スパンを有効にして変更できます。セル スパンを有効にすると、1 つの項目は複数のセルにまたがることができます。この例では、セル スパンが有効になっているため、大きな項目が 1 つではなく 5 つのセルにまたがっています。
セル スパンを有効にすると、基本のセルのサイズも明示的に指定できます。ListView のすべての項目のサイズは、基本のセル サイズの倍数にすることをお勧めします。次の例では、基本のセルと幅は同じで高さが 2 倍になるように、大きな項目が変更されています。
3 種類のサイズの項目を含む ListView の作り方を次に示します。
手順 1: データと ListView を作る
まず、データ ソースと ListView を作りましょう。
JavaScript ファイルで、ListView のデータ ソースを定義します。この例では、JSON オブジェクトの配列から List を作り、パブリックにアクセスできるようにします。これには、WinJS.Namespace.define を使って
DataExamples
という名前空間で公開します。データは「クイックスタート: ListView の追加」などの他のトピックで紹介した例と似ていますが、
type
フィールドを追加しています。 このフィールドに設定できる値は "smallListIconTextItem"、"mediumListIconTextItem"、"largeListIconTextItem" の 3 つです。この後の手順では、このフィールドを使って、各項目のサイズを決定する CSS クラスを割り当てます。(function () { "use strict"; var myCellSpanningData = new WinJS.Binding.List([ { title: "Banana Blast", text: "Low-fat frozen yogurt", picture: "images/60Banana.png", type: "smallListIconTextItem" }, { title: "Lavish Lemon Ice", text: "Sorbet", picture: "images/60Lemon.png", type: "mediumListIconTextItem" }, { title: "Marvelous Mint", text: "Gelato", picture: "images/60Mint.png", type: "largeListIconTextItem" }, { title: "Creamy Orange", text: "Sorbet", picture: "images/60Orange.png", type: "mediumListIconTextItem" }, { title: "Succulent Strawberry", text: "Sorbet", picture: "images/60Strawberry.png", type: "smallListIconTextItem" }, { title: "Very Vanilla", text: "Ice Cream", picture: "images/60Vanilla.png", type: "smallListIconTextItem" }, { title: "Banana Blast", text: "Low-fat frozen yogurt", picture: "images/60Banana.png", type: "mediumListIconTextItem" }, { title: "Lavish Lemon Ice", text: "Sorbet", picture: "images/60Lemon.png", type: "mediumListIconTextItem" }, { title: "Marvelous Mint", text: "Gelato", picture: "images/60Mint.png", type: "smallListIconTextItem" }, { title: "Creamy Orange", text: "Sorbet", picture: "images/60Orange.png", type: "smallListIconTextItem" }, { title: "Succulent Strawberry", text: "Sorbet", picture: "images/60Strawberry.png", type: "smallListIconTextItem" }, { title: "Very Vanilla", text: "Ice Cream", picture: "images/60Vanilla.png", type: "smallListIconTextItem" }, { title: "Banana Blast", text: "Low-fat frozen yogurt", picture: "images/60Banana.png", type: "smallListIconTextItem" }, { title: "Lavish Lemon Ice", text: "Sorbet", picture: "images/60Lemon.png", type: "smallListIconTextItem" }, { title: "Marvelous Mint", text: "Gelato", picture: "images/60Mint.png", type: "mediumListIconTextItem" }, { title: "Creamy Orange", text: "Sorbet", picture: "images/60Orange.png", type: "smallListIconTextItem" }, { title: "Succulent Strawberry", text: "Sorbet", picture: "images/60Strawberry.png", type: "largeListIconTextItem" }, { title: "Very Vanilla", text: "Ice Cream", picture: "images/60Vanilla.png", type: "mediumListIconTextItem" } ]); WinJS.Namespace.define("DataExamples", { myCellSpanningData: myCellSpanningData }); })();
コーディングを進め、この例で使われている画像を使う場合は、ListView 項目テンプレートのサンプルをダウンロードすると画像を入手できます。
HTML ファイルで、セル スパン レイアウトを使った ListView を作ります。その itemDataSource プロパティに、前の手順で作ったデータ ソースを設定します。
<div id="myListView" data-win-control="WinJS.UI.ListView" data-win-options="{ itemDataSource: DataExamples.myCellSpanningData.dataSource, layout: { type: WinJS.UI.CellSpanningLayout } }" ></div>
手順 2: 基本のセル サイズを定義してセル スパンを有効にする
次に、基本のセルのサイズを定義する必要があります。
ListView でセル スパン レイアウトを使うには、CellSpanningLayout オブジェクトを作り、これを使って ListView コントロールの layout プロパティを設定します。セル スパンを有効にして基本のセルのサイズを定義するには、この情報を提供する groupInfo 関数を作り、その関数を使って CellSpanningLayout オブジェクトの groupInfo プロパティを設定します。ここで定義する groupInfo 関数は、次のプロパティを含むオブジェクトを返す必要があります。
enableCellSpanning
セル スパンを有効にするには、true に設定します。既定値は false です。cellWidth
基本のセルの幅。cellHeight
基本のセルの高さ。
この例では、基本のセルのサイズを 310 × 80 ピクセルにしましょう。
基本のセルのサイズを定義してセル スパンを有効にするには
データを作った JavaScript ファイルで、groupInfo 関数を作ります。この関数は、セル スパンを有効にして基本のセルを 310 × 80 ピクセルと定義します。
// Enable cell spanning and specify // the cellWidth and cellHeight for the items var groupInfo = function groupInfo() { return { enableCellSpanning: true, cellWidth: 310, cellHeight: 80 }; };
WinJS.Utilities.markSupportedForProcessing を使って、関数を HTML で利用できるようにします。
// Enable cell spanning and specify // the cellWidth and cellHeight for the items var groupInfo = function groupInfo() { return { enableCellSpanning: true, cellWidth: 310, cellHeight: 80 }; }; WinJS.Utilities.markSupportedForProcessing(groupInfo);
既定では、セキュリティ上の理由により、関数とイベント ハンドラーは JavaScript 用 Windows ライブラリのコントロールで利用できません。WinJS.Utilities.markSupportedForProcessing 関数を使うと、この既定の動作を変更できます。これによって、提供する HTML の形式が正しく、WinJS によって処理できるものと見なされます。詳しくは、「基本的なアプリのコーディング」をご覧ください。)
関数で WinJS.Utilities.markSupportedForProcessing を呼び出しても、パブリックにアクセスできるようになりません。これについては、次の手順で説明します。
名前空間を使って groupInfo 関数を公開することで、この関数にパブリックにアクセスできるようにします。この例では、手順 1.1 で作った
DataExamples
名前空間を更新します。WinJS.Namespace.define("DataExamples", { groupInfo : groupInfo, myCellSpanningData: myCellSpanningData });
groupInfo 関数を使うように ListView を更新します。
<div id="myListView" data-win-control="WinJS.UI.ListView" data-win-options="{ itemDataSource: DataExamples.myCellSpanningData.dataSource, layout: { groupInfo: DataExamples.groupInfo, type: WinJS.UI.GridLayout } }" ></div>
手順 3: 単一のセルにまたがる項目のサイズを定義する
基本のセル サイズを定義したので、項目のサイズを定義できます。最初の手順でデータを定義したときに、項目の大きさに関する情報 (小、中、大) を格納する type
フィールドを含めました。その情報を使って項目のサイズを割り当てることができます。サイズを割り当てる最良の方法として、CSS クラスを使います。この方法は、テンプレート関数と WinJS.Binding.Template のどちらを使った場合にも役立ちます。
基本のセルの幅は 310 ピクセル、高さは 80 ピクセルです。各項目の合計サイズは、基本のセル サイズの倍数である必要があります。基本のセル サイズとは、項目に項目のスペース、余白、境界線を加えたサイズです。
基本のセル サイズを計算する数式を次に示します。
- 基本のセルの幅 = 項目の幅 + 項目の水平方向のスペース + 項目の水平方向の余白 + 項目の境界線の太さ
- 基本のセルの高さ = 項目の高さ + 項目の垂直方向のスペース + 項目の垂直方向の余白 + 項目の境界線の太さ
単一の基本のセルを使う項目のサイズを定義するには
最小の項目のサイズを定義します。カスケード スタイル シート (CSS) ファイルで、"smallListIconTextItem" という名前の CSS クラスを作ります。
.smallListIconTextItem { }
最小の項目が使うセルは 1 つだけです。項目の幅を 300 ピクセル、高さを 70 ピクセル、スペースを 5 ピクセルに設定します。
.smallListIconTextItem { width: 300px; height: 70px; padding: 5px; overflow: hidden; background-color: Pink; display: -ms-grid; }
これらの数値を数式と照合して、基本のセル サイズと一致することを確認します。
セルの幅 = 項目の幅 + 左スペース + 右スペース + 境界線の太さ + 左余白 + 右余白 = 300 + 5 ピクセル + 5 ピクセル + 0 + 0 + 0 = 310
セルの高さ = 項目の高さ + 上スペース + 下スペース + 境界線の太さ + 上余白 + 下余白 = 70 + 5 ピクセル + 5 ピクセル + 0 + 0 + 0 = 80
基本のセル サイズと一致するため、次の手順に進みます。
手順 4: 複数のセルにまたがる項目のサイズを定義する
複数のセルにまたがる項目のサイズを決定する場合は、項目がまたがるセル間の win-container
の余白も考慮に入れる必要があります。たとえば、水平方向に 1 つのセル、垂直方向に 2 つのセルにまたがる項目の場合、次に示すように、その項目の合計サイズには、最初のセルの win-container
の下余白と 2 番目のセルの win-container
の上余白が含まれます。
複数のセルにまたがる項目の合計サイズを計算する数式を次に示します。
項目の幅の合計 = number of cells * 基本のセルの幅 + (number of cells - 1) * (
win-container
左余白 +win-container
右余白)項目の高さの合計 = number of cells * 基本のセルの高さ + (number of cells - 1) * (
win-container
上余白 +win-container
下余白)
ヒント 既定では、win-container
の余白は 5 ピクセルです。
垂直方向に 2 つのセルにまたがる項目のサイズを定義するには
次の数式を使って項目の高さの合計を測定します。
項目の高さの合計 = number of cells * 基本のセルの高さ + (number of cells - 1) * (
win-container
上余白 +win-container
下余白) = 2 * 80 + (2-1) * (5 + 5) = 170項目のサイズを指定する CSS スタイルを作ります。この例では、高さ 160 ピクセル、スペース 5 ピクセルの項目を定義しているため、高さの合計は 160 + 5 + 5 = 170 です。項目が水平方向にまたがるセルは 1 つだけのため、手順 3 で作った CSS クラスの
smallListIconTextItem
と同じ幅とスペースを指定します。.mediumListIconTextItem { width: 300px; height: 160px; padding: 5px; overflow: hidden; background-color: LightGreen; display: -ms-grid; }
垂直方向に 3 つのセルにまたがる項目のサイズを定義するには
次の数式を使って項目の高さの合計を測定します。
項目の高さの合計 = number of cells * 基本のセルの高さ + (number of cells - 1) * (
win-container
上余白 +win-container
下余白) = 3 * 80 + (3-1) * (5 + 5) = 260項目のサイズを指定する CSS スタイルを作ります。この例では、高さ 250 ピクセル、スペース 5 ピクセルの項目を定義しているため、高さの合計は 250 + 5 + 5 = 260 です。
.largeListIconTextItem { width: 300px; height: 250px; padding: 5px; overflow: hidden; background-color: LightBlue; display: -ms-grid; }
手順 5: CellSpanningLayout の項目のサイズ指定関数を作成する
CellSpanningLayout では、groupInfo 関数に加えて、データ ソースのさまざまな "タイプ" の項目をサイズ指定する方法を決定する itemInfo 関数を公開する必要があります。itemInfo 関数は、次のプロパティを含む JavaScript オブジェクトを返す必要があります。
ListView の個別項目のサイズを定義するには
データを作成した JavaScript ファイルで、データ ソースから項目を回転して取得し、該当項目の対応するサイズと高さを返す itemInfo 関数を作成します。
// Item info function that returns the size of a cell spanning item var itemInfo = WinJS.Utilities.markSupportedForProcessing(function itemInfo(itemIndex) { var size = { width: 310, height: 80 }; // Get the item from the data source var item = DataExamples.myCellSpanningData.getAt(itemIndex); if (item) { // Get the size based on the item type switch (item.type) { case "smallListIconTextItem": size = { width: 310, height: 80 }; break; case "mediumListIconTextItem": size = { width: 310, height: 170 }; break; case "largeListIconTextItem": size = { width: 310, height: 260 }; break; default: } } return size; });
itemInfo は、HTML で関数にアクセスできるように、WinJS.Utilities.markSupportedForProcessing に対する呼び出しによってラップされます。
名前空間を使って itemInfo 関数を公開することで、この関数にパブリックにアクセスできるようにします。この例では、手順 1.1 で作った
DataExamples
名前空間を更新します。WinJS.Namespace.define("DataExamples", { myCellSpanningData: myCellSpanningData, groupInfo: groupInfo, itemInfo: itemInfo });
itemInfo 関数を使うように ListView を更新します。
<div id="myListView" data-win-control="WinJS.UI.ListView" data-win-options="{ itemDataSource: DataExamples.myCellSpanningData.dataSource, layout: { groupInfo: DataExamples.groupInfo, itemInfo: DataExamples.itemInfo, type: WinJS.UI.CellSpanningLayout } }" ></div>
手順 6: テンプレートを作る
最後に、先ほど定義した CSS クラスを使ったテンプレートまたはテンプレート関数を作ります。ここでは、WinJS.Binding.Template とテンプレート関数両方の作り方を説明します。
オプション A: WinJS.Binding.Template を使う
HTML で、WinJS.Binding.Template を定義します。
<div id="myItemTemplate" data-win-control="WinJS.Binding.Template" style="display: none"> <div> <img src="#" class="regularListIconTextItem-Image" data-win-bind="src: picture" /> <div class="regularListIconTextItem-Detail"> <h4 data-win-bind="innerText: title"></h4> <h6 data-win-bind="innerText: text"></h6> </div> </div> </div>
手順 1.1 でデータを定義したときに、各項目に割り当てられる CSS クラスを指定する
type
プロパティをどのように含めたかを思い出してください。ここでは、そのデータを使用できます。項目のルート要素で、クラス名をデータのtype
フィールドの値にバインドします。<div id="myItemTemplate" data-win-control="WinJS.Binding.Template" style="display: none"> <div data-win-bind="className: type"> <img src="#" class="regularListIconTextItem-Image" data-win-bind="src: picture" /> <div class="regularListIconTextItem-Detail"> <h4 data-win-bind="innerText: title"></h4> <h6 data-win-bind="innerText: text"></h6> </div> </div> </div>
注 この例では、class ではなく className にバインドしています。これは、HTML で "class" を使っている場合でも、バッキングの JavaScript プロパティの名前が "className" となっているためです。アプリは data-win-bind 属性を処理するときに、JavaScript の呼び出しを使って、バインドされた値を割り当てます。
つまり、HTML 属性の名前とバッキングの JavaScript プロパティの名前が異なると、data-win-bind の設定時に JavaScript プロパティの名前を使います。
itemTemplate プロパティにテンプレートの ID を設定して、テンプレートを使うように ListView を更新します。
<div id="listView" data-win-control="WinJS.UI.ListView" data-win-options="{ itemDataSource: DataExamples.myCellSpanningData.dataSource, itemTemplate: select(#'myItemTemplate'), layout: { groupInfo: DataExamples.groupInfo, itemInfo: DataExamples.itemInfo, type: WinJS.UI.CellSpanningLayout } }"></div
必要に応じて、WinJS.Binding.Template の代わりにテンプレート関数を使うことができます。テンプレート関数を使うと、より柔軟に HTML を生成してサイズを割り当てることができます。
オプション B: テンプレート関数を使う
JavaScript ファイルで、テンプレート関数を定義します。 このコードは、データを含む同一のファイルに追加することも、別のファイルに追加することもできます。ListView を含むページがそのファイルを参照していることを確認してください。
この例では、各項目の
type
データを使って、そのサイズを決める CSS クラスを項目に割り当てます。var myCellSpanningJSTemplate = function myCellSpanningJSTemplate(itemPromise) { return itemPromise.then(function (currentItem) { var result = document.createElement("div"); // Use source data to decide what size to make the // ListView item result.className = currentItem.data.type; result.style.overflow = "hidden"; // Display image var image = document.createElement("img"); image.className = "regularListIconTextItem-Image"; image.src = currentItem.data.picture; result.appendChild(image); var body = document.createElement("div"); body.className = "regularListIconTextItem-Detail"; body.style.overflow = "hidden"; result.appendChild(body); // Display title var title = document.createElement("h4"); title.innerText = currentItem.data.title; body.appendChild(title); // Display text var fulltext = document.createElement("h6"); fulltext.innerText = currentItem.data.text; body.appendChild(fulltext); return result; }); };
マークアップからアクセスできるように、関数で markSupportedForProcessing を呼び出します。
WinJS.Utilities.markSupportedForProcessing(myCellSpanningJSTemplate);
WinJS.Namespace.define を使って、関数にパブリックにアクセスできるようにします。
WinJS.Namespace.define("Templates", { myCellSpanningJSTemplate: myCellSpanningJSTemplate });
HTML で、itemTemplate プロパティにテンプレート関数の名前を設定して、テンプレート関数を使うように ListView を更新します。
<div id="myListView" data-win-control="WinJS.UI.ListView" data-win-options="{ itemDataSource: DataExamples.myCellSpanningData.dataSource, itemTemplate: Templates.myCellSpanningJSTemplate layout: { groupInfo: DataExamples.groupInfo, itemInfo: DataExamples.itemInfo, type: WinJS.UI.CellSpanningLayout } }" ></div>
どちらの方法でテンプレートを使った場合でも、アプリを実行すると ListView に複数のサイズの項目が表示されます。
注釈
項目の編集
セル スパンを有効にした ListView の項目を変更する場合は、変更を行うたびに ListView.recalculateItemPosition を呼び出します。
- データ ソースが WinJS.Binding.List の場合、編集直後 (List.push または List.splice を呼び出した後など) に recalculateItemPosition を呼び出します。
- データ ソースがカスタム VirtualizedDataSource の場合、beginEdits を呼び出し、編集を行います。その後、recalculateItemPosition を呼び出してから、endEdits を呼び出します。