Is there a way to make a NativeScript GridLayout with a fixed aspect ratio? - grid-layout

First of all, I'd like to apologize if I fail to comply with any SO rules, as it's my first question.
What I'm trying to acomplish, is having a square gridLayout in my page. The behavior should be equivalent to having an element with stretch="aspectFit".
If the suggested solution could let me enforce any given aspect ratio instead of just a square one, it would be a nice plus, because it would allow me to solve multiple situations in the future. Or if it could be applied to any Layout element, it would also be nice.
The solution can be as hacky as desired, and the GridLayout can be nested in any way you need to acomplish this.
I have already tried to hack it like this:
<GridLayout rows="*,auto,*" columns="*,auto,*" backgroundColor="green">
<Image row="1" col="1" src="~/Images/1px-black.png" stretch="aspectFit" width="100%"></Image>
<StackLayout row="1" col="1" orientation="vertical" backgroundColor="lightgray">
<Label text="Label 1" width="100%" height="25%" backgroundColor="red"></Label>
<Label text="Label 2" width="100%" height="25%" backgroundColor="green"></Label>
<Label text="Label 3" width="100%" height="25%" backgroundColor="blue"></Label>
<Label text="Label 4" width="100%" height="25%" backgroundColor="yellow"></Label>
</StackLayout>
</GridLayout>
Visually it seemed to work, but the contents of the GridLayout didn't fill it apropriately
PS: I just noticed in the example I chose, the layout element I am trying to make square is the nested StackLayout, but it's the same idea. I need a way to make a nested layout element squared.

