如何在 NativeScript 中的绝对布局底部定位元素?
Posted
技术标签:
【中文标题】如何在 NativeScript 中的绝对布局底部定位元素?【英文标题】:How to position element at the bottom of Absolute Layout in NativeScript? 【发布时间】:2017-12-24 09:07:34 【问题描述】:我想在 NativeScript 中的绝对布局中将一个元素定位在屏幕底部。
我有这个代码:
<AbsoluteLayout>
<maps:mapView
left="0"
top="0"
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"
orientation="horizontal">
<!-- More XML -->
</ScrollView>
<StackLayout
left="0"
bottom="0"
visibility="visible"
orientation="horizontal"
style="background-color: red;">
<Label text="TITLE"></Label>
</StackLayout>
</AbsoluteLayout>
我发现AbsoluteLayout没有底部属性...这是我要创建的图片:
那么如何排列图片中的物品,尤其是底部的物品?
编辑:我应该注意这个底部矩形的尺寸可能并不总是相同的......
【问题讨论】:
【参考方案1】:GridLayout也可以做到:
<GridLayout rows="16,*,16" columns="16,*,16" 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>
【讨论】:
【参考方案2】:这是绝对最佳的解决方案,从其中一位开发者处获得:https://github.com/NativeScript/NativeScript/issues/5591#issuecomment-482640921
<GridLayout rows="*,auto">
<ItemTakingFullScreen rowSpan="2"/>
<ItemShownUnder row="1"/>
<ItemShownAbove row="1">
</GridLayout>
基本上,您可以使用网格布局,让一个项目占据多个网格空间,并与其他项目共享。
【讨论】:
【参考方案3】:这是最好的解决方案 将所有元素包装在一个绝对布局中,宽度和高度为 100%,并可能添加一个网格布局来保存主要内容。
<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>
【讨论】:
【参考方案4】:另一种选择是在您的 AbsoluteLayout 容器中使用 FlexboxLayout,如下所示:
<FlexboxLayout flexDirection="column" justifyContent="space-between" >
<ScrollView
orientation="horizontal">
<!-- More XML -->
</ScrollView>
<StackLayout
visibility="visible"
orientation="horizontal"
style="background-color: red;">
<Label text="TITLE"></Label>
</StackLayout>
</FlexboxLayout>
【讨论】:
【参考方案5】:有一天我做了类似的事情,以编程方式 & 使用 Angular,也许这会有所帮助。
如果您不想使用 GridLayout,您可以尝试获取底部元素和屏幕的高度,然后通过简单的计算从顶部放置元素:屏幕的高度 - 底部元素的高度(如果你想要一些填充)。您可以使用两种类型的值:DIP 和像素。如果您使用像素,则需要使用屏幕比例将值转换为 DIP。
类似这样的(我没有测试我给你的代码,这只是一个例子):
1] 为你的底部元素添加一个 id,这样你就可以在你的组件中访问它:
<StackLayout #bottomElt></StackLayout>
2] 更新您的组件以在绝对布局中设置元素位置
// 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)));
有关屏幕值的更多信息:https://docs.nativescript.org/api-reference/interfaces/platform.screenmetrics.html
另一种方式
您可以使用 GridLayout 来设置底部栏,而不是使用 AbsoluteLayout,它有两行:一排具有通配符大小,另一排具有自动大小,以便每次更改时都能适应底部栏的高度。我在移动应用程序中这样做是为了在 android 和 ios 的底部获得一个菜单:
<GridLayout rows="*, auto" >
<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>
【讨论】:
你知道我怎样才能计算底栏的高度,因为它里面的内容会随着时间的推移而改变,而且它也会被显示/隐藏。所以我需要在显示它之前计算它的新高度......或者即使它被隐藏它也会在内容更改后更新它的高度而我不计算它? 您可以使用getMeasuredHeight()
函数并将其转换为DIP,然后在每次更改他的内容时更改他的位置。您也可以采用完全不同的方式:使用 GridLayout 显示底部栏,您可以使用 visibility
属性隐藏/显示该栏。这样,无论他的身高如何,您的底栏都将始终位于底部,并且主要内容将始终填满所有可用空间。我将在我的答案中添加此选项
我选择了第一个解决方案。因此,布局最初是隐藏的,标签是空的。在未来的某个时候,一个事件被触发,它应该用适当的文本显示这个隐藏的布局。所以我写bottomBarLabel.text='some text'; let h = bottomBar.getMeasuredHeight();
。但是 bottomBar 的高度为零,至少 getMeasuredHeight() 返回零。但是我设置了一个超时来运行,并在该超时打印出 getMeasuredHeight() 并且它是正确的,但我不喜欢使用超时函数来等待组件计算它的高度....
不错的解决方案。在 Angular 中,我会将计算移至“ngAfterViewInit()”,以避免在 Angular 完成绘制之前尝试访问元素时出错。以上是关于如何在 NativeScript 中的绝对布局底部定位元素?的主要内容,如果未能解决你的问题,请参考以下文章
NativeScript BottomNavigation -> 如何在底部导航项点击时打开默认页面?
如何在 NativeScript 布局中查找/查看视图的尺寸?