I am using this example that has nested page-router-outlets. I discovered that the nested router will always take 100% percent of the page height on iOS, while on Android it will obey what you tell it.
For example, if you did something like this the nested page-router-outlet will be the full height on iOS but on Android it will actually be 400 tall
<GridLayout rows="400, *">
<GridLayout row="0">
<page-router-outlet></page-router-outlet>
</GridLayout>
<GridLayout row="1">
<Label text="Some other content"></Label>
</GridLayout>
</GridLayout>
It is working perfectly fine on ios well. There may be some other issue with your code only. As suggested by you, I have cloned the github code and added that to playground for your to test. You can access the playground from here.
What I would suggest is to add your child in above playground and test. May be that child component has 100% height that would be overlapping the parent.
Related
In android, I can't seem to make my TabViewItem icon sizes larger. I tried adding an explicit height and width in the XML but that doesn't change anything. Right now, it looks like this: https://imgur.com/a/PudvqwF which is too small for me. I also tried giving it a class and changing via CSS but still no luck . My code is as follows:
<TabViewItem :title='`FAVORITES ${this.favorites && this.favorites.length ? this.favorites.length : ""}`' width="60" height="60" iconSource="~/assets/images/heart-Icon.png">
<Frame
id="favorites-list-frame"
row="0"
>
<CustomComponent/>
</Frame>
</TabViewItem>
Any way to make these larger?
I have an NS 6 app and testing on an iPhone 6+ with iOS 13.
In this app I have a ListView and in the ListView I have a nativescript-carousel.
In the carousel I have an image component that loads an external image. The issue is that when I load the page, the image is loaded, but the parent does not expand vertically to accommodate the full height of the image. I can only see a small portion of it.
I tried refreshing the ListView and calling page.requestLayout(), but that did not help. If I set the image height, everything works, but the issue is that some of the carousel items may not have an image, so I cannot commit to a set height.
Here is my code (truncated for brevity):
<ListView id="lst" items="{{ asks }}">
<ListView.itemTemplate>
<StackLayout class="ask-item">
…
<GridLayout rows="*" columns="*" marginTop="10">
<ns:Carousel items="{{ recs }}" color="white" pageChanged="myChangeEvent" android:indicatorAnimation="slide" indicatorColor="#999999" indicatorColorUnselected="#dddddd" indicatorOffset="0,15" showIndicator="true">
<ns:Carousel.itemTemplate>
<ns:CarouselItem backgroundColor="#f9f9f9" verticalAlignment="middle">
<StackLayout class="rec-item">
…
<Image src="{{ image }}" stretch="aspectFit" horizontalAlignment="center" />
…
</StackLayout>
</ns:CarouselItem>
</ns:Carousel.itemTemplate>
</ns:Carousel>
</GridLayout>
</StackLayout>
</ListView.itemTemplate>
</ListView>
What is the best way to handle this issue?
Thank you.
By nature iOS ListView height can not be changed once rendered, you will have to update the specific list item.
Try downloading the image upfront or listen to isLoading property change, once then capture the height of the raw image and bind the height to the layout. The images height could be in raw pixel, you might want to convert that into density independent pixel for better display on high resolution devices.
I have a nativescript-vue app with the RadListView component to display data to the user. Each row of the list include multiple informations for the current item. When i tap on a button to load and show the list the UI freeze (fast hardware -> short; slow hardware -> long). I figured out that the code part to load/combine the data run very short but the nativescript-internal rendering or creation of the UI elements are the problem. The android console show the information
I/Choreographer: Skipped 430 frames! The application may be doing too much work on its main thread.
Platform info:
tns-ios 5.2.0
tns-android 5.2.1
nativescript-ui-listview 6.2.0
tns-core-modules 5.3.1
Similar problem reports
I look at stackoverflow and github but the problems there (e.g. NativeScript Angular RadListView rendering extremely slowly) looks similar but the solutions not suitable for me.
I use the LinearListView (not Grid nor Stagged) and maybe in my real app i will be able to simplify the row elements from the list but in my sample app (look down) i use a simple row ui design.
Sample app
For a simpler and better report i created a sample app on the {N}-Playground. The app creates 10000 array elements and set them as source of the RadListView which has a Label, a Switch and an ActivityIndicator for every element.
<RadListView ref="listView"
for="alarm in alarms"
layout="linear">
<v-template>
<StackLayout class="list-element" orientation="vertical" >
<GridLayout columns="*, auto, auto" rows="*">
<Label col="0" row="0">{{alarm.name}}</Label>
<Switch col="1" row="0" :checked="alarm.active" />
<ActivityIndicator col="2" row="0" :busy="alarm.active"/>
</GridLayout>
<Label class="list-element-divider"></Label>
</StackLayout>
</v-template>
</RadListView>
In the first step the 10000 elements will be generated in a temporary array:
loadData() {
this.tmpAlarms = [];
for (let i = 0; i <= 10000; i++) {
this.tmpAlarms.push({
name: "Hase " + i,
active: i % 2 === 0,
});
}
}
With a second button set the temporary array as source:
setData() {
this.alarms = this.tmpAlarms;
}
Note: I use 10000 elements to make the problem visible even the sample app runs on a S9 or another high end smartphone.
The full source is runnable under https://play.nativescript.org/?template=play-vue&id=Td1GWR
A slightly different version with an ObservableArray instead of a plain array is under https://play.nativescript.org/?template=play-vue&id=5BXOFG
In both versions the data handling is fast but as soon the UI elements generated from the internal functions the UI will be frozen.
Sample: On my Nexus 7 2013 with Android 6.x the UI freeze nearly 6 seconds and no other apps running in background.
iOS
If i try the same apps on an iOS device (e.g. iPhone 7s) the rendering is very fast and the UI running smooth even so with the 10000 elements and more.
Ideas?
Have anyone an idea how i can speed up the rendering? If not is there a suggestion how i can build an animation (e.g. ActivityIndicator) to show the user that the device is working? At the moment when i put an ActivityIndicator on the UI the user can not see it because of the frozen UI.
Android and IOS have a very different way of rendering the ui. This difference added to particularity of the Rad list can affect performance. Note that the rad list reuse the instance of the list element to improve performance. This reuse is not done the same way in IOS and in Android.
There are two simple optimizations that can improve a lot the rendering in ios and android.
The first one is to reduce the layouts in layouts. It is easier for the rendering if there are less elements. This reduce the depth/passes rendering
<RadListView ref="listView" for="alarm in alarms" layout="linear">
<v-template>
<GridLayout class="list-element" columns="*, auto, auto" rows="*, auto">
<Label col="0" row="0">{{alarm.name}}</Label>
<Switch col="1" row="0" :checked="alarm.active" />
<ActivityIndicator col="2" row="0" :busy="alarm.active"/>
<Label colSpan="3" row="1" class="list-element-divider"></Label>
</GridLayout>
</v-template>
</RadListView>
The second is the one that have the most impact. Set an height to component when possible. Here the use of *,auto,auto will means that it will have to recalculate for each elements of the list. And here is where IOS and Android differs.
IOS will re render only what is required in the element. This means that the stack layout and the grid layout will stay the same when the element is recycled but if the content of the grid layout would be bigger in lower elements, the rendering on IOS may be all wrong the more you scroll. This is really faster because no need to adjust the height each time. But can be bad if size need to change.
Android tends recycle but to rerender all the components and therefore recalculate for each. This is slower but safer for size change.
In general, setting and height will boost the performance of the app because there are less inference form the rendering engine that need to be done. This is true everywhere in your app but really important in rad list.
Beforehand I was using Ionic for my cross platform apps. When using Angular repeat, there was performance and memory issues in huge lists.
But ionic has a feature called virtualRepeat (or collection-repeat in v1.x). But it has lots of bugs and is not usable.
Is there such a feature in NativeScript? (It must not keep all elements alive in the list, and as user scroll change the list.) The same feature is available in React Native.
Also I took a screenshot video for performance demonstration. At first I have 20 items. Then for load more in scroll, I load a very huge list . Then, see the result:
https://www.youtube.com/watch?v=220FS2SqLqI
In Nativescript you will want to use ListView and not ngFor or other repeating techniques, Listview reuses view and reducing memory usage for big lists
Example
<ListView [items]="myItems">
<template let-item="item">
<StackLayout>
<Label [text]='item.name'></Label>
</StackLayout>
</template>
</ListView>
Link with docs/more examples:
https://docs.nativescript.org/angular/ui/list-view.html
Finally I found out, it uses virtulization. I ran this command:
tns debug android
Then I could be able to see the elements from chrome dev tools:
It uses only a few elements and while scrolling changes them.
I have decided to try Xamarin Forms, because I thought that I can make one design for all platforms or at least Android and iOS.
However a simple form like:
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:app91="clr-namespace:App9;assembly=MasterDetail.Android"
x:Class="MasterDetail.CompetitorsListPage"
>
<StackLayout>
<Label Text="{Binding CurrentEvent.Name}"></Label>
<StackLayout Orientation="Horizontal">
<Button Text="By Place" Clicked="Button_OnClickedByPlace"></Button>
<Button Text="By Number" Clicked="Button_OnClickedByNumber"></Button>
<Button Text="By Rating" Clicked="Button_OnClickedByRating"></Button>
<Button Text="Change Event" Clicked="Button_OnClickedChangeEvent"></Button>
</StackLayout>
<ScrollView>
<ListView x:Name="couples" ItemSelected="Comps_OnItemSelected" ItemTapped="Couples_OnItemTapped">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<ViewCell.View>
<StackLayout Orientation="Horizontal">
<Label Text="{Binding Round}"></Label>
<Label Text="{Binding Pos, StringFormat='({0}).'}"></Label>
<Label Text="{Binding Name}"></Label>
<Label Text="{Binding StartingNumber}" ></Label>
<Label Text="{Binding OldRating, StringFormat=' [{0}]'}"></Label>
<!--<Label Text="{Binding NewRating, StringFormat=' {0} ]'}"></Label>-->
</StackLayout>
</ViewCell.View>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</ScrollView>
</StackLayout>
</ContentPage>
Looks completely different on Android and iOS. I do not mind colours, but font size? I do not set font anywhere in the code or xaml.
Any idea what am I doing wrong?
Here it is a picture showing both versions:
This is by design. Forms is intended to provide a native experience on each platform by using their respective UI standards. Android has a different default color scheme than iOS. iOS default buttons look different than Android.
You can override the default fonts, sizes, colors, etc if you like in order to provide a more consistent UI. Xamarin has also introduced Themes for Forms which help you provide a consistent UI between platforms.
Because Android has variety of screen sizes and different screen DPI as compared to standard dpi and font sizes across iOS devices, it is not possible to create same look. But you can certainly change Theme in the MainActivity of your Droid project and increase font size as per your convenience. Beware that your theme's font size may be too big for small devices and too small for big devices. You can add scaling factor for font size in your theme, but I have not been very successful, instead, I tried to design a UI that will automatically fit for the best.
As per Xamarin Evolve 2016, some questions were raised regarding font sizes, they said it is difficult, but they are trying to make some unified font sizing.
Although Xamarin.Forms has everything in Xaml and C#, you still need to use iOS assets and Android resources to customize look and feel.
For me, #Jason's answer and comments from #Egg and #Bill Reiss are spot-on.
Meanwhile, so often clients request "same font size" across platforms that something like this finds its way into base Styles or Theme to account for what seems to be "natively smaller" fonts on Android:
<OnPlatform x:TypeArguments="Font">
<OnPlatform.iOS>Bold,Medium</OnPlatform.iOS>
<OnPlatform.Android>Bold,Large</OnPlatform.Android>
<OnPlatform.WinPhone>Bold,Medium</OnPlatform.WinPhone>
</OnPlatform>
Something similar can also be expressed in code at or near app startup, for example as a base Label font added to global Styles dictionary.
Just wanted to give a concrete example of what others above alluded to.
Strange behavior on iOS - as you can see those are labels in StackLayout, while in Android they behave OK, in iOS second and third label behave more lithe they were in some kind of grid rather than stack –
You have put 5 labels in a horizontal stack, and haven't changed the layout options on any of them. This will 'stack' all 5 labels next to each other, then size them based on the amount of text to be displayed. There is not enough horizontal space to accommodate all of the text, so the labels are wrapping vertically. The longest labels show the most wrapping, but as they get longer other labels wrap as well, which is why the Pos and OldRating data raps in some labels. When I'm working out layouts like this I often add different background colors to each control so I can see how they are laying out.
There are different ways to solve this depending on your desired result. If you want the entire line of text to wrap you can concatenate the data behind the scenes and add it as one label. If you want the name to wrap and the other data to display without wrapping you can set WidthRequests on the labels.