npm install @nativescript/keyboard-toolbar
Thank you to Eddy Verbruggen for all the excellent work!
iOS and Android running the included demo - much better framerate on YouTube!
Glad you asked 😅!
@nativescript/core
(which your app already has).The plugin works by grabbing your declared toolbar layout and moving it off-screen.
Then, whenever the related TextField
or TextView
received focus, the plugin animates the toolbar to the top of the keyboard and keeps it there until the field loses focus.
For this to behave properly you'll need to grab any layout you currently have and wrap it in a GridLayout
as show in the examples below. The GridLayout
allows for stacking multiple child layout on top of each other when their row
and col
properties are equal (or omitted).
So if your layout structure is currently this:
<ActionBar/>
<StackLayout/>
Change it to this:
<ActionBar/>
<GridLayout>
<StackLayout/>
<Toolbar/>
</GridLayout>
Not too bad, right? That will make the Toolbar
stack on top of the StackLayout
you already had.
Note that the plugin could have done this for you, or take some other approach entirely, but many hours of tinkering has convinced me this is the best solution.
Mind the comments in the example below.
<Page
xmlns="http://schemas.nativescript.org/tns.xsd"
xmlns:kt="@nativescript/keyboard-toolbar"
>
<!-- This GridLayout wrapper is required; it wraps the visible layout and the Toolbar layout(s) -->
<GridLayout>
<StackLayout>
<Label text="Some text" />
<!-- Add an 'id' property that we can reference below -->
<TextField id="priceTextField" hint="Enter the price" keyboardType="number" />
</StackLayout>
<!-- The 'forId' and 'height' properties are mandatory -->
<kt:Toolbar forId="priceTextField" height="44">
<GridLayout columns="*, *, *" class="toolbar">
<Label col="0" text="👍" tap="{{ appendToTextView }}" />
<Label col="1" text="👎" tap="{{ appendToTextView }}" />
<Label col="2" text="😄" tap="{{ appendToTextView }}" />
</GridLayout>
</kt:Toolbar>
</GridLayout>
</Page>
Register the plugin in a specific module, or globally in the app module:
import { registerElement } from '@nativescript/angular'
import { Toolbar } from 'nativescript-keyboard-toolbar'
registerElement('KeyboardToolbar', () => Toolbar)
In this example, we're adding a TextField
to the ActionBar
. Note that we still need to wrap the rest of the page in a GridLayout
:
<ActionBar>
<TextField #textField1 id="tf1"></TextField>
</ActionBar>
<!-- Our Toolbar wrapper - no need for 'columns' / 'rows' properties because we want the children to stack -->
<GridLayout>
<!-- Add whatever visible layout you need here -->
<ListView [items]="items">
<ng-template let-item="item">
<label
[nsRouterLink]="['/item', item.id]"
[text]="item.name"
class="list-group-item"
></label>
</ng-template>
</ListView>
<!-- Use 'KeyboardToolbar' because that's what we registered in our module (see above).
The 'forId' and 'height' properties are mandatory -->
<KeyboardToolbar forId="tf1" height="44">
<GridLayout columns="*, *, *, auto" class="toolbar">
<label col="0" text="👍" (tap)="appendToTextField(textField1, '👍')"></label>
<label col="1" text="👎" (tap)="appendToTextField(textField1, '👎')"></label>
<label col="2" text="😄" (tap)="appendToTextField(textField1, '😄')"></label>
<label col="3" text="Close️" (tap)="closeKeyboard(textField1)"></label>
</GridLayout>
</KeyboardToolbar>
</GridLayout>
Register the plugin in app.js
(or depending on your app's setup: app.ts
, or main.js
, etc):
import Vue from 'nativescript-vue'
Vue.registerElement(
'KeyboardToolbar',
() => require('nativescript-keyboard-toolbar').Toolbar
)
<template>
<Page class="page">
<ActionBar class="action-bar">
<Label class="action-bar-title" text="Home"></Label>
</ActionBar>
<!-- Our Toolbar wrapper - no need for 'columns' / 'rows' properties because we want the children to stack -->
<GridLayout>
<StackLayout>
<TextView id="tv2" text="Say it with emoji!" />
</StackLayout>
<!-- Use 'KeyboardToolbar' because that's what we registered in our module (see above).
The 'forId' and 'height' properties are mandatory -->
<KeyboardToolbar forId="tv2" height="44">
<GridLayout columns="*, *, *" class="toolbar">
<Label col="0" text="👍" @tap="appendToTextView2" />
<Label col="1" text="👎" @tap="appendToTextView2" />
<Label col="2" text="😄" @tap="appendToTextView2" />
</GridLayout>
</KeyboardToolbar>
</GridLayout>
</Page>
</template>
<script>
import { Frame } from '@nativescript/core'
export default {
methods: {
appendToTextView2(args) {
const textView = Frame.topmost().currentPage.getViewById('tv2')
textView.text += args.object.text
}
}
}
</script>
If you have IQKeyboardManager installed for better keyboard behavior on iOS, then this plugin will detect it and add the height of your custom toolbar to the scroll offset IQKeyboardManager applies. You can see this in action in the NativeScript Core demo app.
You may want to suppress IQKeyboardManager's own toolbar in this case (to avoid a double toolbar), as shown here.
Apache License Version 2.0