Last Modified:
RadListViewのitemHeightを動的に設定する方法 #NativeScript
- nativescript-ui-listview v7.0.4
RadListView.listViewLayoutにListViewGridLayoutを設定する場合、itemHeightを素直に書くことができない問題がある。 端的に言うとiosとandroidで方法が違うのでそれぞれの処理を書かないといけない模様。
基本構造として以下のXMLを与えてみる。
<lv:RadListView
xmlns:lv="nativescript-ui-listview"
xmlns="http://www.nativescript.org/tns.xsd">
<lv:RadListView.listViewLayout>
<lv:ListViewGridLayout />
</lv:RadListView.listViewLayout>
<lv:RadListView.itemTemplate>
<AbsoluteLayout>
</AbsoluteLayout>
</lv:RadListView.itemTemplate>
</lv:RadListView>
これをiosで実行すると Warning: When using 'listViewLayout' of type ListViewGridLayout it is recommended to set it's 'itemHeight' property.
となり、当然アイテムの高さは固定されない。
かと言ってitemHeightを設定すると、
<lv:ListViewGridLayout itemHeight="200" />
今度はandroidで Warning: Setting the 'itemHeight' property of 'ListViewGridLayout' is not supported by the Android platform.
となり、これまたアイテムの高さが固定されない。
どうやらandroidではアイテム自身が高さを調整しないといけないらしい。
これらを満たすために、 ios:
,android:
の接頭辞を付けてRadListView.bindingContextを見るようにしてみる。
<lv:RadListView
loaded="onLoaded"
layoutChanged="onLayoutChanged"
xmlns:lv="nativescript-ui-listview"
xmlns="http://www.nativescript.org/tns.xsd">
<lv:RadListView.listViewLayout>
<lv:ListViewGridLayout ios:itemHeight="{{ $parents['RadListView'].itemHeight }}" />
</lv:RadListView.listViewLayout>
<lv:RadListView.itemTemplate>
<AbsoluteLayout android:height="{{ $parents['RadListView'].itemHeight }}">
</AbsoluteLayout>
</lv:RadListView.itemTemplate>
</lv:RadListView>
import { EventData, Observable } from 'tns-core-modules/data/observable';
import { RadListView } from 'nativescript-ui-listview';
class MyViewModel extends Observable {
itemHeight = 0;
}
export function onLoaded(args: EventData): void {
const view = args.object as RadListView;
const vm = new MyViewModel();
view.bindingContext = vm;
}
export function onLayoutChanged(args: EventData): void {
const view = args.object as RadListView;
const vm = view.bindingContext as MyViewModel;
vm.itemHeight = ...;
}
ところがこれではiosでダメなのです。こちらのIssueにある通り $parents
を使わずに直接バインドしろとのこと。
一応解決
色々やり方はあると思うけど、比較的シンプルなのは同じMyViewModelを見る方法だと思うのでそのように実装した。
<lv:RadListView
loaded="onLoaded"
layoutChanged="onLayoutChanged"
xmlns:lv="nativescript-ui-listview"
xmlns="http://www.nativescript.org/tns.xsd">
<lv:RadListView.listViewLayout>
<lv:ListViewGridLayout ios:itemHeight="{{ itemHeight }}" />
</lv:RadListView.listViewLayout>
<lv:RadListView.itemTemplate>
<AbsoluteLayout android:height="{{ $parents['RadListView'].itemHeight }}">
</AbsoluteLayout>
</lv:RadListView.itemTemplate>
</lv:RadListView>
import { EventData, Observable } from 'tns-core-modules/data/observable';
import { RadListView } from 'nativescript-ui-listview';
class MyViewModel extends Observable {
private _itemHeight = 0;
get itemHeight(): number {
return this._itemHeight;
}
set itemHeight(value: number) {
this._itemHeight = value;
this.notifyPropertyChange('itemHeight', this._itemHeight); // for ios
}
}
export function onLoaded(args: EventData): void {
const view = args.object as RadListView;
const vm = new MyViewModel();
view.bindingContext = vm;
view.listViewLayout.bindingContext = vm; // for ios
}
export function onLayoutChanged(args: EventData): void {
const view = args.object as RadListView;
const vm = view.bindingContext as MyViewModel;
vm.itemHeight = ...;
}
ところがこれはiosの警告が消えないのです。どうやらios:itemHeight
が動的だからっぽいです。
実害は無いんですが、ちょっと気持ち悪いのでバインドしない方法でもやってみました。
解決
<lv:RadListView
loaded="onLoaded"
layoutChanged="onLayoutChanged"
xmlns:lv="nativescript-ui-listview"
xmlns="http://www.nativescript.org/tns.xsd">
<lv:RadListView.listViewLayout>
<lv:ListViewGridLayout ios:itemHeight="1" /><!-- 0 だとやはり警告されるので -->
</lv:RadListView.listViewLayout>
<lv:RadListView.itemTemplate>
<AbsoluteLayout android:height="{{ $parents['RadListView'].itemHeight }}">
</AbsoluteLayout>
</lv:RadListView.itemTemplate>
</lv:RadListView>
import * as application from 'tns-core-modules/application';
import { EventData, Observable } from 'tns-core-modules/data/observable';
import { RadListView, ListViewGridLayout } from 'nativescript-ui-listview';
class MyViewModel extends Observable {
itemHeight = 0;
}
export function onLoaded(args: EventData): void {
const view = args.object as RadListView;
const vm = new MyViewModel();
view.bindingContext = vm;
}
export function onLayoutChanged(args: EventData): void {
const view = args.object as RadListView;
const vm = view.bindingContext as MyViewModel;
vm.itemHeight = ...;
if (application.ios) {
(vm.listViewLayout as ListViewGridLayout).itemHeight = vm.itemHeight;
}
}
あれー…こっちの方がシンプルかもしれない…。