Advanced Concepts
Creating Custom Native Elements
What to do when built-in elements don't meet your needs?
When working with view markup in NativeScript, you interact with a set of pre-registered elements, such as GridLayout
, Button
, and Label
. These are commonly referred to as "view components."
You can also create custom native elements or extend existing ones to add specialized functionality to your application.
This guide demonstrates how to:
- Register custom view elements across all NativeScript flavors.
- Implement a simple custom view component, starting from a basic class definition:
import { View } from'@nativescript/core'
exportclassCheckboxextendsView {
// implementation details
}
Registering New Elements β
You could use Checkbox
within XML markup by providing any namespace prefix and the path to it.
<Pagexmlns="http://schemas.nativescript.org/tns.xsd"
xmlns:custom="./checkbox">
<StackLayout>
<custom:Checkboxwidth="200"height="200" />
</StackLayout>
</Page>
The registration can occur anywhere the view is needed or commonly in app.component.ts
, the root bootstrap component, making it available for use anywhere in your application.
import { registerElement } from'@nativescript/angular'
import { Checkbox } from'./checkbox'
registerElement('Checkbox', () => Checkbox)
You can now use it like anything else:
<StackLayout>
<Checkboxwidth="200"height="200" />
</StackLayout>
The registration can be done in the bootsrap file, commonly app.ts
. With Svelte, we use camelCase on elements where applicable.
import { registerNativeViewElement } from'@nativescript-community/svelte-native/dom'
import { Checkbox } from'./checkbox'
registerNativeViewElement('checkbox', () => Checkbox)
You can now use it like anything else:
<stackLayout>
<checkboxwidth="200"height="200" />
</stackLayout>
The registration can be done in the bootsrap file, commonly app.ts
. With React, we use camelCase on elements where applicable.
import { registerElement } from'react-nativescript'
import { Checkbox } from'./checkbox'
registerElement('checkbox', () => Checkbox)
You can now use it like anything else:
<stackLayout>
<checkboxwidth="200"height="200" />
</stackLayout>
The registration can be done in the bootsrap file, commonly app.tsx
.
import { registerElement } from'dominative'
import { Checkbox } from'./checkbox'
registerElement('checkbox', Checkbox)
You can now use it like anything else:
<stacklayout>
<checkboxwidth="200"height="200" />
</stacklayout>
The registration can be done in the bootsrap file, commonly app.ts
.
import { registerElement } from'nativescript-vue'
import { Checkbox } from'./checkbox'
registerElement('Checkbox', () => Checkbox)
You can now use it like anything else:
<StackLayout>
<Checkboxwidth="200"height="200" />
</StackLayout>
Creating Custom View Components β
The process for creating new NativeScript view components is consistent across Angular, React, Solid, Svelte, TypeScript, and Vue.
Anatomy of a Custom View β
Every custom NativeScript view must have:
- (required) A class extending any NativeScript View.
- (required)
createNativeView
: Construct and return a platform-native view. Note: It's only required if you want to override what's being returned from the extended class. - (optional)
initNativeView
: Perform initialization after creation. - (optional)
disposeNativeView
: Cleanup resources when removed.
Example:
import { View } from'@nativescript/core'
exportclassCustomViewextendsView {
createNativeView() {
// return UIView or android.view.View instance
}
initNativeView() {
// initialization code
}
disposeNativeView() {
// cleanup code
}
}
Extending Existing Views β
You can extend any existing NativeScript view, for example:
import { ContentView, Label, Button } from'@nativescript/core'
exportclassCustomView1extendsContentView {}
exportclassCustomView2extendsLabel {}
exportclassCustomView3extendsButton {}
createNativeView
Examples β
This method must return an instance of the native view:
// iOS
createNativeView() {
returnnewWKWebView({ frame: CGRectZero, configuration });
}
// Android
createNativeView() {
returnnew android.webkit.WebView(this._context);
}
Initialization and Cleanup β
initNativeView
: Perform setup after the view has been created.disposeNativeView
: Free resources as needed.
Explore more examples within NativeScript core and plugins:
- Button implementation (iOS)
- Button implementation (Android)
- Custom Flutter view example (iOS)
- Custom Flutter view example (Android)
For additional details on advanced topics like using Cocoapods or Gradle, refer to this blog series.
Project Structure for Custom Views β
Create a dedicated folder for your component, such as:
./checkbox
common.ts
index.android.ts
index.ios.ts
index.d.ts
This structure encapsulates platform-specific implementations and shared logic, simplifying imports and registration:
import { Checkbox } from'./checkbox'
Real-World Example: Custom Checkbox β
Let's create a <Checkbox>
component that behaves consistently on iOS and Android like this:
See the full working example on StackBlitz:
- Angular: https://stackblitz.com/edit/nativescript-create-custom-elements-checkbox?file=src%2Fapp%2Fcheckbox%2Fcommon.ts
- React: https://stackblitz.com/edit/nativescript-create-custom-elements-checkbox-react?file=src%2Fcomponents%2FScreenOne.tsx
- Solid: https://stackblitz.com/edit/nativescript-create-custom-elements-checkbox-solid?file=src%2Fcomponents%2Fhome.tsx
- Svelte: https://stackblitz.com/edit/nativescript-create-custom-elements-checkbox-svelte?file=app%2Fcomponents%2FHome.svelte
- TypeScript: https://stackblitz.com/edit/nativescript-create-custom-elements-checkbox-ts?file=app%2Fmain-page.xml
- Vue: https://stackblitz.com/edit/nativescript-create-custom-elements-checkbox-vue?file=src%2Fcomponents%2FHome.vue
In NativeScript, creating custom UI components can be straightforward and powerful. In this guide, you'll learn how to build a simple, reusable Checkbox component using only built-in modules from @nativescript/core
. We'll leverage a combination of GridLayout
, Label
, and Material Design icons.
Step-by-Step Guide β
1. Extend GridLayout
β
The base structure of our Checkbox will utilize GridLayout
, which serves as a container for the checkbox icon:
import { GridLayout } from'@nativescript/core'
exportclassCheckboxCommonextendsGridLayout {}
2. Initialize Checkbox with a Font Icon β
Next, we'll add a Label to serve as our checkbox icon, using Material Design icons for the visual representation.
import { GridLayout, Label, Color } from'@nativescript/core'
exportclassCheckboxCommonextendsGridLayout {
checked=false
defaultColor=newColor('#dddddd')
selectionColor=newColor('#4CAF50')
private_iconLabel:Label
private_circleIcon= String.fromCharCode(0xf764)
private_checkmarkIcon= String.fromCharCode(0xf5e0)
constructor() {
super()
this.horizontalAlignment ='center'
this.verticalAlignment ='middle'
this._iconLabel =newLabel()
this._iconLabel.text =this._circleIcon
this._iconLabel.className ='mat'
this._iconLabel.color =this.defaultColor
this._iconLabel.horizontalAlignment ='center'
this._iconLabel.verticalAlignment ='middle'
this.addChild(this._iconLabel)
}
}
Include Material Design Icons in your project by adding this CSS class in your app.css
:
.mat {
font-family: 'Material Design Icons', 'MaterialDesignIcons';
font-weight: 400;
}
Ensure you've added the MaterialDesignIcons font file to your app's fonts
directory.
3. Implementing Animation β
To enhance user interaction, add a simple scaling animation when toggling the checkbox state:
import { CoreTypes } from'@nativescript/core'
exportclassCheckboxCommonextendsGridLayout {
// existing properties and constructor...
private_animateCheckmark() {
if (!this.checked) {
this._iconLabel.color =this.defaultColor
}
this._iconLabel
.animate({
scale: { x: 0.5, y: 0.5 },
duration: 200,
curve: CoreTypes.AnimationCurve.easeInOut,
})
.then(() => {
this._iconLabel.text =this.checked
?this._checkmarkIcon
:this._circleIcon
if (this.checked) {
this._iconLabel.color =this.selectionColor
}
this._iconLabel.animate({
scale: { x: 1, y: 1 },
duration: 200,
curve: CoreTypes.AnimationCurve.easeInOut,
})
})
}
}
4. Defining Customizable Properties β
NativeScript's Property
system allows you to easily expose customizable attributes:
constsizeProperty=newProperty<CheckboxCommon, number>({
name: 'size',
defaultValue: 24,
affectsLayout: __APPLE__,
})
constcheckedProperty=newProperty<CheckboxCommon, boolean>({
name: 'checked',
defaultValue: false,
valueConverter: booleanConverter,
})
constdefaultColorProperty=newProperty<CheckboxCommon, Color>({
name: 'defaultColor',
equalityComparer: Color.equals,
valueConverter: (v) =>newColor(v),
})
constselectionColorProperty=newProperty<CheckboxCommon, Color>({
name: 'selectionColor',
equalityComparer: Color.equals,
valueConverter: (v) =>newColor(v),
})
These properties automatically handle conversions, such as strings to colors or booleans.
5. Connecting Properties to Native Views β
Link these properties to your checkbox component:
exportclassCheckboxCommonextendsGridLayout {
// existing implementation...
[sizeProperty.setNative](value:number) {
this._iconLabel.fontSize = value
}
[checkedProperty.setNative](value:boolean) {
this.checked = value
if (this.isLoaded) {
this._animateCheckmark()
}
}
[defaultColorProperty.setNative](value:Color) {
this.defaultColor = value
if (this._iconLabel) {
this._iconLabel.color =this.defaultColor
}
}
[selectionColorProperty.setNative](value:Color) {
this.selectionColor = value
}
}
// Register properties
sizeProperty.register(CheckboxCommon)
checkedProperty.register(CheckboxCommon)
defaultColorProperty.register(CheckboxCommon)
selectionColorProperty.register(CheckboxCommon)
Complete Example and Testing β
Explore and interact with the complete example directly in the flavor you love:
- Angular: https://stackblitz.com/edit/nativescript-create-custom-elements-checkbox?file=src%2Fapp%2Fcheckbox%2Fcommon.ts
- React: https://stackblitz.com/edit/nativescript-create-custom-elements-checkbox-react?file=src%2Fcomponents%2FScreenOne.tsx
- Solid: https://stackblitz.com/edit/nativescript-create-custom-elements-checkbox-solid?file=src%2Fcomponents%2Fhome.tsx
- Svelte: https://stackblitz.com/edit/nativescript-create-custom-elements-checkbox-svelte?file=app%2Fcomponents%2FHome.svelte
- TypeScript: https://stackblitz.com/edit/nativescript-create-custom-elements-checkbox-ts?file=app%2Fmain-page.xml
- Vue: https://stackblitz.com/edit/nativescript-create-custom-elements-checkbox-vue?file=src%2Fcomponents%2FHome.vue
Summary β
Creating custom components in NativeScript allows you to:
- Build complex components from simple elements
- Utilize powerful styling and animations
- Easily manage and expose customizable properties
Whether creating fully native views or hybrid custom components, NativeScript provides flexibility and efficiency to meet your application's needs.
Customize Existing Elements? β
Rather than create new elements from scratch, you may want to just adjust existing view elements. Learn about how to extend any element for custom behavior here.
- Previous
- iOS
- Registering New Elements
- Creating Custom View Components
- Project Structure for Custom Views
- Real-World Example: Custom Checkbox
- Customize Existing Elements?
Contributors
Last updated: