custom layout in nativescript camera plus on android not at all visible - nativescript

I am using nativescript-camera-plus for custom Layout. I tried default icons first which was working fine, but when i put custom gridlayout inside cam then it was not visible.
I have made all icon visible to false when i was checking, but now i just put a general code to show where i'm facing problem.
<Cam:CameraPlus id="camPlus" loaded="camLoaded" height="{{ cameraHeight }}" galleryPickerMode="multiple" enableVideo="true" confirmVideo="false" saveToGallery="true" showCaptureIcon="false" showGalleryIcon="false" showToggleIcon="false" showFlashIcon="false" confirmPhotos="true" flashOffIcon="icon" autoSquareCrop="true" insetButtons="true" insetButtonsPercent="0.02" imagesSelectedEvent="{{ imagesSelectedBinding }}" debug="true">
<GridLayout rows="auto, *, auto" columns="auto, *, auto"><Button row="0" col="0" text="Flash" class="btn-transparent" tap="{{ toggleFlash }}" /><Button row="0" col="2" text="Camera" class="btn-transparent" tap="{{ toggleCamera }}" /><Image row="1" col="1" horizontalAlignment="center" verticalAlignment="center" src="https://img.clipartfest.com/4ec5e2315cea92482da5546e1e7fca89_-pinterest-cute-clipart-snowman-clipart-transparent-background_300-300.png" stretch="none" /><Button row="2" col="0" text="Gallery" class="btn-transparent" tap="{{ openGallery }}" /><Button row="2" col="2" text="Take" class="btn-transparent" tap="{{ takePic }}" /></GridLayout>
</Cam:CameraPlus>

I guess it's a bug with the plugin itself. Here is a workaround,
XML
<Cam:CameraPlus id="camPlus" loaded="camLoaded" height="{{ cameraHeight }}">
<GridLayout id="overlay" rows="auto, *, auto" columns="auto, *, auto">
<Button row="0" col="0" text="Flash" class="btn-transparent" tap="{{ toggleFlash }}" />
<Button row="0" col="2" text="Camera" class="btn-transparent" tap="{{ toggleCamera }}" />
<Image row="1" col="1" horizontalAlignment="center" verticalAlignment="center" src="https://img.clipartfest.com/4ec5e2315cea92482da5546e1e7fca89_-pinterest-cute-clipart-snowman-clipart-transparent-background_300-300.png" stretch="none" />
<Button row="2" col="0" text="Gallery" class="btn-transparent" tap="{{ openGallery }}" />
<Button row="2" col="2" text="Take" class="btn-transparent" tap="{{ takePic }}" />
</GridLayout>
</Cam:CameraPlus>
JS
function camLoaded(args) {
const parentView = args.object.nativeView;
const overlayView = args.object.page.getViewById("overlay");
parentView.removeView(overlayView.nativeView);
overlayView.nativeView.setLayoutParams(new android.widget.RelativeLayout.LayoutParams(android.widget.RelativeLayout.LayoutParams.FILL_PARENT, android.widget.RelativeLayout.LayoutParams.FILL_PARENT));
parentView.addView(overlayView.nativeView);
}

Related

Nativescript AbsoluteLayout, parent position relative

I have an AbsoluteLayout that is supposed to open and go over a mdCardview, but it seems that it is trying to squeeze everything inside the cardview. I tried messing with the CSS position tag, but it doesn't change one bit.
In the picture below you can see the save button which is also an absolutelayout, this one does go over every other component.
This is my TimeCard component which has a button and a absolute layout that would be used as a popup
<template>
<GridLayout class="dialog" rows="*, *" columns="*" :class="{ dialogOpen: dialogOpen }">
<MDButton :text="label" #tap="showDialog()" class="fill" />
<AbsoluteLayout class="dialog-wrapper">
<StackLayout top="100" left="20" class="dialog">
<TimePicker v-bind="$attrs" v-on="$listeners" />
<MDButton text="Confirm" class="cancel" />
<Button class="btn btn-outline" text="Cancel" #tap="closeDialog"></Button>
</StackLayout>
</AbsoluteLayout>
</GridLayout>
</template>
data: () => ({
dialogOpen: false
}),
methods: {
showDialog() {
this.dialogOpen = true
},
closeDialog() {
this.dialogOpen = false
}
}
This is my availabilityCard which contains a slot with the timecard component
<StackLayout >
<MDCardView elevation="5px" ripple="true" width="100%" margin="30px" class="cardview">
<GridLayout rows="*, *" columns="*, *, *" class="card" width="auto">
<StackLayout col="0" row="0">
<Label class="title" :text="getNameAndDayOfMonth(day)" />
</StackLayout>
<MDButton col="2" row="0" text="fill" class="fill" #tap="showActions()" v-if="!show && Object.keys(value).length === 0" />
<GridLayout row="1" colSpan="3" columns="auto, auto, *" rows="*, *" width="auto" v-else>
<GridLayout row="0" columns="auto, auto" rows="*" colSpan="2" width="auto">
<slot />
</GridLayout>
<MDButton text="clear" col="2" row="0" class="cancel" #tap="cancelTime()" />
<template v-if="Object.keys(value).length !== 0">
<Label :text="format(value.start)" col="0" row="1" />
<Label :text="format(value.end)" col="1" row="1" />
</template>
</GridLayout>
</GridLayout>
</MDCardView>
</StackLayout>
This is the parent component availability that defines the timecard component
<StackLayout>
<AvailabilityCard v-for="(day, i) in days" :key="i" v-model="day.element" :day="day.date">
<TimeCard col="0" label="begin" v-model="day.element.start"></TimeCard>
<TimeCard col="1" label="eind" v-model="day.element.end"></TimeCard>
</AvailabilityCard>
</StackLayout>
Availability component screen:

