How do I position an element at the bottom of an Absolute layout in NativeScript?
I want to position an element at the bottom of the screen in an absolute layout in NativeScript.
I have this code:
<AbsoluteLayout>
<maps:mapView
left="0"
top="0"
width="100%"
height="100%"
latitude="{{ map.latitude }}"
longitude="{{ map.longitude }}"
zoom="{{ map.zoom }}"
padding="{{ map.padding }}"
mapReady="onMapReady"
coordinateTapped="onCoordinateTapped"
markerSelect="onMarkerSelect"
shapeSelect="onShapeSelect"
cameraChanged="onMapCameraChanged"/>
<ScrollView
left="0"
top="0"
width="100%"
orientation="horizontal">
<!-- More XML -->
</ScrollView>
<StackLayout
left="0"
bottom="0"
width="100%"
visibility="visible"
orientation="horizontal"
style="background-color: red;">
<Label text="TITLE"></Label>
</StackLayout>
</AbsoluteLayout>
I figured out that the bottom attribute is missing for AbsoluteLayout ... Here is a picture of what I want to create:
So how do you arrange the elements like in the picture, especially the bottom one?
EDIT: I should note that the dimensions of this bottom rectangle may not always be the same ....
source to share
I did something like this one day, programmatically & with Angular , maybe it can help.
If you don't want to use a GridLayout, you can try to get the height of your bottom element and screen, then position your element on top with a simple calculation: screen height - bottom element height (- more if you need a little padding). You can use two types of values: DIP and Pixels. If you are using pixels, you need to convert your values ββto DIP using the screen scale.
Something like this (I have not tested the code I am giving you, this is just an example):
1] add an id to your bottom element so you can access it inside your component:
<StackLayout #bottomElt></StackLayout>
2] update your component to set the position of the element in your absolute layout
// you need ElementRef, OnInit and ViewChild
import { Component, ElementRef, OnInit, ViewChild, ViewContainerRef } from "@angular/core";
import { AbsoluteLayout } from "ui/layouts/absolute-layout";
import { StackLayout } from "ui/layouts/stack-layout";
// you need access to screen properties
import { screen } from "tns-core-modules/platform";
[...]
export class YourComponent implements OnInit {
// add access to element inside your component
@ViewChild("bottomElt") bottomElt: ElementRef;
// create variable to access bottom element properties
bottomContainer: StackLayout;
// set bottom element position after view init
// example : inside ngOnInit function (for Angular version)
ngOnInit(): void {
this.bottomContainer = <StackLayout>this.bottomElt.nativeElement;
// using DIPs values only
AbsoluteLayout.setTop(this.bottomContainer, (screen.mainScreen.heightDIPs - Number(this.bottomContainer.height)));
// using pixels and screen scale
// this way you can get height without knowing it
AbsoluteLayout.setTop(this.bottomContainer, (screen.mainScreen.heightDIPs - (Number(this.bottomContainer.getMeasuredHeight()) / screen.mainScreen.scale)));
}
More information on screen values: https://docs.nativescript.org/api-reference/interfaces/platform.screenmetrics.html
Alternative way
Instead of using an AbsoluteLayout, you can use a GridLayout to set up a bottom bar with two rows, one with a wildcard font and one with an auto size so that every time it changes it can fit your bottom bar height. I did this in a mobile app to get the menu at the bottom in Android and IOS:
<GridLayout rows="*, auto" width="100%">
<AbsoluteLayout row="0" orientation="vertical">
<!-- YOUR CONTENT (maps & ScrollView) -->
</AbsoluteLayout>
<!-- YOUR BOTTOM BAR (StackLayout). Don't forget to add row="1" -->
<StackLayout #bottomElt row="1">[...]</StackLayout>
</GridLayout>
source to share
Another option is to use FlexboxLayout in your AbsoluteLayout container like this:
<FlexboxLayout flexDirection="column" justifyContent="space-between" height="100%">
<ScrollView
width="100%"
orientation="horizontal">
<!-- More XML -->
</ScrollView>
<StackLayout
width="100%"
visibility="visible"
orientation="horizontal"
style="background-color: red;">
<Label text="TITLE"></Label>
</StackLayout>
</FlexboxLayout>
source to share
Here's a better solution - wrap all the elements in absolute decomposition with width and height up to 100% and possibly add grid markup to hold the main content.
<AbsoluteLayout width='100%' height='100%'>
<StackLayout width='100%' hieght='100%' left='0' top='0'>
//add you structure here
</StackLayout>
add your fixed element here
<image src='add the float item'/>
</AbsoluteLayout>
source to share
This is absolutely the best solution I got from one of the developers: https://github.com/NativeScript/NativeScript/issues/5591#issuecomment-482640921
<GridLayout rows="*,auto">
<ItemTakingFullScreen rowSpan="2"/>
<ItemShownUnder row="1"/>
<ItemShownAbove row="1">
</GridLayout>
Basically, you can use a grid and force an element to take up multiple grid spaces by sharing them with another element.
source to share