Pages

Tuesday, 3 November 2020

Show/Hide Views in RunTime in Xamarin Forms

When developing UI a common use case is to hide/show a View according to a certain condition, when thinking on how to do this the first thing that comes to mind is to add an IsVisible property and just hide/show it according to a condition but doing that has performance implications since hiding an element does not remove it from the UI, which means that if you have 10 views you will have all of them loaded in memory even when not visible.


Project Structure 


Code 

App.xaml

<?xml version="1.0" encoding="utf-8"?>

<Application xmlns="http://xamarin.com/schemas/2014/forms"

             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"

             x:Class="HideShowXF.App">

    <Application.Resources>

        <ResourceDictionary>

            <Style x:Key="ButtonStyle" TargetType="Button">

                <Setter Property="BackgroundColor" Value="#2196F3" />

                <Setter Property="VerticalOptions" Value="Start" />

                <Setter Property="HeightRequest" Value="50" />

                <Setter Property="TextColor" Value="White" />

                <Setter Property="HorizontalOptions" Value="FillAndExpand" />

            </Style>


            <Style x:Key="ButtonDisabledStyle" TargetType="Button">

                <Setter Property="TextColor" Value="#2196F3" />

                <Setter Property="VerticalOptions" Value="Start" />

                <Setter Property="HeightRequest" Value="50" />

                <Setter Property="BackgroundColor" Value="White" />

                <Setter Property="BorderColor" Value="#2196F3" />

                <Setter Property="BorderWidth" Value="2" />

                <Setter Property="HorizontalOptions" Value="FillAndExpand" />

            </Style>

        </ResourceDictionary>

    </Application.Resources>

</Application>


App.xaml.cs

using HideShowXF.Views;

using Xamarin.Forms;


namespace HideShowXF

{

    public partial class App : Application

    {

        public App()

        {

            InitializeComponent();


            MainPage = new MainPageCarousel();

        }


        protected override void OnStart()

        {

        }


        protected override void OnSleep()

        {

        }


        protected override void OnResume()

        {

        }

    }

}

MainPageCarousel.xaml

<?xml version="1.0" encoding="UTF-8"?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="HideShowXF.Views.MainPageCarousel"
             xmlns:local="clr-namespace:HideShowXF.Views.CarouselViews.Templates">
    <ContentPage.Resources>
      <ResourceDictionary>
        <local:CarouselDataTemplateSelector x:Key="CarouselDataTemplateSelector"/>
      </ResourceDictionary>
    </ContentPage.Resources>
    <ContentPage.Content>
        <Grid Padding="20"
              ColumnDefinitions="*, *"
              RowDefinitions="Auto, *">

        <Button Text="Tab1"
                Style="{StaticResource ButtonDisabledStyle}"
                Grid.Row="0"
                Grid.Column="0"
                Command="{Binding SelectItemCommand}"
                CommandParameter="0">
            <Button.Triggers>
                         <DataTrigger TargetType="Button"
                                      Binding="{Binding PositionSelected}"
                                      Value="0">
                    <Setter Property="Style" Value="{StaticResource ButtonStyle}" />
                </DataTrigger>
             </Button.Triggers>
        </Button>

        <Button Text="Tab2"
                Style="{StaticResource ButtonDisabledStyle}"
                Grid.Row="0"
                Grid.Column="1"
                Command="{Binding SelectItemCommand}"
                CommandParameter="1">
             <Button.Triggers>
                         <DataTrigger TargetType="Button"
                                      Binding="{Binding PositionSelected}"
                                      Value="1">
                    <Setter Property="Style" Value="{StaticResource ButtonStyle}" />
                </DataTrigger>
             </Button.Triggers>
        </Button>

       <CarouselView Grid.Column="0"
                     Grid.ColumnSpan="2"
                     Grid.Row="1"
                     ItemTemplate="{StaticResource CarouselDataTemplateSelector}"
                     IsSwipeEnabled="False"
                     IsScrollAnimated="False"
                     Position="{Binding PositionSelected}">
           <CarouselView.ItemsSource>
              <x:Array Type="{x:Type x:String}">
                <x:String>1</x:String>
                <x:String>2</x:String>
              </x:Array>
           </CarouselView.ItemsSource>
        </CarouselView>
    </Grid>
    </ContentPage.Content>
</ContentPage>

MainPageCarousel.xaml.cs

using Xamarin.Forms;

namespace HideShowXF.Views
{
    public partial class MainPageCarousel : ContentPage
    {
        public MainPageCarousel()
        {
            InitializeComponent();
            BindingContext = new MainPageViewModel();
        }
    }
}

