How to vertically fill space between elements in ScrollView while preserving scrolling - nativescript

I am trying to achieve the following:
I tried achieving this with a GridLayout and only get one of the following two things working:
The space between the Label and the StackLayout is filled (label is
stretched), but scrolling will not work when adding more labels into
the StackLayout
Scrolling will work when more labels are added into
the StackLayout, but when only one label is showed for example, the
label before the StackLayout will not stretch
Is there any way to achieve such a thing? GridLayout is not necessarily needed, but I tried several ways and could not find any way of doing this.
example code of (1)
<Page class="page dark">
<ScrollView backgroundColor="red">
<GridLayout rows="*, auto" height="100%" backgroundColor="blue">
<Label backgroundColor="green">Top Label</Label>
<StackLayout row="1" backgroundColor="green">
<Label backgroundColor="purple">Label A</Label>
<Label backgroundColor="purple">Label B</Label>
</StackLayout>
</GridLayout>
</ScrollView>
</Page>
example code of (2):
<Page class="page dark">
<ScrollView backgroundColor="red">
<GridLayout rows="*, auto" backgroundColor="blue">
<Label backgroundColor="green">Top Label</Label>
<StackLayout row="1" backgroundColor="green">
<Label backgroundColor="purple">Label A</Label>
<Label backgroundColor="purple">Label B</Label>
</StackLayout>
</GridLayout>
</ScrollView>
</Page>

I wanted to achieve this for months and I finally found a working solution, for iOS and Android.
The solution is to use FlexboxLayout instead of GridLayout. When placed in a ScrollView, FlexboxLayout will take the whole available height if it is not tall enough. If it is taller than the ScrollView, it will be scrollable.
Here is the solution for your example:
<Page class="page dark">
<ScrollView backgroundColor="red">
<FlexboxLayout
flexDirection="column"
justifyContent="space-between"
alignItems="stretch"
backgroundColor="blue"
>
<Label backgroundColor="green">Top Label</Label>
<StackLayout backgroundColor="green">
<Label backgroundColor="purple">Label A</Label>
<Label backgroundColor="purple">Label B</Label>
</StackLayout>
</FlexboxLayout>
</ScrollView>
</Page>

Related

How to fix android ui performance

I'm getting:
Avoid using ListView or ScrollView with no explicit height set inside StackLayout. Doing so might results in poor user interface performance and a poor user experience.
My UI performance is very crappy on Android. It seems pretty smooth on iOS. I'm trying to figure out what could be the issue. This one error crops up for me. I'm running "nativescript-angular": "^8.0.0",
<ScrollView [visibility]="isBusy ? 'collapsed' : 'visible'" #sv>
<GridLayout rows="auto,auto,auto,auto" id="t2" columns="*" class="template_body">
<GridLayout row="0" col="0" #wv1wrapper>
<!-- <web-view id="instruction-wv" #wv1></web-view> -->
<template-text [data]="lessonDetail.instruction" *ngIf="lessonDetail.instruction" [screenwidth]="screenWidth"></template-text>
</GridLayout>
<StackLayout row="1" col="0" class="main-img">
<Image [src]="(lesson$ | async)?.thumbUrl" #imgref [data-image]="(lesson$ | async)?.imageUrl" (tap)="modalImage($event);"></Image>
</StackLayout>
<GridLayout row="2" col="0" #wvwrapper>
<!-- <web-view id="wv" #wv></web-view> -->
<template-text [data]="lessonDetail.body_text" [version]="version" *ngIf="lessonDetail.body_text" [screenwidth]="screenWidth"></template-text>
</GridLayout>
</GridLayout>
This is a template that is pulled into a router-outlet that looks like this in the master template:
<FlexboxLayout class="contentbody" [visibility]="isBusy ? 'hidden' : 'visible'" [data-template]="template_id">
<Label [text]="error" *ngIf="error"></Label>
<router-outlet></router-outlet>
</FlexboxLayout>
Also on that page, I do have a listview inside of a stacklayout.
<StackLayout row="0" >
<StackLayout class="vocab-notes">
<Label *ngIf="vocabArray" class="h3 section-title" text="Vocabulary"></Label>
<ListView [items]="vocabArray" id="vocablistview" (itemTap)="onItemTap($event)" class="list-items">
<ng-template let-item="item" let-i="index" let-odd="odd" let-even="even">
<GridLayout columns="*" rows="auto,auto" [class.odd]="odd" [class.even]="even" class="vocab-list">
<FlexboxLayout col="0" row="0" class="vocab-list-item-layout">
<Label [text]='item.label' textWrap="true" [id]="item.id" class="h3 vocab-list-item" (tap)="showVocab($event)"></Label>
</FlexboxLayout>
</GridLayout>
</ng-template>
</ListView>
</StackLayout>
I know its late for you but if someone is looking for this in future, so if you are getting below in console on any page you load.
JS: Avoid using ListView or ScrollView with no explicit height set inside StackLayout. Doing so might results in poor user interface performance and a poor user experience.
You just need to give your scrollView a height, try different heights like in my case I need 650
<Page class="main" actionBarHidden="true">
<StackLayout class="gradient-bg">
<ScrollView orientation="vertical" height="650"> <!-- Here height is 650 -->
<StackLayout>
<GridLayout rows="50" class="page-header">
<Label
row="0"
class="fa label-back"
:text="'fa-arrow-left' | fonticon"
v-on:tap="navigateTo('app')"
/>
<Label text="Plot Suggestion" row="0" class="lbl-heading" horizontalAlignment="center" />
...
...

