UNPKG

@nativescript/keyboard-toolbar

Version:
226 lines 10.8 kB
import { Screen, CoreTypes, Page, TabView, Utils, Frame } from '@nativescript/core'; import { ToolbarBase } from './common'; export class Toolbar extends ToolbarBase { // private onScrollChangedListener: android.view.ViewTreeObserver.OnScrollChangedListener; constructor() { super(); this.verticalAlignment = CoreTypes.VerticalAlignment.top; } _loaded() { setTimeout(() => this.applyInitialPosition(), 300); setTimeout(() => { const prepFocusEvents = (forView) => { forView.on('focus', () => { this.hasFocus = true; if (that.lastKeyboardHeight) { this.showToolbar(this.content.parent); } }); forView.on('blur', () => { this.hasFocus = false; this.hideToolbar(this.content.parent); }); }; let pg; if (Frame.topmost()) { pg = Frame.topmost().currentPage; } else { pg = this.content.parent; while (pg && !(pg instanceof Page)) { pg = pg.parent; } } this.thePage = pg; const forView = this.thePage.getViewById(this.forId); if (forView) { prepFocusEvents(forView); return; } // let's see if we're inside a tabview, because of https://github.com/EddyVerbruggen/nativescript-keyboard-toolbar/issues/7 let p = this.thePage.parent; while (p && !(p instanceof TabView)) { p = p.parent; } if (p instanceof TabView) { p.on(TabView.selectedIndexChangedEvent, () => { let forView2 = p.getViewById(this.forId); if (forView2) { prepFocusEvents(forView2); p.off(TabView.selectedIndexChangedEvent); } }); } else { console.log(`\n⌨ ⌨ ⌨ Please make sure forId="<view id>" resolves to a visible view, or the toolbar won't render correctly! Example: <Toolbar forId="${this.forId || 'myId'}" height="44">\n\n`); } }, 500); const that = this; this.onGlobalLayoutListener = new android.view.ViewTreeObserver.OnGlobalLayoutListener({ onGlobalLayout() { // this can happen during livesync - no problemo if (!that.content.android) { return; } const rect = new android.graphics.Rect(); that.content.android.getWindowVisibleDisplayFrame(rect); const newKeyboardHeight = (Toolbar.getUsableScreenSizeY() - rect.bottom) / Screen.mainScreen.scale; if (newKeyboardHeight <= 0 && that.lastKeyboardHeight === undefined) { return; } if (newKeyboardHeight === that.lastKeyboardHeight) { return; } // TODO see if orientation needs to be accounted for: https://github.com/siebeprojects/samples-keyboardheight/blob/c6f8aded59447748266515afeb9c54cf8e666610/app/src/main/java/com/siebeprojects/samples/keyboardheight/KeyboardHeightProvider.java#L163 that.lastKeyboardHeight = newKeyboardHeight; if (that.hasFocus) { if (newKeyboardHeight <= 0) { that.hideToolbar(that.content.parent); } else { that.showToolbar(that.content.parent); } } }, }); that.content.android.getViewTreeObserver().addOnGlobalLayoutListener(that.onGlobalLayoutListener); // that.content.android.getViewTreeObserver().addOnScrollChangedListener(that.onScrollChangedListener); } _unloaded() { this.content.android.getViewTreeObserver().removeOnGlobalLayoutListener(this.onGlobalLayoutListener); // this.content.android.getViewTreeObserver().removeOnScrollChangedListener(this.onScrollChangedListener); this.onGlobalLayoutListener = undefined; // this.onScrollChangedListener = undefined; } showToolbar(parent) { let navbarHeight = this.isNavbarVisible ? 0 : this.navbarHeight; // some devices (Samsung S8) with a hidden virtual navbar show the navbar when the keyboard is open, so subtract its height if (!this.isNavbarVisible) { const isNavbarVisibleWhenKeyboardOpen = this.thePage.getMeasuredHeight() < Toolbar.getUsableScreenSizeY() && (Toolbar.isVirtualNavbarHidden_butShowsWhenKeyboardIsOpen() || Toolbar.hasPermanentMenuKey()); if (isNavbarVisibleWhenKeyboardOpen) { // caching for (very minor) performance reasons if (!this.navbarHeightWhenKeyboardOpen) { this.navbarHeightWhenKeyboardOpen = Toolbar.getNavbarHeightWhenKeyboardOpen(); } navbarHeight = this.navbarHeightWhenKeyboardOpen; } } const animateToY = this.startPositionY - this.lastKeyboardHeight - (this.showWhenKeyboardHidden === true ? 0 : this.lastHeight / Screen.mainScreen.scale) - navbarHeight; parent .animate({ translate: { x: 0, y: animateToY }, curve: CoreTypes.AnimationCurve.cubicBezier(0.32, 0.49, 0.56, 1), duration: 370, }) .then(() => { }); } hideToolbar(parent) { const animateToY = this.showWhenKeyboardHidden === true && this.showAtBottomWhenKeyboardHidden !== true ? 0 : this.startPositionY + this.navbarHeight; // console.log("hideToolbar, animateToY: " + animateToY); parent .animate({ translate: { x: 0, y: animateToY }, curve: CoreTypes.AnimationCurve.cubicBezier(0.32, 0.49, 0.56, 1), duration: 370, }) .then(() => { }); } applyInitialPosition() { if (this.startPositionY !== undefined) { return; } const parent = this.content.parent; // at this point, topmost().currentPage is null, so do it like this: this.thePage = parent; while (!this.thePage && !this.thePage.frame) { this.thePage = this.thePage.parent; } const loc = parent.getLocationOnScreen(); if (!loc) { return; } const y = loc.y; const newHeight = parent.getMeasuredHeight(); // this is the bottom navbar - which may be hidden by the user.. so figure out its actual height this.navbarHeight = Toolbar.getNavbarHeight(); this.isNavbarVisible = !!this.navbarHeight; this.startPositionY = Screen.mainScreen.heightDIPs - y - (this.showWhenKeyboardHidden === true ? newHeight : 0) / Screen.mainScreen.scale - (this.isNavbarVisible ? this.navbarHeight : 0); if (this.lastHeight === undefined) { // this moves the keyboardview to the bottom (just move it offscreen/toggle visibility(?) if the user doesn't want to show it without the keyboard being up) if (this.showWhenKeyboardHidden === true) { if (this.showAtBottomWhenKeyboardHidden === true) { parent.translateY = this.startPositionY; } } else { parent.translateY = this.startPositionY + this.navbarHeight; } } else if (this.lastHeight !== newHeight) { parent.translateY = this.startPositionY + this.navbarHeight; } this.lastHeight = newHeight; } static getNavbarHeight() { // detect correct height from: https://shiv19.com/how-to-get-android-navbar-height-nativescript-vanilla/ const context = Utils.android.getApplicationContext(); let navBarHeight = 0; let windowManager = context.getSystemService(android.content.Context.WINDOW_SERVICE); let d = windowManager.getDefaultDisplay(); let realDisplayMetrics = new android.util.DisplayMetrics(); d.getRealMetrics(realDisplayMetrics); let realHeight = realDisplayMetrics.heightPixels; let realWidth = realDisplayMetrics.widthPixels; let displayMetrics = new android.util.DisplayMetrics(); d.getMetrics(displayMetrics); let displayHeight = displayMetrics.heightPixels; let displayWidth = displayMetrics.widthPixels; if (realHeight - displayHeight > 0) { // Portrait navBarHeight = realHeight - displayHeight; } else if (realWidth - displayWidth > 0) { // Landscape navBarHeight = realWidth - displayWidth; } // Convert to device independent pixels and return return navBarHeight / context.getResources().getDisplayMetrics().density; } static getNavbarHeightWhenKeyboardOpen() { const resources = Utils.android.getApplicationContext().getResources(); const resourceId = resources.getIdentifier('navigation_bar_height', 'dimen', 'android'); if (resourceId > 0) { return resources.getDimensionPixelSize(resourceId) / Screen.mainScreen.scale; } return 0; } static hasPermanentMenuKey() { const permMenuKey = Utils.android.getApplicationContext().hasPermanentMenuKey; if (permMenuKey) { return android.view.ViewConfiguration.get(permMenuKey); } return null; } static isVirtualNavbarHidden_butShowsWhenKeyboardIsOpen() { if (Toolbar.supportVirtualKeyboardCheck !== undefined) { return Toolbar.supportVirtualKeyboardCheck; } const SAMSUNG_NAVIGATION_EVENT = 'navigationbar_hide_bar_enabled'; try { // eventId is 1 in case the virtual navbar is hidden (but it shows when the keyboard opens) Toolbar.supportVirtualKeyboardCheck = android.provider.Settings.Global.getInt(Utils.android.getCurrentActivity().getContentResolver(), SAMSUNG_NAVIGATION_EVENT) === 1; } catch (e) { // non-Samsung devices throw a 'SettingNotFoundException' console.log('>> e: ' + e); Toolbar.supportVirtualKeyboardCheck = false; } return Toolbar.supportVirtualKeyboardCheck; } static getUsableScreenSizeY() { const screenSize = new android.graphics.Point(); Utils.android.getCurrentActivity().getWindowManager().getDefaultDisplay().getSize(screenSize); return screenSize.y; } } //# sourceMappingURL=index.android.js.map