Nativescript Vue conditional v-template not working

I have a ListView which renders this:
<ListView v-for="(item, index) in items" height="500">
<v-template v-if="index < items.length - 1">
<GridLayout rows="*, *", columns="220,130,*">
<TextField hint="Project Item" row="0" col="0" />
<TextField hint="Price" row="0" col="1" />
<Button text="X" row="0" col="2" />
</GridLayout>
</v-template>
<!-- render if index reaches last element -->
<v-template v-if="index == items.length - 1">
<GridLayout rows="*, *", columns="220,130,*">
<TextField hint="Project Item" row="0" col="0" />
<TextField hint="Price" row="0" col="1" />
<Button text="index" row="0" col="2" />
</GridLayout>
</v-template>
</ListView>
The second v-template block should be the one rendered if the index reaches last element of the array.
This is the array I have:
items: [1, 2, 3, 1, 1, 1 ,1 ,1 ,1 ]
Whats being rendered on the page is rather the value of each element: 1, 2, 3, 1 ... in TextField without any buttons defined in my code.
How do I get the conditional to work?
<v-template> uses if, not v-if. Also, you can't access items in the in the if (as described here).
Also, you should use for instead of v-for.
So this is what you can do:
1- Change the template to:
<ListView for="(item, index) in listItems" height="500">
<v-template if="!item.isLast">
<GridLayout rows="*, *", columns="220,130,*">
<TextField hint="Project Item" row="0" col="0" />
<TextField hint="Price" row="0" col="1" />
<Button text="X" row="0" col="2" />
</GridLayout>
</v-template>
<!-- render if index reaches last element -->
<v-template if="!item.isLast">
<GridLayout rows="*, *", columns="220,130,*">
<TextField hint="Project Item" row="0" col="0" />
<TextField hint="Price" row="0" col="1" />
<Button text="index" row="0" col="2" />
</GridLayout>
</v-template>
</ListView>
This would use another list listItems, which you could build with a computed prop like so:
computed: {
listItems() {
return this.items.map((item, index) => {
item.isLast = index === items.length - 1;
return item;
});
}
}
You should have to use for instead of v-for. Also, For the index in ListView, there is a default $index variable so you can use it as below.
<ListView for="item in items" height="500">
<v-template v-if="$index < items.length - 1">
<GridLayout rows="*, *", columns="220,130,*">
<TextField hint="Project Item" row="0" col="0" />
<TextField hint="Price" row="0" col="1" />
<Button text="X" row="0" col="2" />
</GridLayout>
</v-template>
<v-template v-if="$index == items.length - 1">
<GridLayout rows="*, *", columns="220,130,*">
<TextField hint="Project Item" row="0" col="0" />
<TextField hint="Price" row="0" col="1" />
<Button text="index" row="0" col="2" />
</GridLayout>
</v-template>
</ListView>

What is Repeater.itemsLayout property for? How and in what cases to use it?

