xamarinxamarin.formsvisualstatemanagervisualstatesvisualstategroup

How to change the visual state of a control in Xamarin Forms?


I am trying to make a tabs like view with plain xamarin forms because I don't want to use any third party plugin. For that I used two frames like below and changed its state as "Selected" & "Unselected" when tapped on that frame to make it look like that.

enter image description here

Style for frame:

<Style TargetType="Frame">
                <Setter Property="VisualStateManager.VisualStateGroups">
                    <VisualStateGroupList>
                        <VisualStateGroup>
                            <VisualState x:Name="Selected">
                                <VisualState.Setters>
                                    <Setter Property="BackgroundColor" Value="Orange" />
                                </VisualState.Setters>
                            </VisualState>
                            <VisualState x:Name="UnSelected">
                                <VisualState.Setters>
                                    <Setter Property="BackgroundColor" Value="White" />
                                </VisualState.Setters>
                            </VisualState>
                        </VisualStateGroup>
                    </VisualStateGroupList>
                </Setter>
            </Style>

My Frame:

<Frame x:Name="AllNewsTab" Padding="10,5,10,5" CornerRadius="3" HasShadow="False" VerticalOptions="FillAndExpand">
                    <Label Text="All" FontFamily="{StaticResource BoldFont}" TextColor="{StaticResource BodyTextColor}" FontSize="Medium" HorizontalTextAlignment="Center" VerticalTextAlignment="Center" HorizontalOptions="Center"/>
                    <Frame.GestureRecognizers>
                        <TapGestureRecognizer NumberOfTapsRequired="1" Tapped="Tab_Tapped"/>
                    </Frame.GestureRecognizers>
                </Frame>

Tapped Event:

private void Tab_Tapped(object sender, EventArgs e)
        {
            if (frameSelected != null)
                VisualStateManager.GoToState(frameSelected, "UnSelected");

            VisualStateManager.GoToState((Frame)sender, "Selected");

            frameSelected = (Frame)sender;
}

But I want one frame to look selected when the page appears for the first time. So I tried to do like this in the pages OnAppearing Method. But it doesn't work. What is the problem here?

protected override void OnAppearing()
        {
            VisualStateManager.GoToState(AllNewsTab, "Selected");

            base.OnAppearing();
        }

Solution

  • Try this, In xamarin, VisualElement have 4 states such as Normal, Disabled, Focused, Selected. And we can define our own VisualElements.

    MainPage.Xml

    <?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:d="http://xamarin.com/schemas/2014/forms/design"
                 xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
                 mc:Ignorable="d"
                 x:Class="Xam_VS_Test.Views.MainPage">
        <ContentPage.Resources>
            <Style TargetType="Frame">
                <Setter Property="VisualStateManager.VisualStateGroups">
                    <VisualStateGroupList>
                        <VisualStateGroup Name="SelectionStates">
                            <VisualState x:Name="Selected">
                                <VisualState.Setters>
                                    <Setter Property="BackgroundColor" Value="Orange" />
                                </VisualState.Setters>
                            </VisualState>
                            <VisualState x:Name="UnSelected">
                                <VisualState.Setters>
                                    <Setter Property="BackgroundColor" Value="White" />
                                </VisualState.Setters>
                            </VisualState>
                        </VisualStateGroup>
                    </VisualStateGroupList>
                </Setter>
            </Style>
        </ContentPage.Resources>
        <ContentPage.Content>
            <StackLayout Orientation="Vertical" >
                <Frame x:Name="AllNewsTab" Padding="10,5,10,5" HeightRequest="20" WidthRequest="50" HorizontalOptions="FillAndExpand" CornerRadius="3" HasShadow="False" VerticalOptions="FillAndExpand">
                    <Label Text="All" FontSize="Large" HorizontalTextAlignment="Center" VerticalTextAlignment="Center" HorizontalOptions="Center"/>
                    <Frame.GestureRecognizers>
                        <TapGestureRecognizer NumberOfTapsRequired="1" Tapped="Tab_Tapped"/>
                    </Frame.GestureRecognizers>
                </Frame>
                <Frame x:Name="AllNewsTab2" Padding="10,5,10,5" HeightRequest="20" WidthRequest="50" HorizontalOptions="FillAndExpand" CornerRadius="3" HasShadow="False" VerticalOptions="FillAndExpand">
                    <Label Text="1" FontSize="Large" HorizontalTextAlignment="Center" VerticalTextAlignment="Center" HorizontalOptions="Center"/>
                    <Frame.GestureRecognizers>
                        <TapGestureRecognizer NumberOfTapsRequired="1" Tapped="Tab_Tapped"/>
                    </Frame.GestureRecognizers>
                </Frame>
                <Frame x:Name="AllNewsTab3" Padding="10,5,10,5" HeightRequest="20" WidthRequest="50" HorizontalOptions="FillAndExpand" CornerRadius="3" HasShadow="False" VerticalOptions="FillAndExpand">
                    <Label Text="2" FontSize="Large" HorizontalTextAlignment="Center" VerticalTextAlignment="Center" HorizontalOptions="Center"/>
                    <Frame.GestureRecognizers>
                        <TapGestureRecognizer NumberOfTapsRequired="1" Tapped="Tab_Tapped"/>
                    </Frame.GestureRecognizers>
                </Frame>
            </StackLayout>
        </ContentPage.Content>
    </ContentPage>
    

    MainPage.cs

        public partial class MainPage : ContentPage
        {
            Frame frameSelected;
           public MainPage()
           {
               InitializeComponent();
           }
           protected override void OnAppearing()
           {
             if (frameSelected == null)
             {
                VisualStateManager.GoToState(AllNewsTab, "Selected");
                frameSelected = AllNewsTab;
             }
              base.OnAppearing();
            }
            private void Tab_Tapped(object sender, EventArgs e)
            {
                if (frameSelected != null)
                    VisualStateManager.GoToState(frameSelected, "UnSelected");
    
                VisualStateManager.GoToState((Frame)sender, "Selected");
    
                frameSelected = (Frame)sender;
            }
        }