How can I maintain the ratio of the space occupied by the components on the screen when the screen resizes.
I have the code that looks something like as written below,
where the size of the webview1 is reduced while size if webview2 is increased on screen readjustment.
I want that both the webviews occupy equal amount of space on the screen post screen readjustment.
Content = new StackLayout
{
Spacing = 0,
Padding = 0,
Children = {
wewbview1,
new StackLayout
{
BackgroundColor=Color.FromHex("#000033"),
Padding=2,
Children=
{
webview2
},
VerticalOptions = LayoutOptions.FillAndExpand
},
txt_Search
}
};
I would use an AbsoluteLayout to embed the two WebViews as you can than control the height ratio as a percentage and embed that into a StackLayout to bundle in your "text_search" at that bottom.
In the following example, AFTER removing the height of the "txt_Search" (I'm using a BoxView as a placeholder), the top web view gets 40% of the remaining space an the second web view gets 60%. Flip that to portrait and everything resizes correctly and maintains the 40/60 split after removing the space required for the "text_search".
Note: I did it in Xamarin.Forms XAML, but it is a simple conversion to code.
<StackLayout VerticalOptions="FillAndExpand">
<AbsoluteLayout
VerticalOptions="FillAndExpand"
HorizontalOptions="FillAndExpand">
<!--Top WebView-->
<BoxView
Color="Silver"
AbsoluteLayout.LayoutBounds="0, 0, 1, 0.4"
AbsoluteLayout.LayoutFlags="All" />
<!--Bottom WebView-->
<BoxView
Color="Maroon"
AbsoluteLayout.LayoutBounds="1, 1, 1, 0.6"
AbsoluteLayout.LayoutFlags="All" />
</AbsoluteLayout>
<!--Search txt_Search-->
<BoxView
Color="Green"
HeightRequest="50" />
</StackLayout>
Related
I have this sample code that works as I want:
<ScrollView orientation="horizontal">
<GridLayout columns="*,*,*,*,*,*" >
<Label class="gridlabel" col="0" text="Monday" />
<Label class="gridlabel" col="1" text="Tuesday" />
<Label class="gridlabel" col="2" text="Wednesday" />
<Label class="gridlabel" col="3" text="Thursday" />
<Label class="gridlabel" col="4" text="Friday" />
<Label class="gridlabel" col="5" text="Saturday" />
</GridLayout>
</ScrollView>
That is, the labels within the GridLayout scroll horizontally.
I have a component that generates a GridLayout, and now I need to wrap that in a horizontal ScrollView.
That is, I for each label:
let label = new Label();
// Add tap event handler for each tab
label.on("tap", function () {
onTabTap(label, "tabTap");
}.bind(label));
label.id = key;
label.text = key;
label.class = "gridtab";
this.addColumn(new ItemSpec(1, GridUnitType.STAR));
GridLayout.setColumn(label, i);
GridLayout.setRow(label, 0);
this.addChild(label);
But when I try to add the ScrollView, I get errors. If I try to add the labels to the ScrollView, such as scrollView.addChild(label) (where scrollView is an instance of ScrollView), I get "scrollView.addChild is not a function". (See this similar SO post). If, as suggested in the mentioned post, I use scrollView.content = this; then I get the error, Error: View already has a parent.
So, the question is, from code, how do I replicate the hierarchy from my sample xml? That is, how can I wrap the generated GridLayout in a horizontal ScrollView?
Edit 7/17/2020
Upon reflection, I don't think this can work given my component's current design. That is, it subclasses GridLayout, and I want the generated GridLayout to be wrapped by a ScrollView, but that would be external to the content generated by the component, yes? It almost seems I'd need to subclasss ScrollView, and then generate the GridLayout within.
So, I was ultimately able to resolve this by subclassing StackLayout, then within the StackLayout adding a ScrollView, and within the ScrollView adding the GridLayout. The "magic" is:
scroll.content = grid;
this.addChild(scroll);
Where scroll is the ScrollView instance, and grid is the GridLayout instance.
Then, after spending a day on this I found I didn't actually need horizontal scrolling after all, but at least I know what to do should the need arise.
I have two labels side by side in a horizontally oriented stack layout. The labels have different font sizes. I would like to make the baseline (bottom edge) of each label text the same regardless of the font size. However the default behaviour of xamarin forms is not to do that. The following code
<StackLayout Orientation="Horizontal" >
<Label FontSize="12" Text="A Noble Spirit"></Label>
<Label FontSize="18" Text="Embiggens The Smallest Man"></Label>
</StackLayout>
Results in the following view running on android.
I've tried many different combinations of setting the vertical text alignment and the vertical options attributes on the labels. The best I've been able to come up with (and what I think should work) is adding vertical options = end to them both. This improves things a bit but there's still a mismatch, so that the bigger label's text (embiggens) starts higher up than the smaller label - like so:
<StackLayout Orientation="Horizontal" >
<Label VerticalOptions="End" FontSize="12" Text="A Noble Spirit"></Label>
<Label VerticalOptions="End" FontSize="18" Text="Embiggens The Smallest Man"></Label>
</StackLayout>
As you can see, somewhat of an improvement, but still not aligned. This is driving me up the wall a bit. I'm starting to think it may be a bug in Xamarin Forms for android. (I'll add to this question later when I can get an example running on iOS to see if it's android specific.).
I CAN hack it to sort of work by adding top margin to the smaller label that is equal to the difference in font size, which is gross and I don't want to introduce that technical debt and upkeep into my system. But here it is to show it. Hoping not to have to resort to this...
<StackLayout Orientation="Horizontal" >
<Label FontSize="12" Margin="0,6,0,0" Text="A Noble Spirit"></Label>
<Label FontSize="18" Text="Embiggens The Smallest Man"></Label>
</StackLayout>
Cause: If you set the background color of two labels ,you can see that because label has a default "Padding" . The value depends on its height .
Solution:
You can put two different strings in the same Label. It has the property called FormattedText ,which allows you to set the formatted text for the Label .
<StackLayout Orientation="Horizontal" VerticalOptions="CenterAndExpand" HorizontalOptions="CenterAndExpand">
<Label FormattedText="{Binding FormattedTextContent}" x:Name="label" ></Label>
<Label FormattedText="{Binding FormattedTextContent}" x:Name="label2" ></Label>
</StackLayout>
in code behind
FormattedTextContent = new FormattedString();
var fs = new FormattedString();
fs.Spans.Add(new Span { Text = "A Noble Spirit " , FontSize = 12, TextColor = Color.Black });
fs.Spans.Add(new Span { Text = " ", FontSize = 18 });
label.FormattedText = fs;
var fs1 = new FormattedString();
fs.Spans.Add(new Span { Text = " ", FontSize = 12 });
fs.Spans.Add(new Span { Text = "Embiggens The Smallest Man", TextColor = Color.Black, FontSize = 18 });
label2.FormattedText = fs1;
Of course you can use MVVM because it is a bindable property .
I want to add a button which have Two Text with different TextSize.
here is the sample
how to do this?
rather than a button why don't you make it something like a boxview, add your text as labels with different text sizes, then give the box a tap gesture?
add this in OnAppearing
var my_tap = new TapGestureRecognizer();
my_tap.Tapped += (s, e) =>
{
// do your thing;
};
YourBoxView.GestureRecognizers.Add(connect_tap);
Or a StackLayout:
<StackLayout x:Name="buttonStack" BackgroudColor="Blue">
<StackLayout.GestureRecognizers>
<TapGestureRecognizer Tapped="YourCode"></TapGestureRecognizer>
</StackLayout.GestureRecognizers>
<Label FontSize="Large">your text</Label>
<Label FontSize="Small">your other text</Label>
</StackLayout>
I'm trying to display a list of items within a list of items. Basically it's a card game, where each suit is being repeated, and then each card for each suit is being repeated.
<StackLayout margin="10 0 60 0" padding="0 0">
<ListView class="list-group" [items]="hand" (itemTap)="onItemTap($event)"
(itemLoading)="onItemLoading($event)" backgroundColor="#26252A"
style="height:100%">
<ng-template let-suit="item">
<FlexboxLayout flexDirection="row">
<ScrollView orientation="horizontal">
<StackLayout height="100" orientation="horizontal" margin="2.5, 15">
<ListView class="list-group" [items]="suit.cards">
<ng-template let-card="item">
<Label [text]="card" class="card"></Label>
</ng-template>
</ListView>
</StackLayout>
</ScrollView>
</FlexboxLayout>
</ng-template>
</ListView>
</StackLayout>
And this is what my "hand" looks like:
hand: { suit: Suit, fontColor: Color, cards: string[] }[] = [
{ suit: "Red", fontColor: new Color("red"), cards: ["14", "13"] },
{ suit: "Green", fontColor: new Color("green"), cards: ["14", "13", "12", "9"] },
{ suit: "Yellow", fontColor: new Color("yellow"), cards: ["14", "13", "10", "9"] },
{ suit: "Black", fontColor: new Color("black"), cards: ["14", "13", "9"] }
];
When I run it though, I'm only getting the very first card in each suit to be displayed.
You can check it out at the playground here:
https://play.nativescript.org/?template=play-ng&id=XfogFt&v=3
(I'm new to both NaitiveScript and Angular, so I may be missing something simple)
EDIT: It is not advisable to use nested listview as this would break
the recycling and virtualization for cells that are containing a
nested listview
You don't need a scrollview inside the ng-template, if you just remove it, it will show your all the items in each row of parent list.
<ListView class="list-group" [items]="hand" (itemTap)="onItemTap($event)"
(itemLoading)="onItemLoading($event)" backgroundColor="#26252A"
style="height:100%">
<ng-template let-suit="item">
<FlexboxLayout flexDirection="row">
<!-- <ScrollView orientation="horizontal"> -->
<StackLayout height="100" orientation="horizontal" margin="2.5, 15">
<ListView class="list-group" [items]="suit.cards">
<ng-template let-card="item">
<Label [text]="card" class="card"></Label>
</ng-template>
</ListView>
</StackLayout>
<!-- </ScrollView> -->
<Label text="Label"></Label>
</FlexboxLayout>
</ng-template>
</ListView>
I have updated the playground here. You can also use the itemHeight and itemWidth properties here for size tuning.
P.S. The itemHeight and itemWidth properties are iOS specific. If not used, items are sized dynamically depending on the data coming from the source.
As #Narendra mentioned it's not recommended to use nested list views or ngFor inside template.
I guess nativescript-accordion plugin will suit your needs, it basically supports the data structure you are looking for - List Item -> List of Items (Suit -> Cards). If you like to show the items expanded upon loading, all you have to do is, populate the selectedIndexes with all indexes. There is one issue with latest version of the plugin, which can be still handled with a simple math.
Preventing collapse upon tap is still an open feature request, but possible to achieve with an override. But as far I know, this plugin could be the only viable solution for nested list views.
I have this simple layout markup :
<StackLayout orientation="horizontal" #myStack>
<StackLayout width="300" backgroundColor="red">
</StackLayout>
<StackLayout width="300" backgroundColor="green">
</StackLayout>
</StackLayout>
As you can see , both are same width of 300:
Let's see this :
Notice that green is also 300 but we only see a part of it since 300+300 > screen size.
Ok so let's try to animate #myStack (!!) to the left , in order to see the left green :
ngOnInit(): void {
setTimeout(() => {
this.myStack.nativeElement.animate({
translate: { x: -300, y: 0 },
duration: 2000,
curve: enums.AnimationCurve.easeIn
});
},1000)
}
Question:
What is this white area on the right ? there should be also a green section there
Basically this is the situation :
So i'm expecting the green from the right to be scrolled to the left , i'm basically trying to move #myStack left.
How can I make the green area slide from the right ?
PLAYGROUND
Copy/paste this answer so that the community can see the provided solutions:
#RoyiNamir this is expected behavior.
What is happening is that by default the root layout will have an effective width (and height) as the screen size.
You need to explicitly create the wider container if you want to have an effective width larger than the screen width.
There are several approaches on how to achieve that.
- use container with fixed width - demo Playground here
<GridLayout rows="auto, *" columns="600" backgroundColor="lightgray">
<Button row="0" text="animate" (tap)="animate()"></Button>
<StackLayout row="1" orientation="horizontal" #myStack>
<StackLayout width="300" backgroundColor="red">
<Label text="Label"></Label>
</StackLayout>
<StackLayout width="300" backgroundColor="green">
<Label text="Label"></Label>
</StackLayout>
</StackLayout>
</GridLayout>
Note that our container GridLayout has columns set to 600.
Another option is instead of creating fixed size container to use ScrollView (which will measure its children so the children should have predefined size - in your case width="300") - demo Playground here
In the example above the container element is not needed (used just to create the animate Button).
The ScrollView will measure its children (300 + 300 = 600 width) and will take the space needed.