This works as expected (without <Repeater.itemsLayout> and wrapped by <StackLayout>):
<GridLayout columns="auto, *" rows="auto">
<Label text="Some Text" row="0" col="0" backgroundColor="orange"/>
<StackLayout row="0" col="1" backgroundColor="green">
<Repeater items="{{ items }}">
<Repeater.itemTemplate>
<Label text="{{ $value }}"/>
</Repeater.itemTemplate>
</Repeater>
</StackLayout>
</GridLayout>
And this as NOT expected (with <Repeater.itemsLayout> and without wrapping by <StackLayout>):
<GridLayout columns="auto, *" rows="auto">
<Label text="Some Text" row="0" col="0" backgroundColor="orange"/>
<Repeater items="{{ items }}">
<Repeater.itemsLayout>
<StackLayout row="0" col="1" backgroundColor="green"/>
</Repeater.itemsLayout>
<Repeater.itemTemplate>
<Label text="{{ $value }}"/>
</Repeater.itemTemplate>
</Repeater>
</GridLayout>
Following code works because you are wrapping your Repeater in StackLayout and assiging it row and column and that is required as well if your putting that inside a GridLayout.
<GridLayout columns="auto, *" rows="auto">
<Label text="Some Text" row="0" col="0" backgroundColor="orange"/>
<StackLayout row="0" col="1" backgroundColor="green">
<Repeater items="{{ items }}">
<Repeater.itemTemplate>
<Label text="{{ $value }}"/>
</Repeater.itemTemplate>
</Repeater>
</StackLayout>
</GridLayout>
If you do not want to wrap inside a StackLayout, you should assign row="0" col="1" to Repeater.
Now comes to your question, that use of Repeater.itemsLayout, it gets or set the items layout of the Repeater. Default value is StackLayout with orientation="vertical".
So if you have a usecase where you want all the items in Repeater align horizontally, you should use following code.
<ScrollView row="0" col="0" orientation="horizontal">
<Repeater items="{{ items }}">
<Repeater.itemsLayout>
<StackLayout orientation="horizontal" />
</Repeater.itemsLayout>
<Repeater.itemTemplate>
<Label text="{{ $value }}" />
</Repeater.itemTemplate>
</Repeater>
</ScrollView>
We can set row and col properties for Repeater tag. Like so:
<GridLayout columns="auto, *" rows="auto, *">
<Label text="Some Text" row="0" col="0"/>
<Repeater row="1" items="{{ items }}">
<Repeater.itemsLayout>
<StackLayout orientation="horizontal" />
</Repeater.itemsLayout>
<Repeater.itemTemplate>
<Label text="{{ $value }}"/>
</Repeater.itemTemplate>
</Repeater>
</GridLayout>
Answer can be found here: https://github.com/NativeScript/NativeScript/issues/6554#issuecomment-438167999

Nativescript RadListView not visible on iOS

I have created an component with RadListView and placed on few pages in my application. The RadListView is inside an Panel, and the visibility of the RadListView is controlled using the Panel header. The functionality works appropriately on Android, however, on iOS(iPhone 5s iOS 11.1) the RadListView is not visible.
I have tried wrapping the RadListView with GridLayout, however, that doesn't work.
Version information: nativescript-ui-listview: ^3.5.1, tns-core-modules: ^3.4.1
Component code:
<StackLayout xmlns:lv="nativescript-ui-listview">
<GridLayout rows="*" columns="auto, *, auto" verticalAlignment="top" onTap="EntityHeaderTap" class="entity-header">
<Image row="0" col="0" width="23" src="res://detail_Employee" verticalAlignment="center"/>
<StackLayout row="0" col="1" orientation="horizontal" verticalAlignment="center" marginLeft="10">
<Label id="entityLabel" text="Employee" fontSize="15" verticalAlignment="center" color="#706e77"/>
</StackLayout>
<Image id="entityArrow" row="0" col="2" width="14" src="res://arrow_u" verticalAlignment="center" />
</GridLayout>
<StackLayout id="entityContent" visibility="collapse" class="entity-content">
<lv:RadListView id="employeeListView" items="{{ Employees }}" itemTap="EmployeeItemTap" visibility="{{ Employees ? 'visible' : 'collapsed' }}" selectionBehavior="None" separatorColor="transparent" height="100%">
<lv:RadListView.itemTemplate>
<GridLayout columns="*, 17" rows="50" class="{{ IsLast ? 'entity-item-last' : 'entity-item' }}">
<StackLayout col="0" verticalAlignment="center" marginLeft="5">
<Label text="{{ FullName ? FullName : '' }}" textWrap="true" fontSize="14" color="#4B4F63"/>
<Label text="{{ OrganisationName ? OrganisationName : '' }}" visibility="{{ OrganisationName ? 'visible' : 'collapsed' }}" textWrap="true" fontSize="12" color="#706e77"/>
</StackLayout>
<Image col="1" src="res://arrow_r" width="6" verticalAlignment="center"></Image>
</GridLayout>
</lv:RadListView.itemTemplate>
</lv:RadListView>
<StackLayout visibility="{{ Employees ? 'collapsed' : 'visible' }}">
<Label text="No record found" fontSize="14" padding="5" margin="0 5" color="#aeafb7" />
</StackLayout>
</StackLayout>
</StackLayout>
Implementation
<GridLayout rows="auto, auto, *, auto">
<ScrollView row="3" visibility="{{ selectedTabIndex == 2 ? 'visible' : 'collapsed' }}">
<GridLayout rows="auto, auto, auto, auto, auto, auto, *" columns="*, *" class="tab-container" paddingBottom="15">
....
<SearchComponent:EmployeePanel row="3" colSpan="2" marginTop="15" />
</GridLayout>
</ScrollView>
</GridLayout>
The thing is that StackLayout does not have predefined size and will take the space needed for its children component. In this case, the RadListView is also lacking a predefined size (height="100%" but the parent stack layout is measured with infinity).On iOS, the native control behind the list view needs a size to measure and occupy.
So as a possible solution try to either provide a size (for the container or directly to the RadListView) or use GridLayout with rows="*" to take all available space and then set row="0" to your RadListView
For example something like this:
<GridLayout rows="auto, 500" xmlns:lv="nativescript-ui-listview">
<GridLayout row="0" rows="*" columns="auto, *, auto" verticalAlignment="top" onTap="EntityHeaderTap" class="entity-header">
<Image row="0" col="0" width="23" src="res://detail_Employee" verticalAlignment="center"/>
<StackLayout row="0" col="1" orientation="horizontal" verticalAlignment="center" marginLeft="10">
<Label id="entityLabel" text="Employee" fontSize="15" verticalAlignment="center" color="#706e77"/>
</StackLayout>
<Image id="entityArrow" row="0" col="2" width="14" src="res://arrow_u" verticalAlignment="center" />
</GridLayout>
<lv:RadListView row="1" id="employeeListView" items="{{ Employees }}" itemTap="EmployeeItemTap" visibility="{{ Employees ? 'visible' : 'collapsed' }}" selectionBehavior="None" separatorColor="transparent" height="100%">
<lv:RadListView.itemTemplate>
<GridLayout columns="*, 17" rows="50" class="{{ IsLast ? 'entity-item-last' : 'entity-item' }}">
<StackLayout col="0" verticalAlignment="center" marginLeft="5">
<Label text="{{ FullName ? FullName : '' }}" textWrap="true" fontSize="14" color="#4B4F63"/>
<Label text="{{ OrganisationName ? OrganisationName : '' }}" visibility="{{ OrganisationName ? 'visible' : 'collapsed' }}" textWrap="true" fontSize="12" color="#706e77"/>
</StackLayout>
<Image col="1" src="res://arrow_r" width="6" verticalAlignment="center"></Image>
</GridLayout>
</lv:RadListView.itemTemplate>
</lv:RadListView>
</GridLayout >
Or instead of explicitly setting DP you can use the star symbol to take all space available
rows="auto, *"