MainPageViewModel.cs

using System.ComponentModel;
using System.Windows.Input;
using Xamarin.Forms;

namespace HideShowXF
{
    public class MainPageViewModel : INotifyPropertyChanged
    {
        public ICommand SelectItemCommand { get => new Command<string>((param) => PositionSelected = int.Parse(param)); }

        public int _positionSelected = 0;

        public int PositionSelected
        {
            set
            {
                if (_positionSelected != value)
                {
                    _positionSelected = value;

                    PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(PositionSelected)));
                }
            }
            get => _positionSelected;
        }

        public event PropertyChangedEventHandler PropertyChanged;
    }
}
CarouselDataTemplateSelector.cs

using Xamarin.Forms;

namespace HideShowXF.Views.CarouselViews.Templates
{
    public class CarouselDataTemplateSelector : DataTemplateSelector
    {
        public DataTemplate Tab1 { get; set; }
        public DataTemplate Tab2 { get; set; }

        public CarouselDataTemplateSelector()
        {
            Tab1 = new DataTemplate(typeof(Tab1View));
            Tab2 = new DataTemplate(typeof(Tab2View));
        }

        protected override DataTemplate OnSelectTemplate(object item, BindableObject container)
        {
            var position = $"{item}";

            if(position == "1")
                 return Tab1;

                return Tab2;
        }
    }
}

Tab1View.xaml

<?xml version="1.0" encoding="UTF-8"?>
<StackLayout xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="HideShowXF.Views.CarouselViews.Tab1View"
             BackgroundColor="Red"
             VerticalOptions="FillAndExpand"/>

Cs File :Tab1View.xaml.cs
namespace HideShowXF.Views.CarouselViews
{
    public partial class Tab1View 
    {
        public Tab1View()
        {
            InitializeComponent();
        }
    }
}

Tab2View.xaml
<?xml version="1.0" encoding="UTF-8"?>
<StackLayout xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="HideShowXF.Views.CarouselViews.Tab2View"
             BackgroundColor="Yellow"
             VerticalOptions="FillAndExpand"/>

Tab2View.xaml.cs

namespace HideShowXF.Views.CarouselViews
{
    public partial class Tab2View 
    {
        public Tab2View()
        {
            InitializeComponent();
        }
    }
}

MainPageControlTemplate.xaml

<?xml version="1.0" encoding="UTF-8"?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="HideShowXF.MainPageControlTemplate"
             xmlns:View="clr-namespace:HideShowXF.Views.Templates"
             ControlTemplate="{DynamicResource Tab1View}">
    <ContentPage.Triggers>
           <DataTrigger TargetType="ContentPage"
                        Binding="{Binding PositionSelected}"
                        Value="2">
            <Setter Property="ControlTemplate" Value="{DynamicResource Tab2View}" />
        </DataTrigger>
    </ContentPage.Triggers>
    <ContentPage.Resources>
        <ResourceDictionary>
            <ControlTemplate x:Key="Tab1View">
                 <View:Tab1View />
            </ControlTemplate>
             <ControlTemplate x:Key="Tab2View">
                 <View:Tab2View />
            </ControlTemplate>
        </ResourceDictionary>
    </ContentPage.Resources>
    <StackLayout Padding="20"
                 Orientation="Horizontal">

        <Button Text="Tab1"
                Style="{StaticResource ButtonDisabledStyle}"
                Command="{Binding SelectItemCommand}"
                CommandParameter="1">
            <Button.Triggers>
                         <DataTrigger TargetType="Button"
                                      Binding="{Binding PositionSelected}"
                                      Value="1">
                    <Setter Property="Style" Value="{StaticResource ButtonStyle}" />
                </DataTrigger>
             </Button.Triggers>
        </Button>

        <Button Text="Tab2"
                Style="{StaticResource ButtonDisabledStyle}"
                Command="{Binding SelectItemCommand}"
                CommandParameter="2">
             <Button.Triggers>
                         <DataTrigger TargetType="Button"
                                      Binding="{Binding PositionSelected}"
                                      Value="2">
                    <Setter Property="Style" Value="{StaticResource ButtonStyle}" />
                </DataTrigger>
             </Button.Triggers>
        </Button>
    </StackLayout>
</ContentPage>

Cs File MainPageControlTemplate.cs

using System;
using System.Collections.Generic;

using Xamarin.Forms;

namespace HideShowXF
{
    public partial class MainPageControlTemplate : ContentPage
    {
        public MainPageControlTemplate()
        {
            InitializeComponent();
        }
    }
}

Full Source code : Link

No comments:

Post a Comment