Images with remote source not in cache Nativescript vuejs - image

I use Nativescript with vuejs (NS 8.2 & VueJs 2.6).
The problem I have is the following :
The images fetched on a remote url, seem to be refreshed each time I navigate on the component.
This is not very user friendly :-( when I arrive on the Home I have white blocks and they take a bit of time to be loaded (slow internet).
It looks like my pictures are not in cache...
Is there anything I can do to solve the problem ?
Here is a part of the code :
<ListView height="850" for="item in list_items" #itemTap="onFlickTap" >
<v-template>
<GridLayout
height="280"
class="bg-secondary"
rows="*, auto, auto"
columns="*"
margin="5 10"
padding="0"
>
<image row="0" margin="0" height="200" stretch="aspectFill" :src="'https://my_remote_web_site.Com/upload/pictures/small_'+item.picture" />
<label
row="1"
margin="10 10 0 10"
fontWeight="700"
class="text-primary"
fontSize="18"
:text="item.title"
/>
</GridLayout>
</v-template>
</ListView>
*One precision I test my app on phone android with usb
Thanks a lot !

Related

Image being requested multiple times on RadListView

I'm loading a list of items, each with an URL reference for a thumbnail foreach item. When rendering the list using RadListView, I notice that each image is being loaded several times from the server. This only happens in iOS, in Android each thumbnail only loads once. The view however, is correct (no duplicates).
NativeScript version is 5.1.1
<StackLayout>
<SearchBar id="searchBar" hint="{{sbHint}}" text="{{sbText}}" clear="onClear" submit="onSubmit" />
<GridLayout rows="auto, *" class="list-group">
<lv:RadListView class="listview" items="{{itemList}}" pullToRefresh="true" pullToRefreshInitiated="onPullToRefreshInitiated" loaded="onListLoaded" itemTemplateSelector="selectItemTemplate" row="1">
<lv:RadListView.itemTemplates>
<template key="hasimg">
<GridLayout rows="auto" columns="70,*,auto" class="list-group-item" tap="select">
<Image row="0" col="0" src="{{imgurl}}" width="60" height="50" stretch="aspectFill"/>
<Label row="0" col="1" class="p-l-15 text" text="{{ name }}"/>
<Label class="p-l-15 fa" text="" row="0" col="2"/>
</GridLayout>
</template>
<template key="noimg">
<GridLayout rows="auto" columns="70,*,auto" class="list-group-item" tap="select">
<Label class="fa imgicon" text="" row="0" col="0"/>
<Label row="0" col="1" class="p-l-15 text" text="{{ name }}"/>
<Label class="p-l-15 fa" text="" row="0" col="2"/>
</GridLayout>
</template>
</lv:RadListView.itemTemplates>
</lv:RadListView>
<ActivityIndicator busy="{{ isLoading }}" row="1" horizontalAlignment="center" verticalAlignment="center"/>
</GridLayout>
</StackLayout>
Output from the API server on the same list load, using iOS and Android.
Using iOS (wrong):
GET /v4/item/file/display/1/ 404 Not Found
GET /v4/item/file/display/1/ 404 Not Found
GET /v4/item/file/display/2/ 404 Not Found
GET /v4/item/file/display/2/ 404 Not Found
GET /v4/item/file/display/1/ 404 Not Found
GET /v4/item/file/display/2/ 404 Not Found
GET /v4/item/file/display/1/ 404 Not Found
GET /v4/item/file/display/2/ 404 Not Found
POST /v4/item/list/ 200 OK
Using Android (correct):
GET /v4/item/file/display/1/ 404 Not Found
GET /v4/item/file/display/2/ 404 Not Found
POST /v4/item/list/ 200 OK
(in reversed order, please ignore the 404, I changed the path better to diff each call)
When using ListView, it reuses the item template as you scroll down / up. Let's say if you have 100 data items loaded on ListView, it would not create 100 View / Image components. It will probably create a few depending on the visible area of your screen, when you scroll up / down the same views will be reused for other data items to keep the performance up. This is the advantage of using ListView or RadListView.
Coming to why the Image was loaded multiple times, by default Android caches the image and uses it on subsequent requests. With iOS, it doesn't. So it hits the URL every time whenever it has to render the image while you scroll up / down.
The solution is to cache your images in temp storage. You could simply do it with http module and a bit of logical statements Or there are even several plugins you could find in the market place for this purpose, nativescript-web-image-cache or nativescript-image-cache-it are couple to name.

Nativescript performance with custom components

Let's say I have a Nativescript Vue component that looks like this:
<template>
<GridLayout columns="auto, auto">
<TextField col="0" />
<Button col="1" />
</GridLayout>
</template>
I would like to use this component for example 10 times in a form. As far as I know using the component like this would be rather inefficient in nativescript.
For the performance it would be better to not use a custom vue component and just create a component with one GridLayout that contains the above components 10 times.
I mean something like this:
<template>
<GridLayout rows="10" columns="auto, auto">
<TextField row="0" col="0" />
<Button row="0" col="1" />
<TextField row="1" col="0" />
<Button row="1" col="1" />
...
</GridLayout>
</template>
With a custom component it would look like this:
<template>
<GridLayout rows="10" columns="auto, auto">
<CustomComponent row="0" />
<CustomComponent row="1" />
...
</GridLayout>
</template>
which would translate to:
<template>
<GridLayout rows="10" columns="auto, auto">
<GridLayout row="0" columns="auto, auto">
<TextField col="0" />
<Button col="1" />
</GridLayout>
<GridLayout row="1" columns="auto, auto">
<TextField col="0" />
<Button col="1" />
</GridLayout>
...
</GridLayout>
</template>
In this case I have only one GridLayout instead of 11 with the custom component. Using a custom component would be a lot more convenient though.
I could easily tweak the component and don't have duplicate code. I also can do animations with ref more easily (not giving each Label/Button a unique name etc.).
I wonder if the second approach is the best one could do if you want better performance? Is there a way to achive the same performance with custom components?
Using custom Vue components are never a issue but it's all about how your design and what layouts you use. There are two simple ways you could retain the performance here,
Choose right layout: Instead of using GridLayout with 10 rows, you should consider using a StackLayout. GridLayout is good when you have known number of limited partitions. When you just want to stack items one after another you must go with StackLayout.
Use ListView / RadListView: The more UI elements you add to screen, the main / UI thread becomes heavy and looses responsiveness. It's not just with NativeScript, but even with native apps. You must consider using ListView / RadListView with one or more item templates as needed. The component has its own logics to reuse the views (item templates) as you scroll down / up. You should not use Id / Ref with this component as the templates will be reused as needed, so prefer playing with data, binding class names etc.,

Slow ScrollView performance in Xamarin.Forms and WinPhone Silverlight

I´m facing a bad performance using all sort of layouts (e.g. StackLayout, Grid) inside a ScrollView specifically on the WP SL platform. On the other platforms (Android and iOS) the performance is way better using the same layout. I´m using the latest stable version of Xamarin.Forms (2.3.1.114) at the moment. Has anyone faced this issue too?
Thanks.
UPDATE: Code sample added to better understanding. The layout itself is not complex.
<ScrollView>
<StackLayout BackgroundColor="Black" Padding="5" Spacing="20" >
<StackLayout>
<Label Text="User name:" />
<Label Text="{Binding LoggedInUser}" />
</StackLayout>
<StackLayout>
<Label FontSize="Medium" FontAttributes="Bold" TextColor="Gray" Text="Help" />
<BoxView HeightRequest="1" BackgroundColor="Gray" HorizontalOptions="Fill" />
<Label FontSize="Small" FontAttributes="Bold" TextColor="Gray" Text="Please, send an email to xxx#example.com" />
</StackLayout>
</StackLayout>
</ScrollView>

NativeScript Scroll ListView with Title

I have this code in main-page.xml:
<GridLayout rows="auto, *">
<Label text="Title" class="title" row="0" />
<ListView id="listView" items="{{ listItems }}" row="1">
<ListView.itemTemplate>
<StackLayout>
<Button text="{{ name }}" tap="dd" />
</StackLayout>
</ListView.itemTemplate>
</ListView>
</GridLayout>
When I scroll the title stick to the top (stay and don't move), is there is a way to make it behave normally ?
I found a cleaner solution using : https://docs.nativescript.org/cookbook/ui/repeater
<ScrollView>
<StackLayout>
<Label text="Title" class="title" />
<Repeater id="listItems" items="{{ listItems }}">
<Repeater.itemTemplate>
<StackLayout>
<Button text="{{ name }}" tap="loadGuide" />
</StackLayout>
</Repeater.itemTemplate>
</Repeater>
</StackLayout>
This is definitely the expected behavior when placing a Label at a row of a GridLayout which is set to auto. What you want to achieve can be done but will require additional implementations for example like this (No boring ActionBar) third party Android library. What you can do is either implement the same using pure JavaScript/TypeScript directly in your app (by managing the size of the ActionBar) or create a custom NativeScript plugin that uses the mentioned android library.
One of the many beauties of NativeScript is that 100% of the native iOS and Android APIs are accessible meaning anything that is achievable in an native iOS or Android app is achievable in {N}.

NativeScript Floating Button

I just recently started with NativeScript and ran into a roadblock.
I have a AppBuilder/NativeScript project (iOS only for now) in which I want to implement a floating action button. I have seen plenty of examples where the FAB is positioned above a ListView however my scenario is different:
I have 3 repeaters (displaying unrelated data).
each repeater may or may not be visible on the page (if there is no data to display, I am hiding it)
I would like to place the FAB on the bottom right regardless of what the content is
The whole page is wrapped in a ScrollView
I tried using nativescript-floatingactionbutton, but I cannot compile with this module installed. I keep getting "Cannot build project because module nativescript-floatingactionbutton contains insecure code. Remove the module and try again."
I also tried an AbsoluteLayout on the page level, but it seems that the layout overlays the rest of the page and I cannot even see the content, just the FAB.
Here is the markup
<Page id="MainPage" xmlns="http://schema.nativescript.org/tns.xsd" actionBarHidden="true" loaded="pageLoaded" xmlns:drawer="nativescript-telerik-ui/sidedrawer" xmlns:sharedDrawers="widgets/drawers">
<drawer:RadSideDrawer id="mainDrawer">
<drawer:RadSideDrawer.mainContent>
<ScrollView id="wrapper" opacity="0">
<DockLayout stretchLastChild="false">
<GridLayout id="mainHeader" cssClass="header" dock="top" columns="50, *, 50">
<Label class="icomoon-icon" text="" row="0" col="0" horizontalAlignment="center" tap="openDrawer" fontSize="18" />
<Label horizontalAlignment="center" text="{{ pageTitle }}" row="0" col="1" />
<Label class="icomoon-icon" text="" row="0" col="2" horizontalAlignment="center" tap="notifications" fontSize="18" />
</GridLayout>
<GridLayout cssClass="main" rows="auto, *" >
<StackLayout row="0">
<StackLayout cssClass="{{arr.length ? '' : 'hidden' }}">
<label cssClass="section-title" text="{{strings.activeLoans}}"></label>
<Repeater items="{{ arr }}" >
<Repeater.itemTemplate cssClass="item">
...
</Repeater.itemTemplate>
</Repeater>
</StackLayout>
<StackLayout cssClass="{{arr2.length ? '' : 'hidden' }}">
<label cssClass="section-title" text="{{strings.history}}" marginTop="20" />
<Repeater items="{{ arr2 }}">
<Repeater.itemTemplate>
...
</Repeater.itemTemplate>
</Repeater>
</StackLayout>
<StackLayout cssClass="{{arr3.length ? '' : 'hidden' }}">
<label cssClass="section-title" text="{{strings.data}}" marginTop="20" />
<Image src="~/images/pic.jpg" />
<Repeater items="{{ arr3 }}">
<Repeater.itemTemplate>
...
</Repeater.itemTemplate>
</Repeater>
</StackLayout>
</StackLayout>
</GridLayout>
</DockLayout>
</ScrollView>
</drawer:RadSideDrawer.mainContent>
<drawer:SideDrawer.drawerContent>
<sharedDrawers:mainDrawer />
</drawer:SideDrawer.drawerContent>
</drawer:RadSideDrawer>
<!--<AbsoluteLayout cssClass="fabContainer">
<Image src="res://fab_add" tap="newLoan" cssClass="fab" />
</AbsoluteLayout>-->
</Page>
I have truncated and changed some of the non-relevant code.
Any help is greatly appreciated.
Thank you.
Аs Brad Martin says, the plugin cannot be built inside Telerik Platform as not all of its maintainers are white listed. To be more precise, when an iOS build of a plugin containing a pod file is initiated in Telerik Platform, the service checks its maintainers. As a pod file can contain post build scripts, Telerik Platform is currently flagging plugins as safe by keeping a list of white listed maintainers.
This plugin has 5 maintainers - Brad Martin being only one of them. Brad’s email is white listed but ‘gabrielbiga’ and ‘lazaromenezes’ are not yet whitelisted. #Brad Martin- can you please let us know whether we should whitelist these users emails as well?
The other approach would be to replace the pod file with frameworks instead.
One last thing, moving forward with Telerik Platform releases Telerik Platform team will be working on improving the support for plugins containing pods. They will probably remove the "whitelisting” approach with sandboxing instead but we couldn’t yet comment on any specifics. 

Resources