Thanks to #Nathanael for giving me insights into what I could possibly do.
I found the solution and here it is for anyone who might need it.
First of all, I'll be using the following Template:
<GridLayout rows="2*,3*,*,3*,*,3*,*,3*,2*" columns="2*,3*,*,3*,*,3*,*,3*,2*" backgroundColor="green" #refGrid>
<Label text="A1" col="1" row="1" backgroundColor="#899bfe"></Label>
<Label text="A2" col="1" row="3" backgroundColor="#899bfe"></Label>
<Label text="A3" col="1" row="5" backgroundColor="#899bfe"></Label>
<Label text="A4" col="1" row="7" backgroundColor="#899bfe"></Label>
<Label text="B1" col="3" row="1" backgroundColor="#899bfe"></Label>
<Label text="B2" col="3" row="3" backgroundColor="#899bfe"></Label>
<Label text="B3" col="3" row="5" backgroundColor="#899bfe"></Label>
<Label text="B4" col="3" row="7" backgroundColor="#899bfe"></Label>
<Label text="C1" col="5" row="1" backgroundColor="#899bfe"></Label>
<Label text="C2" col="5" row="3" backgroundColor="#899bfe"></Label>
<Label text="C3" col="5" row="5" backgroundColor="#899bfe"></Label>
<Label text="C4" col="5" row="7" backgroundColor="#899bfe"></Label>
<Label text="D1" col="7" row="1" backgroundColor="#899bfe"></Label>
<Label text="D2" col="7" row="3" backgroundColor="#899bfe"></Label>
<Label text="D3" col="7" row="5" backgroundColor="#899bfe"></Label>
<Label text="D4" col="7" row="7" backgroundColor="#899bfe"></Label>
</GridLayout>
My goal is to make the GridLayout look square and centered on the screen, no matter the device or screen aspect ratio. To accomplish this I did the following in JavaScript (or TypeScript in this case, as I'm working with Angular2 + Nativescript) inside the Component Definition
ngAfterViewInit() {
let grid: GridLayout = <GridLayout>this.refGrid.nativeElement;
var x = grid.getActualSize();
function wait() {
if (x.width <= 0) {
x = grid.getActualSize();
setTimeout(wait, 10);
} else {
grid.width=Math.min(x.width, x.height);
grid.height=Math.min(x.width, x.height);
}
}
wait();
}
And this was the result:
Square GridLayout in multiple screen resolutions and aspect ratios

You can use the native properties of a grid layout. You will need to ensure your grid fills the whole screen (can be done by targeting it with a css class). Then you can create the resolution you need in rows and columns, note the use of x* to define relative widths, my chosen demo has 10, so * represents 10%.
You can then nest other layouts in the grid cells if you wish.
<GridLayout rows="*,*,*,*" columns="*,2*,3*,4*">
<Label row="0" col="0" [colSpan]="4" backgroundColor="lightgray"> // Will be 100% width, height will be 10%
</Label>
<Label row="1" col="0" [colSpan]="4" backgroundColor="blue"> // Will be 100% width, height will be 20%
</Label>
<Label row="2" col="0" [colSpan]="4" backgroundColor="green"> // Will be 100% width, height will be 30%
</Label>
<Label row="3" col="0" [colSpan]="4" backgroundColor="red"> // Will be 100% width, height will be 40%
</Label>
</GridLayout>
Hope that helps.

The code below worked for me - it uses up all space of the screen. You might want something different for larger screens though.
<FlexboxLayout flexDirection="row" flexWrap="wrap">
<GridLayout flexGrow="1" row="*" columns="*" *ngFor="let tile of tiles" [width]="len" [height]="len">
<StackLayout horizontalAlignment="center" verticalAlignment="center">
<Label [text]="tile.line"></Label>
</StackLayout>
</GridLayout>
</FlexboxLayout>
The value len is computed as follows:
import {isAndroid, isIOS, screen} from "tns-core-modules/platform";
...
ngAfterViewInit() {
this.len = screen.mainScreen.widthDIPs / 2;
}

Related

Xamarin's forms Date Picker android icon a bit out of way

I am trying to place a synfcusion button that has a calendar image near a xarmain forms entry box.
But its a bit out of alignment what I have tried so far is.
<Label Text="Please select a start date below"></Label>
<StackLayout Orientation="Horizontal">
<Entry x:Name="txtDateStartEntry" WidthRequest="200" ></Entry>
<syncfusion:SfButton x:Name="btnPickStartDate" CornerRadius="10" HorizontalTextAlignment="Start" ShowIcon="True" Clicked="btnPickStartDate_Clicked" FontSize="24" BorderThickness="2" TextColor="White" BackgroundColor="White" Text="..." >
<syncfusion:SfButton.Content>
<Grid ColumnDefinitions="Auto, *, Auto" ColumnSpacing="16" Padding="16">
<Image Grid.Column="1" HorizontalOptions="End" WidthRequest="30" HeightRequest="30" Source="cal16.png" VerticalOptions="End"/>
</Grid>
</syncfusion:SfButton.Content>
</syncfusion:SfButton>
</StackLayout>
What I have eneded up with is this.
As you can see its a bit far away from the entry field and doesnt look like it belongs.
If you're using Syncfusion, you should make use of SfTextInputLayout which provides leading/trailing view functionality for the express purpose of adding descriptive iconography to an input view.
Code example assumes importing the following xmlns:
xmlns:sftl="clr-namespace:Syncfusion.XForms.TextInputLayout;assembly=Syncfusion.Core.XForms"
<sftl:SfTextInputLayout TrailingViewPosition="Inside">
<Entry x:Name="txtDateStartEntry" WidthRequest="200" />
<sftl:SfTextInputLayout.TrailingView>
<Image HeightRequest="30" Source="cal16.png">
<Image.GestureRecognizers>
<TapGestureRecognizer Tapped="btnPickStartDate_Clicked" />
</Image.GestureRecognizers>
</Image>
<sftl:SfTextInputLayout.TrailingView>
</sftl:SfTextInputLayout>
Note: when using LeadingView or TrailingView, it's recommended to not assign a Width value as Syncfusion will calculate the width based on the height you request to maintain aspect ratio of the specified view. Therefore I have intentionally excluded HeightRequest from the Image.

Flexlayout or grid for better screen sizes handling

Xamarin layout advice
Hi given the nature of mobile devices screen sizes as a rule of thumb when building screen
would you say use "Flexlayout" all the time rather than a grid.
It is my understanding that the flexlayout is more suitable for adapting to various screens sizes without building complexity in your pages.
Still do not understand "Grow and shrink" despite reading few documentations.
How would you describe grow and shrink?
Sample one
<Grid
RowSpacing="0">
<Grid.RowDefinitions>
<RowDefinition Height="3*" />
<RowDefinition Height="6*" />
<RowDefinition Height="1*" />
</Grid.RowDefinitions>
<StackLayout Grid.Row="0" BackgroundColor="Green">
<Label Text="Header with logo"
HorizontalTextAlignment="Center"
VerticalTextAlignment="Center" />
</StackLayout>
<StackLayout Grid.Row="1" BackgroundColor="LightBlue">
<Label Text="Content"
HorizontalTextAlignment="Center"
VerticalTextAlignment="Center" />
</StackLayout>
<StackLayout Grid.Row="2" BackgroundColor="Red">
<Label Text="Footer"
HorizontalTextAlignment="Center"
VerticalTextAlignment="Center" />
</StackLayout>
</Grid>
VS
<FlexLayout Direction="Column">
<!-- Header -->
<Label Text="HEADER"
FontSize="Large"
BackgroundColor="Aqua"
HorizontalTextAlignment="Center" />
<!-- Body -->
<FlexLayout FlexLayout.Grow="1">
<!-- Content -->
<Label Text="Content"
FontSize="Large"
BackgroundColor="Gray"
HorizontalTextAlignment="Center"
VerticalTextAlignment="Center"
FlexLayout.Grow="1" />
</FlexLayout>
<!-- Footer -->
<Label Text="FOOTER"
FontSize="Large"
BackgroundColor="Pink"
HorizontalTextAlignment="Center" />
</FlexLayout>
Grow setting of 1. This means that all the extra vertical space is allocated to this blank Label like these screenshot.
I add second label called content2, if I set grow 0, content2 will not fill extra vertical space
if I set grow 1, content2 will fill extra vertical space
shrink property plays a role when the Wrap property is set to NoWrap and the aggregate width of a row of children is greater than the width of the FlexLayout, or the aggregate height of a single column of children is greater than the height of the FlexLayout. Normally the FlexLayout will display these children by constricting their sizes. The Shrink property can indicate which children are given priority in being displayed at their full sizes.
You can download this demo, and test it by yourself.
https://developer.xamarin.com/samples/xamarin-forms/UserInterface/FlexLayoutDemos/

is it possible to change css properties of class label in nativescript

I have used label class for every label in my project. If any other font color like
class="label font-clr-green"
is applied then it not taking green color. So I decided to overwrite the label class in app.css but it's also a failure. I need to know whether label class can be overridden or not.
I checked your Playground Sample and what I could deduce from it is, that the <Label> used in the problem part is not taking the green color as it should be. Well, that's because you are using this <Label> element inside a <StackLayout> having class input-field. It seems like, CSS for .input-field Label is pre-defined.
The solution to your problem, would be to rename this class input-field to something else. That's all it needed. Below is the updated XML part. You can also check my attached Playground demo with the fix.
<Page loaded="pageLoaded" class="page" xmlns="http://www.nativescript.org/tns.xsd">
<ActionBar title="Home" class="action-bar">
</ActionBar>
<ScrollView>
<StackLayout class="form">
<!--this was working fine -->
<Label textWrap="true" text="Play with NativeScript!" class="label font-weight-bold m-b-5 fcg" />
<Label textWrap="true" text="Play with NativeScript!" class="label font-weight-bold m-b-5"
color="green" />
<!-- the problem was here, solution was to rename input-field to input-field-1 -->
<StackLayout class="input-field-1">
<StackLayout class="okay">
<Label text="Active Flag" class="label font-weight-bold m-b-5 fcg" />
</StackLayout>
<Switch checked="true" class="switch fcg"
horizontalAlignment='left' margin="0" />
<StackLayout class="hr-light"></StackLayout>
</StackLayout>
</StackLayout>
</ScrollView>
Working Playground Demo.

Picker with custom Items [Xaml]

I am trying to figure out a way how to create a picker with custom items in XAML. I am not sure if it is possible to achieve this task only using xaml. The picker would have to contain items that consist of a label and a switch. The code below illustrates the end goal:
<Picker Title="Picker title here">
<Picker.ItemsSource>
<StackLayout Orientation="Horizontal">
<Label Text="Hello Xamarin.Forms!" />
<Switch />
</StackLayout>
<StackLayout Orientation="Horizontal">
<Label Text="Hello Xamarin.Forms2!" />
<Switch />
</StackLayout>
</Picker.ItemsSource>
</Picker>
It's not possible. I think you can create a Popup with a ListView, where you have a ViewCell with all controls you need

auto resizing the height of the views

<ScrollView id="scrollGeneric" height ='auto' visible='false'>
<View id="formView" height='auto'>
<View id='distSlider' top='0' height='100'>
<Label id="lblGeneric" >
Search Distance:
</Label>
<Slider id="sliderDistance" top="50" min="2" max="80" width="50%"/>
<Label id="sliderDistanceText" width='auto' top="50" right="40" />
<Label id="sliderDistanceTextMeasure" width='auto' top="50" right="10" text="km" />
</View>
</View>
</ScrollView>
I have set the height auto for scrollView and formView. However whenever I add more views inside of the formView the size of the window does not expand vertically with it. It will eventually crop out the views that exceed the window height.
The only way to solve this is to manually specify the height of each view within the form view div.
Is there anyway I can avoid doing this, thanks
Have you tried using Ti.UI.SIZE instead for the height? As per the documentation, "height:auto is not recommended for new development and will be deprecated in the future."

Resources