NativeScript Hacks- Here are mine, share yours


#1

Here are few hacks I learned since I start learning NativeScript a short while ago, If you have any other hacks then please share them to expand this list:


  • Vertically align text inside Label on Android (on iOS vertical-align: center; works fine)
    add loaded event to a label
<Label text="Text to be centre inside its container" loaded="centerMe"/>
function centerMe(event) {
    if (event.object.android) {
        event.object.android.setGravity(17);
    };
}
exports.centerMe = centerMe;

The numbers are:
17: center of its container in both the vertical and horizontal
1: horizontal center of its container
16: vertical center of its container
OR
Set the padding accordingly to the (width - font-size) / 2


  • Remove borders from Android button, just add the following to your button css class
    border-width: 0.1;

  • Dismiss a keyboard autofocusing on SearchBar when navigating to a page. add loaded event to the SearchBar
<SearchBar id="mainSearchBar" hint="Search products" loaded="onSearchBarLoaded"/>
function onSearchBarLoaded(event) {
    if (event.object.android) {
        event.object.dismissSoftInput();
        event.object.android.clearFocus();
    } else if (event.object.ios) {
        event.object.dismissSoftInput();
        event.object.ios.endEditing(true);
    }
}
exports.onSearchBarLoaded = onSearchBarLoaded;

  • Avoid using <StackLayout class="hr-light"></StackLayout> for divider since containers are costly performance wise, instead use label with set hight and background color or set border-width and color for one side of your components when you can

  • Using FormattedString to create multiline labels (&#xa; is hex for new line. you can search all hex here)
<Label textWrap="true" >
    <Label.formattedText>
        <FormattedString>
            <FormattedString.spans>
                <Span text="John Smith &#xa;" class="font-weight-bold" fontSize="15"/>
                <Span text="Phone: 905-567-7766" class="footnote"/>
            </FormattedString.spans>
        </FormattedString>
        </Label.formattedText> 
</Label>

Lets keep this list growing, please shear your hacks


#2

Also, feel free to create a cool Playground hack and submit it to nativescriptsnacks.com!


#3

Or you can use
android.view.Gravity. followed by one of the enums

listed in this link https://developer.android.com/reference/android/view/Gravity.html


#4

that’s a neat trick!


#5

Switch UI

In iOS the Switch doesn’t style properly with the exposed {N} properties, so I use this in NAN:

const switchEl = this.switchEl.nativeElement as Switch;
if (switchEl) {
    switchEl.ios.backgroundColor = new Color('#E6E6E6').ios;
    switchEl.ios.hintColor = new Color('#E6E6E6').ios;
    switchEl.ios.layer.cornerRadius = 16;
}

Horizontal Separators

I never use StackLayouts for these, as it’s expensive to render a container for something that can be accomplished with:

<Label height="1" margin="10 0" backgroundColor="black" width="100%"></Label>

You can just make that into a css class and use the class name instead.

Lazy-Loaded Modules break Navigation with Clear History (NAN)

There’s a terrible bug with the NativeScript Angular page-router-outlet logic that causes change detection to fail to execute after navigating from a lazy-loaded module to another top-level lazy-loaded module with the clearHistory flag. To get around this, you need to run the navigation even in a zone.

this.zone.run(() => {
   this.routerExt.navigate(['/app/dashboard/user'], { clearHistory: true });
});

setTimeout

Use it for pretty much any time change detection fails, {N} behaves inconsistently, UI thread gets locked up with execution of other items.

Phone Directive (NAN)

Only renders the container if the device is a phone.

import { Directive, ViewContainerRef, ElementRef } from '@angular/core';
import { isPhone } from '../../core/utils/device';
import { View } from 'tns-core-modules/ui/frame';
/**
 * Helper directive to only display specific containers for phone devices
 */
@Directive({
    selector: '[isPhone]', // tslint:disable-line:directive-selector
})
export class PhoneDirective {

    constructor(
        private elementRef: ElementRef,
        private viewContainer: ViewContainerRef) {
        if (!isPhone) {
            this.destroyContainer();
        }
    }

    private destroyContainer() {
        this.viewContainer.clear();
        if (this.elementRef) {
            const element = this.elementRef.nativeElement as View;
            if (element) {
                element.parent._removeView(element);
            }
        }
    }

}

where the device file is:

import * as platform from 'tns-core-modules/platform';
import * as enums from 'tns-core-modules/ui/enums';

export const isPhone = platform.device && platform.device.deviceType === enums.DeviceType.Phone;
export const isTablet = platform.device && platform.device.deviceType === enums.DeviceType.Tablet;

You can do the inverse for only tablet devices.

Tap-off Events

You can use an AbsoluteLayout to detect when the user taps “off” your pop-up items, like a drop down. To do this you just need to render the AbsoluteLayout first and then render your customer UI over-top it. Any space not consumed by your customer UI will emit the tap event when pressed.

<GridLayout rows="*">
    <AbsoluteLayout row="0"
            width="100%"
            height="100%"
            backgroundColor="transparent"
            (tap)="closeFilter()"></AbsoluteLayout>
   <Label row="0" text="MY CUSTOM UI" (tap)="anotherEvent()"></Label>
</GridLayout>

I have about 99999999 more. Too many for this thread.


#6

Like the idea of the Tap-off events, and totally agree setTimeout always comes to the rescue when ui doesn’t behave as expected


#7

My detailed implementation for this is like

<Label text="I'm a label" loaded="alignMe" gravity="16 3" />
function alignMe(event) {
    let g = event.object.gravity.split(" ");
    if (event.object.android) {
        event.object.android.setGravity(g[0] | g[1]);
    };
}
exports.alignMe = alignMe;

In this case, it will be vertically aligned to centre and horizontally to the left. However, this is stupid hack and I hope the vertical-align in css for android gets fixed