repeater reworked

This commit is contained in:
Vladimir Enchev
2015-05-25 12:09:28 +03:00
parent 342bae570d
commit 5a85775bf0
2 changed files with 119 additions and 99 deletions

View File

@@ -4,31 +4,12 @@
declare module "ui/repeater" { declare module "ui/repeater" {
import view = require("ui/core/view"); import view = require("ui/core/view");
import dependencyObservable = require("ui/core/dependency-observable"); import dependencyObservable = require("ui/core/dependency-observable");
import layoutModule = require("ui/layouts/layout");
/** /**
* Represents a UI Repeater component. * Represents a UI Repeater component.
*/ */
export class Repeater extends view.View { export class Repeater extends view.View {
/**
* Represents the observable property backing the orientation property of each Repeater instance.
*/
public static orientationProperty: dependencyObservable.Property;
/**
* Dependency property used to support binding operations for the items wrapping of the current Repeater instance.
*/
public static wrapProperty: dependencyObservable.Property;
/**
* Represents the observable property backing the itemWidth property of each Repeater instance.
*/
public static itemWidthProperty: dependencyObservable.Property;
/**
* Represents the observable property backing the itemHeight property of each Repeater instance.
*/
public static itemHeightProperty: dependencyObservable.Property;
/** /**
* Represents the observable property backing the items property of each Repeater instance. * Represents the observable property backing the items property of each Repeater instance.
*/ */
@@ -40,27 +21,9 @@ declare module "ui/repeater" {
public static itemTemplateProperty: dependencyObservable.Property; public static itemTemplateProperty: dependencyObservable.Property;
/** /**
* Gets or sets if layout should be horizontal or vertical. * Represents the items layout property of each Repeater instance.
* The default value is vertical.
*/ */
orientation: string; public static itemsLayoutProperty: dependencyObservable.Property;
/**
* Gets or sets whether the Repeater wraps items or not.
*/
wrap: boolean;
/**
* Gets or sets the width used to measure and layout each child.
* Default value is Number.NaN which does not restrict children.
*/
itemWidth: number;
/**
* Gets or sets the height used to measure and layout each child.
* Default value is Number.NaN which does not restrict children.
*/
itemHeight: number;
/** /**
* Gets or set the items collection of the Repeater. * Gets or set the items collection of the Repeater.
@@ -72,6 +35,11 @@ declare module "ui/repeater" {
* Gets or set the item template of the Repeater. * Gets or set the item template of the Repeater.
*/ */
itemTemplate: string; itemTemplate: string;
/**
* Gets or set the items layout of the Repeater. Default value is StackLayout with orientation="vertical".
*/
itemsLayout: layoutModule.Layout;
/** /**
* Forces the Repeater to reload all its items. * Forces the Repeater to reload all its items.

View File

@@ -5,14 +5,16 @@ import viewModule = require("ui/core/view");
import observable = require("data/observable"); import observable = require("data/observable");
import observableArray = require("data/observable-array"); import observableArray = require("data/observable-array");
import weakEvents = require("ui/core/weak-event-listener"); import weakEvents = require("ui/core/weak-event-listener");
import enums = require("ui/enums"); import types = require("utils/types");
import layoutModule = require("ui/layouts/layout");
import stackLayoutModule = require("ui/layouts/stack-layout");
import builder = require("ui/builder");
import utils = require("utils/utils");
import platform = require("platform");
var ITEMS = "items"; var ITEMS = "items";
var WRAP = "wrap";
var ORIENTATION = "orientation";
var ITEMTEMPLATE = "itemTemplate"; var ITEMTEMPLATE = "itemTemplate";
var ITEMWIDTH = "itemWidth"; var LAYOUT = "layout";
var ITEMHEIGHT = "itemHeight";
var REPEATER = "Repeater"; var REPEATER = "Repeater";
export module knownTemplates { export module knownTemplates {
@@ -29,15 +31,22 @@ function onItemTemplatePropertyChanged(data: dependencyObservable.PropertyChange
repeater.refresh(); repeater.refresh();
} }
function validateOrientation(value: any): boolean { function onItemsLayoutPropertyPropertyChanged(data: dependencyObservable.PropertyChangeData) {
return value === enums.Orientation.vertical || value === enums.Orientation.horizontal; var repeater = <definition.Repeater>data.object;
repeater.refresh();
} }
function isWidthHeightValid(value: any): boolean { export class Repeater extends viewModule.CustomLayoutView implements definition.Repeater {
return isNaN(value) || (value >= 0.0 && value !== Number.POSITIVE_INFINITY); private isDirty: boolean = true;
} private _ios: UIView;
export class Repeater extends viewModule.View implements definition.Repeater { constructor() {
super();
if (platform.device.os === platform.platformNames.ios) {
this._ios = UIView.new();
}
}
public static itemsProperty = new dependencyObservable.Property( public static itemsProperty = new dependencyObservable.Property(
ITEMS, ITEMS,
@@ -59,37 +68,14 @@ export class Repeater extends viewModule.View implements definition.Repeater {
) )
); );
public static orientationProperty = new dependencyObservable.Property( public static itemsLayoutProperty = new dependencyObservable.Property(
ORIENTATION, LAYOUT,
REPEATER, REPEATER,
new proxy.PropertyMetadata(enums.Orientation.vertical, new proxy.PropertyMetadata(
dependencyObservable.PropertyMetadataSettings.AffectsLayout,
undefined, undefined,
validateOrientation)
);
public static wrapProperty = new dependencyObservable.Property(
WRAP,
REPEATER,
new proxy.PropertyMetadata(false, dependencyObservable.PropertyMetadataSettings.AffectsLayout)
);
public static itemWidthProperty = new dependencyObservable.Property(
ITEMWIDTH,
REPEATER,
new proxy.PropertyMetadata(Number.NaN,
dependencyObservable.PropertyMetadataSettings.AffectsLayout, dependencyObservable.PropertyMetadataSettings.AffectsLayout,
undefined, onItemsLayoutPropertyPropertyChanged
isWidthHeightValid) )
);
public static itemHeightProperty = new dependencyObservable.Property(
ITEMHEIGHT,
REPEATER,
new proxy.PropertyMetadata(Number.NaN,
dependencyObservable.PropertyMetadataSettings.AffectsLayout,
undefined,
isWidthHeightValid)
); );
get items(): any { get items(): any {
@@ -106,8 +92,22 @@ export class Repeater extends viewModule.View implements definition.Repeater {
this._setValue(Repeater.itemTemplateProperty, value); this._setValue(Repeater.itemTemplateProperty, value);
} }
get itemsLayout(): layoutModule.Layout {
return this._getValue(Repeater.itemsLayoutProperty);
}
set itemsLayout(value: layoutModule.Layout) {
this._setValue(Repeater.itemsLayoutProperty, value);
}
public refresh() { public refresh() {
// this.isDirty = true;
this._createChildren();
}
public onLoaded() {
super.onLoaded();
this._createChildren();
} }
public _onItemsPropertyChanged(data: dependencyObservable.PropertyChangeData) { public _onItemsPropertyChanged(data: dependencyObservable.PropertyChangeData) {
@@ -126,31 +126,83 @@ export class Repeater extends viewModule.View implements definition.Repeater {
this.refresh(); this.refresh();
} }
get wrap(): boolean { private _createChildren() {
return this._getValue(Repeater.wrapProperty); if (this.isDirty && this.isLoaded) {
} if (types.isDefined(this.items) && types.isNumber(this.items.length)) {
set wrap(value: boolean) {
this._setValue(Repeater.wrapProperty, value); if (types.isUndefined(this.itemsLayout)) {
this.itemsLayout = new stackLayoutModule.StackLayout();
}
if (this.itemsLayout.parent !== this) {
this._addView(this.itemsLayout);
}
clearItemsLayout(this.itemsLayout);
var i: number;
for (i = 0; i < this.items.length; i++) {
var viewToAdd = builder.parse(this.itemTemplate, this);
if (types.isDefined(viewToAdd)) {
this.itemsLayout.addChild(viewToAdd);
viewToAdd.bindingContext = this._getDataItem(i);
}
}
}
this.isDirty = false;
}
} }
get orientation(): string { private _getDataItem(index: number): any {
return this._getValue(Repeater.orientationProperty); return this.items.getItem ? this.items.getItem(index) : this.items[index];
}
set orientation(value: string) {
this._setValue(Repeater.orientationProperty, value);
} }
get itemWidth(): number { get ios(): UIView {
return this._getValue(Repeater.itemWidthProperty); return this._ios;
}
set itemWidth(value: number) {
this._setValue(Repeater.itemWidthProperty, value);
} }
get itemHeight(): number { get _childrenCount(): number {
return this._getValue(Repeater.itemHeightProperty); var count = 0;
if (this.itemsLayout) {
count++;
}
return count;
} }
set itemHeight(value: number) {
this._setValue(Repeater.itemHeightProperty, value); public _eachChildView(callback: (child: viewModule.View) => boolean) {
if (this.itemsLayout) {
callback(this.itemsLayout);
}
}
public onLayout(left: number, top: number, right: number, bottom: number): void {
viewModule.View.layoutChild(this, this.itemsLayout, 0, 0, right, bottom);
}
public onMeasure(widthMeasureSpec: number, heightMeasureSpec: number): void {
var result = viewModule.View.measureChild(this, this.itemsLayout, widthMeasureSpec, heightMeasureSpec);
var width = utils.layout.getMeasureSpecSize(widthMeasureSpec);
var widthMode = utils.layout.getMeasureSpecMode(widthMeasureSpec);
var height = utils.layout.getMeasureSpecSize(heightMeasureSpec);
var heightMode = utils.layout.getMeasureSpecMode(heightMeasureSpec);
var widthAndState = viewModule.View.resolveSizeAndState(result.measuredWidth, width, widthMode, 0);
var heightAndState = viewModule.View.resolveSizeAndState(result.measuredHeight, height, heightMode, 0);
this.setMeasuredDimension(widthAndState, heightAndState);
}
}
function clearItemsLayout(itemsLayout: layoutModule.Layout) {
var i: number = itemsLayout.getChildrenCount();
if (i > 0) {
while (i >= 0) {
itemsLayout.removeChild(itemsLayout.getChildAt(i));
i--;
}
} }
} }