nativescript 'this' inside tkListViewHeader (RadListView header directive)

I'm using the TKListViewHeaderDirective of teleriks RadListView in nativescript like so:
<GridLayout columns="*" rows="*" tkToggleNavButton>
<RadListView *ngIf="!loading" row="3" col="0" [items]="nodes" ...>
<ng-template tkListItemTemplate let-node="item">
<!-- list item -->
</ng-template>
<ng-template tkListViewHeader>
<GridLayout columns="*" rows="auto, auto, auto">
<GridLayout row="0" col="0" columns="40,*,40">
<Button class="fa action-item" row="0" col="0" [text]="'fa-sort-amount-asc' | fonticon" ios.position="right" android="actionBar" style="background-color:#c9c9ce;;"></Button>
<SearchBar row="0" col="1" #searchInput hint="Search" (submit)="search(searchInput.text)" (clear)="search('')" (textChange)="search(searchInput.text)"></SearchBar>
<Button class="fa action-item" row="0" col="2" [text]="'fa-th' | fonticon" ios.position="right" android="actionBar" style="background-color:#c9c9ce;"></Button>
</GridLayout>
<StackLayout row="1" col="0">
<Label text="Hello world"></Label>
<Label [text]="currentNode.name"></Label>
<Label [text]="nodes?.length ? nodes.length : 0"></Label>
</StackLayout>
<StackLayout row="2" col="0" *ngIf="!nodes?.length" class="list-group">
<!-- some contents -->
</StackLayout>
<StackLayout row="3" col="0" *ngIf="currentNode?.name !== '/'" class="list-group">
<!-- some contents -->
</StackLayout>
</GridLayout>
</ng-template>
</RadListView>
</GridLayout>
it seems like two things go wrong here:
this seems to be missing here (the *ngIf should show one of the StackLayouts in specific cases but does not
The GridLayout (does not have any effect if I change it to StackLayout) inside the list header shows only one child element
According to the docs: http://docs.telerik.com/devtools/nativescript-ui/Controls/Angular/ListView/header-footer
There is an issue on github concerning this: https://github.com/telerik/nativescript-ui-feedback/issues/207

Resources