Sectioned Table Extension¶
All Sectioned Table extension classes must extend the IView
interface.
For Mobile Development Kit version 6.2 or older, the return value of the view()
method must be a subclass of a native view (i.e. a subclass of UIView
for iOS or android.view.View
for Android) for section/table and form cell extensions. The viewIsNative()
must also be overridden to return true
.
With Mobile Development Kit version 6.3 or newer, it is possible to return a NativeScript view through the view()
method. In this case, the viewIsNative()
must also be overridden to return false
.
Example - Creating Extension Using Native Views¶
Implementing the Extension control to return native iOS / Android views using TypeScript Marshalling.
You have the following the file in the Extensions
folder: /MyMDKExtensionModule/controls/MyExtensionViewControl.ts
:
//file: MyExtensionViewControl.ts
import * as app from '@nativescript/core/application';
import { Color } from '@nativescript/core/color';
import { IView } from 'mdk-core/IView';
export class MyExtensionView extends IView {
private _label: any;
private _value: any;
public initialize(props) {
super.initialize(props);
const color = new Color('yellow');
if (this.definition().data.ExtensionProperties.Prop1) {
this._value = this.definition().data.ExtensionProperties.Prop1.Value;
}
else {
this._value = "Default Value";
}
if (app.ios) {
this._label = UILabel.alloc().init();
this._label.numberOfLines = 3;
this._label.backgroundColor = color.ios;
} else {
this._label = new android.widget.TextView(this.androidContext());
this._label.setBackgroundColor(color.android);
}
}
public view() {
//Use provided ValueResolver to resolve value to support bindings, rules, etc in your extension
this.valueResolver().resolveValue(this._value).then((resolvedValue)=> {
if (app.ios) {
this._label.text = resolvedValue;
} else {
this._label.setText(resolvedValue);
}
});
return this._label;
}
public viewIsNative() {
return true;
}
}
Consuming the extension control in your app e.g. in a Section of a Sectioned Table:
{
"Module": "MyMDKExtensionModule",
"Control": "MyExtensionViewControl",
"Class": "MyExtensionView",
"Height": 200,
"ExtensionProperties": {
"MinValue": 0,
"MaxValue": 100,
"Unit": "mi",
"Title": "Distance"
},
"Value": 10,
"OnPress": "/MDKApp/Actions/ShowMessage.action",
"_Type": "Section.Type.Extension",
"_Name": "MyNSProgress2"
}
Example - Creating Extension Using NativeScript Views¶
Implementing the Extension control to return NativeScript views.
You have the following the file in the Extensions
folder: /MyMDKExtensionModule/controls/NSProgressControl.ts
:
//file: NSProgressControl.ts
import { GridLayout, Label, Progress, Button, PropertyChangeData } from '@nativescript/core';
import { IView } from 'mdk-core/IView';
function toNumber(value: any, defaultIfNaN = 0): number {
if ((typeof value !== 'number' && typeof value !== 'string') || (typeof value === 'string' && value.trim().length === 0)) {
return defaultIfNaN;
}
const n = +value;
return isNaN(n) ? defaultIfNaN : n;
}
function toNumberGenerator(defaultIfNaN = 0): (value: any) => number {
return (value: any) => toNumber(value, defaultIfNaN);
}
export class NSProgress extends IView {
private _nsView: GridLayout;
private _progress: Progress;
private _progressValueText: Label;
private _unit = '';
public view(): any {
const defaultMaxValue = 10000;
if (!this._nsView) {
this._nsView = new GridLayout();
(this._nsView as any).rows = 'auto,auto';
(this._nsView as any).columns = 'auto,*,auto';
const headerGrid = new GridLayout();
const progressLabel = new Label();
progressLabel.className = 'progress-label';
const progressValue = new Label();
this._progressValueText = progressValue;
progressValue.className = 'progress-value';
headerGrid.colSpan = 3;
headerGrid.addChild(progressLabel);
headerGrid.addChild(progressValue);
headerGrid.className = 'header-wrapper';
const progress = new Progress();
this._progress = progress;
progress.row = 1;
progress.col = 1;
progress.className = 'progress';
progress.on('valueChange', (evt: PropertyChangeData) => {
this.setValue(evt.value, true, false);
});
const progressMinValueLabel = new Label();
progressMinValueLabel.row = 1;
progressMinValueLabel.col = 0;
progressMinValueLabel.className = 'progress-min-value-label';
progressMinValueLabel.text = "0";
const progressMaxValueLabel = new Label();
progressMaxValueLabel.row = 1;
progressMaxValueLabel.col = 2;
progressMaxValueLabel.className = 'progress-max-value-label';
this._nsView.className = 'wrapper';
this._nsView.addChild(headerGrid);
this._nsView.addChild(progress);
this._nsView.addChild(progressMinValueLabel);
this._nsView.addChild(progressMaxValueLabel);
this._nsView.addCss(`
.wrapper {
padding: 20;
}
.progress-label {
horizontal-align: left;
font-weight: bold;
}
.progress-value {
horizontal-align: right;
}
.header-wrapper {
margin-bottom: 10;
}
.progress {
margin-left: 10;
margin-right: 10;
vertical-align: middle;
}
.progress-min-value-label, .progress-max-value-label {
vertical-align: middle;
}
`);
// set the unit
this.resolve(this.definition().data.ExtensionProperties.Unit).then((unit) => {
this._unit = unit ?? '';
// update the text
this._setProgressValueText(this._progress.value);
});
// set title
this.resolve(this.definition().data.ExtensionProperties.Title).then((v) => {
progressLabel.text = `${v ?? ''}`;
});
// set max value
this.resolve(this.definition().data.ExtensionProperties.MaxValue)
.then(toNumberGenerator(defaultMaxValue))
.then((v) => {
progress.maxValue = v;
progressMaxValueLabel.text = `${v}`;
});
// set start value
this.resolve(this.definition().data.Value).then((v) => {
this.setValue(v, false, false);
});
}
return this._nsView;
}
public viewIsNative() {
return false;
}
public setContainer(container: IControl) {
// do nothing
}
public async setValue(value: any, notify: boolean, isTextValue?: boolean): Promise<any> {
let finalNumber = toNumber(value, NaN);
if (isNaN(finalNumber)) {
throw new Error('Error: Value is not a number');
}
finalNumber = Math.max(0, Math.min(this._progress.maxValue, finalNumber));
this._setProgressValue(finalNumber);
this._setProgressValueText(finalNumber);
}
private resolve(v: any): Promise<any> {
return this.valueResolver().resolveValue(v, this.context);
}
private _setProgressValue(value: number) {
this._progress.value = value;
}
private _setProgressValueText(value: number) {
const roundValue = Math.round(value);
this._progressValueText.text = `${roundValue}${this._unit ? ' ' + this._unit : ''}`;
}
}
Consuming the extension control in your app e.g. in a Section of a Sectioned Table:
{
"Module": "MyMDKExtensionModule",
"Control": "NSProgressControl",
"Class": "NSProgress",
"Height": 200,
"ExtensionProperties": {
"MinValue": 0,
"MaxValue": 100,
"Unit": "mi",
"Title": "Distance"
},
"Value": 10,
"OnPress": "/MDKApp/Actions/ShowMessage.action",
"_Type": "Section.Type.Extension",
"_Name": "MyNSProgress2"
}