StackLayout's vertical alignment

I'm trying to put a button at the bottom of a StackLayout and it's not working.
I don't know what I'm doing wrong!
Here's my template:
<Page actionBarHidden="true">
<GridLayout rows="*, *, *, *" columns="*">
<StackLayout horizontalAlignment="center"
verticalAlignment="center">
<Label text="My Account" id="login-label"/>
</StackLayout>
<CardView row="1" class="cardStyle" margin="10"
elevation="40"
radius="4"
verticalAlignment="center"
horizontalAlignment="center"
rowSpan="2"
id="login-box">
<StackLayout id="form-container">
<TextField hint="Login"/>
<TextField hint="Password"/>
<Label text="Forgot password?" horizontalAlignment="right"/>
<Button text="Button" #tap="loginButton()" verticalAlignment="bottom"/>
</StackLayout>
</CardView>
</GridLayout>
</Page>
Thank you!
StackLayout do not support that by its design. It is used to just stack the child elements one after another in given orientation, you can't have mixed output - few child elements at top and few at bottom or center.
Use Grid / Dock layout in order to dock an element at bottom.

How to customize tabview in nativescript?

How can i dock my Tabview items to the left of the screen like in the image below?
This is how my layout looks like currently.
<TabView dock="left" tabsBackgroundColor="red" selectedIndex="1" selectedColor="#FF0000" iosIconRenderingMode="alwaysOriginal" sdkExampleTitle sdkToggleNavButton>
<StackLayout tabsBackgroundColor="red" *tabItem="{ iconSource: 'res://ic_ham'}" >
</StackLayout>
<StackLayout *tabItem="{title: 'Home'}">
<ns-home></ns-home>
</StackLayout>
<StackLayout *tabItem="{title: 'Bookings'}">
<ns-booking></ns-booking>
</StackLayout>
</TabView>
Resulting layout
It may be a bit of overkill for your needs, but what I've found simplest for us was to change the tab buttons to be fully designable and customizable by disabling the current buttons and the add new tab buttons.
<StackLayout class="grid-tab-view" columns="*,100,100,100,*" ios:rows="auto, auto" android:rows="auto, *">
<label row="0" col="1" class="tab-button" text="Tab1" (tap)="switchTabByIndex(0)" [ngClass]="{'selected': tabSelectedIndex===0}"></label>
<label row="0" col="2" class="tab-button" text="Tab2" (tap)="switchTabByIndex(1)" [ngClass]="{'selected': tabSelectedIndex===1}"></label>
<label row="0" col="3" class="tab-button" text="Tab3" (tap)="switchTabByIndex(2)" [ngClass]="{'selected': tabSelectedIndex===2}"></label>
<TabView colSpan="5" row="1" col="0" #tabView class="tab-view" [(ngModel)]="tabSelectedIndex" (loaded)="onTabsLoaded()" (selectedIndexChanged)="onTabSwitch($event)">
<StackLayout class="tab" *tabItem="{title: 'Tab1'}">
<Label text="tab1 body"></Label>
</StackLayout>
<StackLayout class="tab" *tabItem="{title: 'Tab2'}">
<Label text="tab2 body"></Label>
</StackLayout>
<StackLayout class="tab" *tabItem="{title: 'Tab3'}">
<Label text="tab3 body"></Label>
</StackLayout>
</TabView>
</StackLayout>
And in code:
Add tap event handlers for when button selected and give it a custom selected class (for styling)
Hide the default tab buttons using the tabs loaded event:
onTabsLoaded(): void{
let tabViewElement = <TabView>this.tabView.nativeElement;
if (tabViewElement && tabViewElement.android) {
tabViewElement.android.removeViewAt(0);
} else {
tabViewElement.ios.tabBar.hidden = true;
}
};
and with a bit of css, our result:
Hope this helps, good luck!

