How to position element at the bottom of Absolute Layout in NativeScript?
Asked Answered
H

6

12

I want to position an element at the bottom of the screen in 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 there is no bottom attribute for AbsoluteLayout... Here is the picture of what I want to create:

enter image description here

So how to arange items like in the picture, especially the bottom one?

EDIT: I should note that dimensions of this bottom rectangle may not be always same....

Higgle answered 19/7, 2017 at 8:16 Comment(0)
A
8

I did something similar one day, programmatically & with Angular, maybe this can help.

If you don't want to use a GridLayout you can try to get height of your bottom element and of the screen, then place your element from the top with a simple calcul : screen's height - bottom element's height (- more if you want some padding). You can use two types of values : DIPs and pixels. If you're using pixels, you need to convert your values into DIPs by using the screen scale.

Something like this (I didn't test the code I'm giving you, it's 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 element position inside 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 about screen values : https://docs.nativescript.org/api-reference/interfaces/platform.screenmetrics.html

Alternative way

Instead of using AbsoluteLayout, you can use a GridLayout to set a bottom bar, with two rows : one with a wildcard size and the other with auto size so it can fit your bottom bar height everytime it changes. I did it this way in a mobile application to get a 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>
Arad answered 19/7, 2017 at 9:19 Comment(4)
Do you know maybe how can I can calculate height of bottom bar because the content inside of it will change overtime and also it will be shown/hidden. So I would need to calculate its new height before showing it... Or even if it is hidden it will update it's height after content is changed and I do not to calculate it?Higgle
You can use the getMeasuredHeight() function and convert it to DIPs before changing his position every time you change his content. You can do it a totally different way too : using GridLayout to display the bottom bar which you can hide/show using visibility property. This way your bottom bar will always be at the bottom, regarless his height, and the main content will always fill all available space. I'll add this option in my answerArad
I've went for the first solution. So, layout is initially hidden and label is empty. Sometime in the future, an event is trigger which should show this hidden layout with appropriate text. So I write bottomBarLabel.text='some text'; let h = bottomBar.getMeasuredHeight();. But the height of bottomBar is zero, at lease getMeasuredHeight() returns zero. However I set a timeout to run and in that timeout printed out getMeasuredHeight() and it got it right, but I do not like using timeout function to wait for component to calculate its height....Higgle
Nice solution. In Angular, I would move the calculation to 'ngAfterViewInit()' to avoid errors of trying to access the elements before Angular finishes drawing them.Wisteria
E
6

Another option is using 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>
Effable answered 11/8, 2017 at 10:43 Comment(0)
H
4

This is the absolute best solution, got it from one of the devs: 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 grid layout and have a item take up multiple grid spaces, sharing them with some other item.

Hewie answered 12/4, 2019 at 17:27 Comment(0)
B
0

here is the best solution wrapper all the elements in an absolutelayout with width and hieght to 100% and maybe add a gridlayout 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>
Ballade answered 4/7, 2018 at 12:9 Comment(0)
T
0

It can be done also with GridLayout:

<GridLayout rows="16,*,16" columns="16,*,16" width="100%" backgroundColor="red">
    <GridLayout row="1" col="1" rows="auto, auto, auto" columns="auto" horizontalAlignment="right" verticalAlignment="bottom" backgroundColor="blue">
        <!-- Your content at bottom right corner -->
        <Label row="0" text="Your content" textAlignment="center" textWrap="true"></Label>
        <Label row="1" text="at" textAlignment="center" textWrap="true"></Label>
        <Label row="2" text="bottom right corner" textAlignment="center"></Label>
    </GridLayout>
</GridLayout>
Tasteless answered 19/5, 2020 at 16:59 Comment(0)
R
0

This is the easy way

        <DockLayout backgroundColor="lightgray" stretchLastChild="true">

        <Label text="top" dock="top" height="60" backgroundColor="green">
        </Label>

        <Label text="bottom" dock="bottom" height="60" backgroundColor="yellow"></Label>
        <Label text="center" backgroundColor="red"></Label>
        </DockLayout>

enter image description here

This is what you want!

<DockLayout backgroundColor="lightgray" stretchLastChild="false">

        <Label text="top" dock="top" height="60" backgroundColor="green">
        </Label>

        <Label text="bottom" dock="bottom" height="60" backgroundColor="yellow"></Label>
     
    </DockLayout>

enter image description here

Rollet answered 21/2, 2022 at 6:1 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.