What is right way to create custom template in Nativescript?
For example I have XML structure like:
<FlexboxLayout flexDirection="column" alignItems = "stretch">
<Border borderWidth="1" borderColor="#000000">
<FlexboxLayout height="60">
<Button cssClass="sdk-button" col="0" text="initSDK" tap="{{initSdk}}" flexGrow="1"/>
<StackLayout orientation="horizontal" class="data-wrapper" flexGrow="3" paddingLeft="20">
<Label text="{{ initSdkResponse }}" class="data_wrapper-label" textWrap="true"/>
</StackLayout>
</FlexboxLayout>
</Border>
</FlexboxLayout>
I want to create component with above mentioned structure, named MyItem and use it as follow:
<Page xmlns="http://schemas.nativescript.org/tns.xsd" navigatingTo="onNavigatingTo">
<StackLayout orientation="vertical">
<MyItem buttonName="click1"
buttonAction="onClick1()"
labelText="xxxxxxx1"
></MyItem>
<MyItem buttonName="click2"
buttonAction="onClick2()"
labelText="xxxxxxx2"
></MyItem>
</StackLayout>
</Page>
I think you will find these resources helpful:
https://moduscreate.com/custom-components-in-nativescript/
http://blog.bradleygore.com/2016/03/12/custom-nativescript-components/
http://docs.nativescript.org/ui/basics#custom-components
Related
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>
In Xamarin.Android it has a class named ViewPager to support "Gestural navigation allows the user to swipe left and right to step through pages of data." (https://learn.microsoft.com/en-us/xamarin/android/user-interface/controls/view-pager/)
But my task is write cross-platform codes for both Android & iOS (without rewrite new code for this gesture). With Xamarin.Form does any library support this ? I have read about Xamarin.Form carousel, but it seem used for slideshow, not appropriate for news list.
I think TabbedPage is more suitable for you. tabbedPage support the Gestural navigation allows the user to swipe left and right to step through pages of data, just set the different pages of data in different tabs.
Here is running GIF.
You can add this Tabbedpage like following code.
<TabbedPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:TabbedPageDemo;assembly=TabbedPageDemo"
x:Class="TabbedPageDemo.TabbedPageDemoPage">
<TabbedPage.Resources>
<ResourceDictionary>
<local:NonNullToBooleanConverter x:Key="booleanConverter" />
</ResourceDictionary>
</TabbedPage.Resources>
<TabbedPage.ItemTemplate>
<DataTemplate>
<ContentPage Title="{Binding Name}" Icon="monkeyicon.png">
<StackLayout Padding="5, 25">
<Label Text="{Binding Name}"
Font="Bold,Large"
HorizontalOptions="Center" />
<Image Source="{Binding PhotoUrl}"
WidthRequest="200"
HeightRequest="200" />
<StackLayout Padding="50, 10">
<StackLayout Orientation="Horizontal">
<Label Text="Family:"
HorizontalOptions="FillAndExpand" />
<Label Text="{Binding Family}"
Font="Bold,Medium" />
</StackLayout>
<StackLayout Orientation="Horizontal"
IsVisible="{Binding Subfamily,
Converter={StaticResource booleanConverter}}">
<Label Text="Subfamily:"
HorizontalOptions="FillAndExpand" />
<Label Text="{Binding Subfamily}"
Font="Bold,Medium" />
</StackLayout>
<StackLayout Orientation="Horizontal"
IsVisible="{Binding Tribe,
Converter={StaticResource booleanConverter}}">
<Label Text="Tribe:"
HorizontalOptions="FillAndExpand" />
<Label Text="{Binding Tribe}"
Font="Bold,Medium" />
</StackLayout>
<StackLayout Orientation="Horizontal">
<Label Text="Genus:"
HorizontalOptions="FillAndExpand" />
<Label Text="{Binding Genus}"
Font="Bold,Medium" />
</StackLayout>
</StackLayout>
</StackLayout>
</ContentPage>
</DataTemplate>
</TabbedPage.ItemTemplate>
</TabbedPage>
You can add different ItemTemplate in the Tabbedpage.
Here is a related link.
https://learn.microsoft.com/en-us/xamarin/xamarin-forms/app-fundamentals/navigation/tabbed-page
Update: you can add the listview in the tabbpage like following GIF.
I am creating a Horizontal scroll in NS. When using below code it's working as expected.
<Page xmlns="http://schemas.nativescript.org/tns.xsd" navigatingTo="onPageLoad" class="page">
<StackLayout>
<!-- This is where the magic happens -->
<ScrollView orientation="horizontal">
<StackLayout orientation="horizontal" class="scroll-menu">
<StackLayout class="scroll-pane">
<Button text="Button" />
</StackLayout>
<StackLayout class="scroll-pane">
<Button text="Button" />
</StackLayout>
<StackLayout class="scroll-pane">
<Button text="Button" />
</StackLayout>
<StackLayout class="scroll-pane">
<Button text="Button" />
</StackLayout>
</StackLayout>
</ScrollView>
</StackLayout>
Horizontal Scroll:
But, Once I am using the Repeater it's changing to orientation with Vertical and not scrolling.
<Page xmlns="http://schemas.nativescript.org/tns.xsd" navigatingTo="onPageLoad" class="page">
<StackLayout>
<!-- This is where the magic happens -->
<ScrollView orientation="horizontal">
<StackLayout orientation="horizontal" class="scroll-menu">
<Repeater items="{{ categories }}" >
<Repeater.itemTemplate>
<StackLayout class="scroll-pane" >
<Label text="{{name}}" />
</StackLayout>
</Repeater.itemTemplate>
</Repeater>
</StackLayout>
</ScrollView>
</StackLayout>
Change to Vertical when use of Repeater:
What's wrong with the code?
I have little difficult problem for me with ListView.
1) I have this graphics https://ibb.co/j6wdk71
2) I have done it but with *ngFor’s
<ActionBarLogo (myEvent)="onDrawerButtonTap($event)"></ActionBarLogo>
<RadSideDrawer #drawer showOverNavigation="false" gesturesEnabled="{{android}}" [drawerTransition]="sideDrawerTransition">
<StackLayout tkDrawerContent class="drawer">
<MyDrawer [selectedPage]="'Home'"></MyDrawer>
</StackLayout>
<GridLayout rows="*, auto" class="page page-content" tkMainContent>
<StackLayout class="fade-in" row="0" orientation="vertical" *ngIf="loading==false && network_error==false">
<StackLayout>
<PullToRefresh (refresh)="refreshList($event)">
<ScrollView orientation="vertical">
<StackLayout>
<StackLayout>
<ScrollView orientation="horizontal" scrollBarIndicatorVisible="false">
<StackLayout orientation="horizontal" class="games">
<StackLayout class="game" width="{{screen_width}}" *ngFor="let game of games">
<StackLayout class="game-inner">
<StackLayout class="game-date">
<Label text="{{game.league}}, {{game.round}}. kolo" class="game-round"></Label>
<Label text="{{ game.date | format_date }}" class="game-date-text"></Label>
</StackLayout>
<StackLayout class="game-data">
<FlexboxLayout flexDirection="row">
<StackLayout flexGrow="1" class="game-team">
<WebImage src="{{game.team_home.logo}}" height="40" class="game-team-logo"></WebImage>
<Label text="{{game.team_home.name}}" textWrap="true" class="game-team-name"></Label>
</StackLayout>
<StackLayout flexGrow="1" class="game-score">
<Label class="game-score-inner" text="-:-" textWrap="true" *ngIf="game.score==null"></Label>
<Label class="game-score-inner" text="{{game.score}}" textWrap="true" *ngIf="game.score!=null"></Label>
</StackLayout>
<StackLayout flexGrow="1" class="game-team">
<WebImage src="{{game.team_away.logo}}" height="40" class="game-team-logo"></WebImage>
<Label text="{{game.team_away.name}}" textWrap="true" class="game-team-name"></Label>
</StackLayout>
</FlexboxLayout>
</StackLayout>
<StackLayout class="game-button" orientation="horizontal" horizontalAlignment="center" [nsRouterLink]="['/game', game.id]"
pageTransition="flip">
<WebImage src="~/assets/menu_icons/matches.png" width="15"></WebImage>
<Label text="informácie o zápase" class="game-button-btn"></Label>
</StackLayout>
</StackLayout>
</StackLayout>
</StackLayout>
</ScrollView>
</StackLayout>
<StackLayout>
<StackLayout class="hp-partners">
<StackLayout class="hp-partners-heading">
<Label text="Partneri klubu"></Label>
</StackLayout>
<FlexboxLayout flexDirection="row">
<StackLayout class="partner" *ngFor="let partner of partners">
<WebImage src="{{partner.img_url}}" stretch="aspectFit" width="100%" class="partner-image" (tap)="open_url(partner.url)"></WebImage>
</StackLayout>
</FlexboxLayout>
</StackLayout>
<StackLayout class="articles-list">
<StackLayout class="article" [nsRouterLink]="['/article', article.id]" pageTransition="slideLeft" *ngFor="let article of articles, let i=index">
<StackLayout class="article-photo">
<WebImage src="{{article.photo}}" stretch="aspectFill" placeholder="~/assets/placeholder.png" class="article-photo-image"></WebImage>
</StackLayout>
<StackLayout class="article-body">
<StackLayout class="article-data">
<FlexboxLayout flexDirection="row">
<StackLayout class="article-date" orientation="horizontal">
<WebImage src="~/assets/menu_icons/date.png" class="article-date-ico"></WebImage>
<Label text="{{ article.date | format_date }}" class="article-date-text"></Label>
</StackLayout>
<StackLayout class="article-sticker" orientation="horizontal">
<WebImage src="~/assets/menu_icons/tag.png" class="article-sticker-ico"></WebImage>
<Label text="{{article.category}}" class="article-sticker-text"></Label>
</StackLayout>
<StackLayout class="article-stickers" flexGrow="1" orientation="horizontal">
<WebImage src="~/assets/article_stickers/text.png" class="article-stickers-image" *ngIf="article.sticker_text==true"></WebImage>
<WebImage src="~/assets/article_stickers/video.png" class="article-stickers-image" *ngIf="article.sticker_video==true"></WebImage>
<WebImage src="~/assets/article_stickers/photo.png" class="article-stickers-image" *ngIf="article.sticker_photogallery==true"></WebImage>
</StackLayout>
</FlexboxLayout>
</StackLayout>
<StackLayout class="article-heading">
<Label text="{{article.heading}}" class="article-heading-text" textWrap="true"></Label>
</StackLayout>
</StackLayout>
<StackLayout *ngIf="i==330">
<StackLayout class="banner" *ngFor="let banner of banners">
<WebImage src="{{banner.image}}" stretch="aspectFit" width="100%" class="banner-image" (tap)="open_url(banner.url)"></WebImage>
</StackLayout>
</StackLayout>
</StackLayout>
</StackLayout>
<StackLayout class="load-more-button">
<Button class="btn btn-primary" text="Načítať ďalšie" (tap)="load_more_articles()" *ngIf="loading_more_articles==false"></Button>
<LoadingSmall *ngIf="loading_more_articles==true"></LoadingSmall>
</StackLayout>
</StackLayout>
</StackLayout>
</ScrollView>
</PullToRefresh>
</StackLayout>
</StackLayout>
<Loading *ngIf="loading==true && network_error==false"></Loading>
<StackLayout height="100%" (tap)="check_connection()" *ngIf="network_error==true">
<NetworkError></NetworkError>
</StackLayout>
<Tabs></Tabs>
</GridLayout>
</RadSideDrawer>
3) This is how I want it. (uses *ngFor) https://www.youtube.com/watch?v=z5CY_R6OAmI&feature=youtu.be1
4) Performance is very bad on android and app is crashing (iOS is great as usual)
5) I need everything transform to ListView
6) I really don’t know how. I read doc, google for done examples and I can’t find solution which would solve my problem.
7)I made simple template in playground https://play.nativescript.org/?template=play-ng&id=Rhw4HJ&v=21
Is possible to give me some advice or edit playground example to show how to do it?
Could someone help me find solution? I will really appreciate it. :frowning:
Thank you so much
# 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>