why Listview is not scroll-able inside scrollview in nativescrit angular2

# I am using listview inside the Scrollview but listview is not scrollable inside the scrollview as top parent view
component.html
<ScrollView>
<StackLayout class="zindex">
<!--<AutoComplete [items]="ArrayVillage" (itemTap)="itemTapped($event)"> </AutoComplete>-->
<SearchBar row="0" #sb hint="Search for a country and press enter" (clear)="onClear()" [text]="searchPhrase" (submit)="onSubmit(sb.text)"></SearchBar>
<ListView row="1" [items]="myItems" class="list-group">
<template let-item="item">
<GridLayout class="item" class="list-group-item">
<Label [text]="item.name" class="list-group-item-heading"></Label>
</GridLayout>
</template>
</ListView>
</StackLayout>
<ScrollView>
Try Using Repeater instead of ListView as mentioned in https://docs.nativescript.org/cookbook/ui/repeater. Following is an example of how you can include Repeater inside a ScrollView and can obtain whole layout as scrollable.
<ScrollView>
<StackLayout class="margin">
<Label text="{{ description }}"></Label>
<Repeater items="{{ options }}" row="1">
<Repeater.itemTemplate>
<StackLayout>
<Label text="{{ description }}"></Label>
</StackLayout>
</Repeater.itemTemplate>
</Repeater>
</StackLayout>
</ScrollView>
Trying it by wrapping the scrollview into a AbsoluteLayout
<AbsoluteLayout>
<ScrollView>
<StackLayout class="zindex">
//Rest of stuff
</StackLayout>
<ScrollView>
</AbsoluteLayout>
Having a scrollview inside other one is not a good practice. It doesn't work beacuse scrollview tries to calculate the infinite view and do it with a scrollable inside could work just in some cases having control of the parent view, but don't go that painfull way.
In your code I have a question, why would you want to scroll the SearchBar? Try this structure I think is what you want.
<StackLayout>
<SearchBar></SearchBar>
<ListView>
<template>
<GridLayout >
<Label ></Label>
</GridLayout>
</template>
</ListView>
The SearchBar is fixed and the List scrolllable
Look at the video, play with the emulator and you will see that at the beggining it seems to work but is the "computer mouse scroll" when you use click trying to scroll it doesn't work anymore and is because the screen doesn't know which scrollable element has to scroll.
To do 2 scrollable parts can be a solution, as shown in the end of the video (I implemented in Nativescript with Javascript because I'm working in a project but is almost the same)
<StackLayout>
<Label fontSize="20" color="blue" text="You can do two scrollable parts" textWrap="true" />
<Button text="to" />
<ListView items="{{ items }}" height="300" loaded="onLoaded" itemLoading="onItemLoading" itemTap="onItemTap">
<ListView.itemTemplate>
<Label text="{{ name }}" textWrap="true" />
</ListView.itemTemplate>
</ListView>
<ScrollView>
<StackLayout>
<Button text="1" />
<Button text="2" />
<Button text="3" />
<Button text="4" />
<Button text="5" />
<Button text="6" />
<Button text="3" />
<Button text="4" />
<Button text="5" />
<Button text="6" />
</StackLayout>
</ScrollView>
</StackLayout>

Get a TextView to scroll

I've got a TextView inside a GridLayout and have it set to take maximum available height. That works.
But If the user presses new-line to the bottom of the TextView and more - the TextView cursor goes off the bottom of the screen instead of scrolling the TextView.
How can I get the TextView to scroll.
In iOS the TextView should be scrollable by default if you set large text in it.
However for Android you could use ScrollView and to use StackLayout for main container inside it. For further help you could review the below attached example:
main-page.xml
<Page xmlns="http://schemas.nativescript.org/tns.xsd" navigatingTo="navigatingTo">
<GridLayout columns="*" rows="auto,*">
<GridLayout row="0" col="0" columns="auto,*" rows="auto">
<Label text="header" row="0" col="0" />
</GridLayout>
<GridLayout row="1" col="0" columns="auto,*" rows="auto">
<Label text="Note" row="0" col="0" />
<ScrollView orientation="vertical" row="1" col="0" height="300" width="300" backgroundColor="green">
<StackLayout orientation="vertical" class="scroll-menu" backgroundColor="red">
<TextView text="" hint="Enter text..." />
</StackLayout>
</ScrollView>
</GridLayout>
</GridLayout>
</Page>

Resources