I'm trying to make piano-like layout using Grid in Xamarin.Forms. Looks fine but because of using RowSpan when I press one of my white buttons, it corrupts visibility of the black button near to it.
Example pressing button "D"
I tried to fix this by focusing to the "corrupted" black button when the white one is pressed but it didn't solve anything. I'd appreciate any tip.
Here's a part of my XAML:
<Grid.Resources>
<Style TargetType="Button">
<Setter Property="BackgroundColor" Value="White"/>
<Setter Property="Grid.RowSpan" Value="3"/>
<Setter Property="Grid.Row" Value="0"/>
<Setter Property="Grid.ColumnSpan" Value="3"/>
</Style>
</Grid.Resources>
<!--white buttons-->
<Button x:Name="C" Text="C" Grid.Column="0" Clicked="Button_Clicked"/>
<Button x:Name="D" Text="D" Grid.Column="3" Clicked="Button_Clicked"/>
<Button x:Name="E" Text="E" Grid.Column="6" Clicked="Button_Clicked"/>
<Button x:Name="F" Text="F" Grid.Column="9" Clicked="Button_Clicked"/>
<Button x:Name="G" Text="G" Grid.Column="12" Clicked="Button_Clicked"/>
<Button x:Name="A" Text="A" Grid.Column="15" Clicked="Button_Clicked"/>
<Button x:Name="H" Text="H" Grid.Column="18" Clicked="Button_Clicked"/>
<!--black buttons-->
<Button x:Name="Cis" Text="Cis" BackgroundColor="Black" TextColor="White" Grid.Row="0" Grid.Column="2" Grid.ColumnSpan="2" Grid.RowSpan="1" Clicked="Button_Clicked"/>
<Button x:Name="Dis" Text="Dis" BackgroundColor="Black" TextColor="White" Grid.Row="0" Grid.Column="5" Grid.ColumnSpan="2" Grid.RowSpan="1" Clicked="Button_Clicked"/>
<Button x:Name="Fis" Text="Fis" BackgroundColor="Black" TextColor="White" Grid.Row="0" Grid.Column="11" Grid.ColumnSpan="2" Grid.RowSpan="1" Clicked="Button_Clicked"/>
<Button x:Name="Gis" Text="Gis" BackgroundColor="Black" TextColor="White" Grid.Row="0" Grid.Column="14" Grid.ColumnSpan="2" Grid.RowSpan="1" Clicked="Button_Clicked"/>
<Button x:Name="Ais" Text="Ais" BackgroundColor="Black" TextColor="White" Grid.Row="0" Grid.Column="17" Grid.ColumnSpan="2" Grid.RowSpan="1" Clicked="Button_Clicked"/>
This is caused by Xamarin.Forms Fast Renderers:
From Xamarin.Forms 4.0 onwards, all applications targeting FormsAppCompatActivity will use these fast renderers by default.
The quickest way to solve this problem is adding the following line of code to your MainActivity class before calling Forms.Init to override the fast renderers:
Forms.SetFlags("UseLegacyRenderers");
You can also write a custom renderer of Button to improve the behavior.
I uploaded a sample project here and you can check it.
Related
I have a login page and my code is this:
<ContentPage.Content>
<Grid>
<StackLayout Orientation="Vertical" Padding="20">
<Entry Placeholder="{x:Static resources:AppResources.EMB_PLACEHOLDER}" Keyboard="Numeric" Text="{Binding EMB}"></Entry>
<Button Text="{x:Static resources:AppResources.LOGIN_BTN}" TextColor="White" Padding="0,-20" BackgroundColor="#07987f" Command="{Binding LoadLoginCommand}"></Button>
<Label
Margin="0,10,0,0" >
<Label.FormattedText>
<FormattedString>
<Span Text="{x:Static resources:AppResources.MESSAGE} "></Span>
</FormattedString>
</Label.FormattedText>
</Label>
<Grid Margin="0,10,0,0" >
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Label Padding="20,0,0,0" Text="{x:Static resources:AppResources.LBLLANGUAGE}" VerticalOptions="Center" FontSize="Body" TextColor="Gray" Grid.Column="0"/>
<Picker x:Name="languagePicker" Grid.Column="1" ItemsSource="{Binding Languages}" Title="{x:Static resources:AppResources.LBLLANGUAGE}" ItemDisplayBinding="{Binding Name}" SelectedItem="{Binding SelectedLanguage, Mode=TwoWay}"></Picker>
</Grid>
</StackLayout>
<StackLayout HorizontalOptions="Center" VerticalOptions="Center">
<ActivityIndicator IsVisible="{Binding IsBusy}" IsRunning="{Binding IsBusy}" HorizontalOptions="Center" VerticalOptions="Center"></ActivityIndicator>
<Label Text="{x:Static resources:AppResources.TSMSG1}" HorizontalTextAlignment="Center" VerticalTextAlignment="Center" HorizontalOptions="Center" VerticalOptions="Center" IsVisible="{Binding IsBusy}"/>
</StackLayout>
</Grid>
</ContentPage.Content>
Have a picker with list of languages. Also have resx file for every language. My scenario is when i click on picker and select some language i want to change the language of all text on the login page in choosed language in realtime. Any idea how to do it?
The first link provided in the comments is an awesome solution, however for the shake of simplicity, a very simple way of doing what you want is to bind the control's text to properties in the ViewModel:
<Label Text="{Binding TSMSG1}"...
rather than using
<Label Text="{x:Static resources:AppResources.TSMSG1}"...
Then in your ViewModel you would have a property TSMSG1 (and others) that you manually update when the language changes. Of course those properties need to follow INPC pattern for the changes to be reflected on the view.
I would not recommend doing this everywhere because bindings are expensive for your app performance, but it should be fine for the screen that changes the language.
I'm looking to get Swipe and Tap events both working on a button in Xamarin Forms, using the Command pattern.
However, I fail at the first fence, since if I put a Tap Command inside a GestureRecognizer (ButtonA below) then the event doesn't register.
If I put the Command directly inside the button (ButtonB below) then it does register.
Others have reported problems with GestureRecognizers in Buttons, so i tried embedding the GestureRecognizer in a StackLayout, but that doesn't register either.
<Button x:Name="buttonA" Grid.Row="1" Text="Button A" BackgroundColor="LightGreen" >
<Button.GestureRecognizers>
<TapGestureRecognizer Command="{Binding OnCommand}" CommandParameter="Button" />
<ClickGestureRecognizer Command="{Binding OnCommand}" CommandParameter="Button" />
</Button.GestureRecognizers>
</Button>
<Button x:Name="buttonB" Grid.Row="2" Text="Button B" BackgroundColor="LightBlue"
Command="{Binding OnCommand}" CommandParameter="Button" >
</Button>
<StackLayout Grid.Row="3" >
<StackLayout.GestureRecognizers>
<TapGestureRecognizer Command="{Binding OnCommand}" CommandParameter="Button" />
</StackLayout.GestureRecognizers>
<Button x:Name="buttonC" Text="Button C" BackgroundColor="Orange" />
</StackLayout>
Lucas' comment put me on the right track.
Here's a summary of behaviors as I understand them:
(*) Putting GestureRecognizers of any kind - including a ClickGestureRecognizer - into a Button conflicts and wont work (buttonA below)
() Putting the Command directly into the Button does work (buttonB below)
() Putting GestureRecognizers into an element such as a Grid or a StackLayout that contains a Button conflicts and wont work (LayoutA + buttonC below)
() Removing the Button from the Grid or StackLayout fixes the problem (LayoutB below)
<Button x:Name="buttonA" Grid.Row="1" Text="Button A" BackgroundColor="LightGreen" >
<Button.GestureRecognizers>
<TapGestureRecognizer Command="{Binding TapCommand}" CommandParameter="Button" />
<ClickGestureRecognizer Command="{Binding TapCommand}" CommandParameter="Button" />
</Button.GestureRecognizers>
</Button>
<Button x:Name="buttonB" Grid.Row="2" Text="Button B" BackgroundColor="LightBlue"
Command="{Binding TapCommand}" CommandParameter="Button" >
</Button>
<StackLayout x:Name="LayoutA" Grid.Row="3" >
<StackLayout.GestureRecognizers>
<TapGestureRecognizer Command="{Binding TapCommand}" CommandParameter="Button" />
</StackLayout.GestureRecognizers>
<Button x:Name="buttonC" Text="Button C" BackgroundColor="Orange" />
</StackLayout>
<StackLayout x:Name="LayoutB" Grid.Row="4" BackgroundColor="White" >
<StackLayout.GestureRecognizers>
<TapGestureRecognizer Command="{Binding TapCommand}" CommandParameter="Button" />
<SwipeGestureRecognizer Direction="Left" Command="{Binding SwipeCommand}" CommandParameter="leftSwipe" />
</StackLayout.GestureRecognizers>
</StackLayout>
I have the following XAML in my Xamarin Forms project
<StackLayout x:Name="slFullPage" Orientation="Vertical" HorizontalOptions="Fill" VerticalOptions="FillAndExpand" Margin="0,0,0,0" BackgroundColor="AliceBlue">
<localapp:PageHeader x:Name="pgHeader" VerticalOptions="Start" HorizontalOptions="Fill" />
<combobox:SfComboBox x:Name="cmbLanguage" DataSource="{Binding LangaugesByAppLanguage}" TextSize="Micro"
TextColor="#283655" SelectionChanged="cmbLanguage_SelectionChanged"
Watermark="{localapp:Translate SelectValue}" DropDownItemHeight="25" WidthRequest="250" HeightRequest="30"
DropDownTextSize="Micro" BackgroundColor="White" HorizontalOptions="Center" VerticalOptions="Start"
DisplayMemberPath="LanguageName" SelectedValuePath="ISO_639_1_Code">
</combobox:SfComboBox>
<StackLayout Orientation="Horizontal" HorizontalOptions="FillAndExpand" VerticalOptions="End" BackgroundColor="Aqua">
<buttons:SfButton x:Name="btnCancel" Text="{localapp:Translate Cancel}" HorizontalOptions="Start" VerticalOptions="End" Margin="8,0,4,0"/>
<buttons:SfButton x:Name="btnDone" Text="{localapp:Translate Done}" HorizontalOptions="End" VerticalOptions="End" Margin="4,0,8,0"/>
</StackLayout>
<localapp:AppFooter x:Name="pgFooter" VerticalOptions="End" HorizontalOptions="Fill" />
</StackLayout>
Based on my understanding of the horizontal options that can be specified on an object, I would expect the Cancel button to be at the start of my horizontal stack layout and my Done button to be at the end of the same stack layout.
Additionally, based on the vertical options that can be used, I would expect the stacklayout with the buttons in it as well as my appfoot to appear at the bottom of my slFullPage stack layout. However, neither of those things are happening.
Instead what I get can be seen below:
You can see that the entire page stacklayout is going all the way to the bottom of the screen but my buttons and footer are not at the bottom.
Additinally, you can see the horizontal stack layout (aqua) goes all the way across the screen but the buttons are not positioned based on their horizontal options.
Any ideas?? FYI - I am running the project as a UWP app.
Based on my understanding of the horizontal options that can be specified on an object, I would expect the Cancel button to be at the start of my horizontal stack layout and my Done button to be at the end of the same stack layout.
You could use a AbsoluteLayout to make the buttons positioned anywhere within a view.
<AbsoluteLayout BackgroundColor="LightBlue" HeightRequest="60" VerticalOptions="EndAndExpand">
<Button Text="Cancel" Margin="10,10" BackgroundColor="DarkBlue" TextColor="White"/>
<Button Text="Done" Margin="10,10" AbsoluteLayout.LayoutBounds="1, 0, AutoSize, AutoSize" AbsoluteLayout.LayoutFlags="PositionProportional" BackgroundColor="DarkBlue" TextColor="White"/>
</AbsoluteLayout>
And use the VerticalOptions="EndAndExpand" to make it appears at the end of its parent and expands.
Updated:
I do not know what it was before, but for now, it doesn’t actually fill up the space in the StackLayout. It’s only when the fill option is used, that it will expand to that space.
When you expect the Cancel button to be at the start and the Done button to be at the end of the same stack layout, fill option and expend need to be setted. I use simple example to display.
<StackLayout Orientation="Horizontal" HorizontalOptions="FillAndExpand" VerticalOptions="EndAndExpand" BackgroundColor="Aqua">
<Button x:Name="btnCancel" Text="Cancel" HorizontalOptions="StartAndExpand" Margin="8,0,4,0"/>
<Button x:Name="btnDone" Text="Done" HorizontalOptions="EndAndExpand" Margin="4,0,8,0"/>
</StackLayout>
And if you do not want space between last two lines in the end, you need a nested stacklayout to do that without space.
Simple code:
<StackLayout BackgroundColor="LightGray">
<StackLayout>
<Entry x:Name="pgHeader" Text="pgHeader" HorizontalOptions="FillAndExpand" />
<Entry x:Name="cmbLanguage" Text="cmbLanguage" WidthRequest="250" HeightRequest="30"
BackgroundColor="Red" HorizontalOptions="CenterAndExpand" ></Entry>
</StackLayout>
<StackLayout HorizontalOptions="FillAndExpand" VerticalOptions="EndAndExpand">
<StackLayout Orientation="Horizontal" BackgroundColor="Aqua">
<Button x:Name="btnCancel" Text="Cancel" HorizontalOptions="StartAndExpand" Margin="8,0,4,0"/>
<Button x:Name="btnDone" Text="Done" HorizontalOptions="EndAndExpand" Margin="4,0,8,0"/>
</StackLayout>
<Entry x:Name="pgFooter" Text="pgFooter"/>
</StackLayout>
</StackLayout>
You don't want to use a StackLayout (well 2 StackLayout), but a Grid:
It's more convenient for your layout, and it is way more performant.
<Grid ColumnSpacing="0" RowSpacing="0">
<Grid.RowDefinitions>
<RowDefinition Height="50" />
<RowDefinition Height="40" />
<RowDefinition Height="40" />
</Grid.RowDefinitions>
<Grid.ColumnDefinition>
<ColumnDefinition Width="80" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="80" />
</Grid.ColumnDefinition>
<localapp:PageHeader Grid.Row="0" x:Name="pgHeader" />
<combobox:SfComboBox Grid.Row="1" x:Name="cmbLanguage" DataSource="{Binding LangaugesByAppLanguage}" TextSize="Micro"
TextColor="#283655" SelectionChanged="cmbLanguage_SelectionChanged"
Watermark="{localapp:Translate SelectValue}" DropDownItemHeight="25" WidthRequest="250"
DropDownTextSize="Micro" BackgroundColor="White" HorizontalOptions="Center"
DisplayMemberPath="LanguageName" SelectedValuePath="ISO_639_1_Code">
</combobox:SfComboBox>
<buttons:SfButton Grid.Row="2" Grid.Column="0"
x:Name="btnCancel" Text="{localapp:Translate Cancel}" Margin="8,0,4,0"/>
<buttons:SfButton Grid.Row="2" Grid.Column="2"
x:Name="btnDone" Text="{localapp:Translate Done}" Margin="4,0,8,0"/>
</Grid>
I typed "tab" and the only thing that seems to be relavent in the IntelliSense was "TabbedPage". I searched Google, and it also only showed tabbed page.
But what if I want something else above the tab? Something like this? Is this achievable in Xamarin Form? It is possible in native Android.
--------------------
Text inputs, buttons
---------------------
tabbed or swipe-able
content
--------------------
TabbedPage is a Page, is not a View so you can't include it inside another page.
On GitHub there is some TabView you can use. For example XFControls
<ctrls:TabView.TabTemplate>
<DataTemplate>
<StackLayout>
<ctrls:FontIcon Glyph="{Binding Glyph}"
FontFamily="{StaticResource font}"
FontSize="25"
Color="Gray"
HorizontalOptions="Center"
>
<ctrls:FontIcon.Triggers>
<DataTrigger TargetType="ctrls:FontIcon"
Binding="{Binding IsSelected}"
Value="True"
>
<Setter Property="Color" Value="Red" />
</DataTrigger>
</ctrls:FontIcon.Triggers>
</ctrls:FontIcon>
<Label Text="{Binding Title}"
TextColor="Gray"
HorizontalOptions="Center"
VerticalOptions="CenterAndExpand"
FontSize="10">
<Label.Triggers>
<DataTrigger TargetType="Label"
Binding="{Binding IsSelected}"
Value="True"
>
<Setter Property="TextColor" Value="Red" />
</DataTrigger>
</Label.Triggers>
</Label>
</StackLayout>
</DataTemplate>
</ctrls:TabView.TabTemplate>
<ctrls:TabView.ItemTemplate>
<DataTemplate>
<Label Text="{Binding Title}"
HorizontalOptions="Center" />
</DataTemplate>
</ctrls:TabView.ItemTemplate>
</ctrls:TabView>
I am trying to get the similar popup as below on Androd, see the X close button is nicely lays on top of the frame. I copied code from the github to test but actual code is also not working. half of the button is always behind the frame. I thought that first added control goes below and 2nd one comes above if their position lays on each other. is there any exception here? whatever I tried i couldnt set button obove the frame. Can somebody sheds some light on usage of absolutelayout here?
<ScrollView
HorizontalOptions="Center"
VerticalOptions="Center">
<AbsoluteLayout>
<Frame
x:Name="FrameContainer"
Margin="15"
HorizontalOptions="Center"
BackgroundColor="White">
<StackLayout
IsClippedToBounds="True"
Padding="10, 5"
Spacing="3">
<Image
HorizontalOptions="Center"
x:Name="OctocatImage"
Margin="10"
HeightRequest="150"
WidthRequest="150">
<Image.Source>
<OnPlatform
x:TypeArguments="ImageSource"
Android="github_octocat.png"
iOS="github_octocat.png"
WinPhone="Assets/github_octocat.png"/>
</Image.Source>
</Image>
<Entry
HorizontalOptions="Center"
x:Name="UsernameEntry"
Style="{StaticResource EntryStyle}"
Placeholder="Username" />
<Entry
HorizontalOptions="Center"
x:Name="PasswordEntry"
Style="{StaticResource EntryStyle}"
Placeholder="Password"
IsPassword="True"/>
<Button
Margin="10, 5"
BackgroundColor="#7dbbe6"
HorizontalOptions="Fill"
Clicked="OnLogin"
x:Name="LoginButton"
Text="Login">
<Button.HeightRequest>
<OnPlatform x:TypeArguments="x:Double" Android="50" iOS="30" WinPhone="30"/>
</Button.HeightRequest>
</Button>
</StackLayout>
</Frame>
<ContentView
AbsoluteLayout.LayoutFlags="PositionProportional"
AbsoluteLayout.LayoutBounds="1, 0, -1, -1">
<ContentView.GestureRecognizers>
<TapGestureRecognizer Tapped="OnCloseButtonTapped"/>
</ContentView.GestureRecognizers>
<Image
x:Name="CloseImage"
HeightRequest="30"
WidthRequest="30">
<Image.Source>
<OnPlatform
x:TypeArguments="ImageSource"
Android="close_circle_button.png"
iOS="close_circle_button.png"
WinPhone="Assets/close_circle_button.png"/>
</Image.Source>
</Image>
</ContentView>
</AbsoluteLayout>
</ScrollView>
I just tried with a fresh project and below is how it looks like for me. Close button is always behind the frame. here you can find repro test project
Removed Frame and moved some attributes onto StackLayout. Related bug
https://bugzilla.xamarin.com/show_bug.cgi?id=55744
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:test"
x:Class="test.MainPage">
<ContentPage.Resources>
<ResourceDictionary>
<Style x:Key="EntryStyle" TargetType="Entry">
<Setter Property="PlaceholderColor" Value="#9cdaf1"/>
<Setter Property="TextColor" Value="#7dbbe6"/>
</Style>
</ResourceDictionary>
</ContentPage.Resources>
<ContentPage.Content>
<ScrollView
HorizontalOptions="Center"
VerticalOptions="Center">
<AbsoluteLayout>
<StackLayout Margin="15" BackgroundColor="White"
IsClippedToBounds="True"
Padding="10, 5"
Spacing="3">
<Image
HorizontalOptions="Center"
x:Name="OctocatImage"
Margin="10"
HeightRequest="150"
WidthRequest="150">
<Image.Source>
<OnPlatform
x:TypeArguments="ImageSource"
Android="icon.png"
/>
</Image.Source>
</Image>
<Entry
HorizontalOptions="Center"
x:Name="UsernameEntry"
Style="{StaticResource EntryStyle}"
Placeholder="Username" />
<Entry
HorizontalOptions="Center"
x:Name="PasswordEntry"
Style="{StaticResource EntryStyle}"
Placeholder="Password"
IsPassword="True"/>
<Button
Margin="10, 5"
BackgroundColor="#7dbbe6"
HorizontalOptions="Fill"
x:Name="LoginButton"
Text="Login">
<Button.HeightRequest>
<OnPlatform x:TypeArguments="x:Double" Android="50" iOS="30" WinPhone="30"/>
</Button.HeightRequest>
</Button>
</StackLayout>
<ContentView
AbsoluteLayout.LayoutFlags="PositionProportional"
AbsoluteLayout.LayoutBounds="1, 0, -1, -1">
<Image
x:Name="CloseImage"
HeightRequest="30"
WidthRequest="30">
<Image.Source>
<OnPlatform
x:TypeArguments="ImageSource"
Android="close_circle_button.png"
/>
</Image.Source>
</Image>
</ContentView>
</AbsoluteLayout>
</ScrollView>
</ContentPage.Content>
</ContentPage>
It's a bug, set HasShadow="False" on your Frame and it should work.