Dynamically show/hide Header or Footer of Xamarin.Forms.ListView

后端 未结 7 1728
粉色の甜心
粉色の甜心 2021-02-09 18:29

Is there a way to dynamically show/hide the header of a ListView based on a condition at runtime.



        
相关标签:
7条回答
  • 2021-02-09 18:31

    You should use FooterTemplate and Footer properties. It works as ItemTemplate and ItemSource:

    <ListView Footer="{Binding IsFooterVisible}">
        <ListView.FooterTemplate>
            <DataTemplate>
                <!-- Footer content. Always visible -->
            </DataTemplate>
        <ListView.FooterTemplate>
    </ListView>
    

    And bind to Footer property something nullable (object for example). Or you can use converter to convert: true -> new object() and false -> null

    Also it is possible to create a subclass of ListView. My example (IsLoading property is what you searching for):

    Xaml:

    <?xml version="1.0" encoding="UTF-8"?>
    <ListView xmlns="http://xamarin.com/schemas/2014/forms"
        xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
        x:Class="Panor.Views.LoadableListView"
        x:Name="element"
        >
        <ListView.FooterTemplate>
            <DataTemplate>
                <ContentView>
                    <ActivityIndicator IsRunning="true"
                        Margin="0, 5"
                        Color="{StaticResource mainColor}"
                        VerticalOptions="CenterAndExpand"
                        HorizontalOptions="CenterAndExpand"
                        >
                        <ActivityIndicator.Scale>
                            <OnPlatform x:TypeArguments="x:Double" iOS="2" Android="1" />
                        </ActivityIndicator.Scale>
                    </ActivityIndicator>
                </ContentView>            
            </DataTemplate>
        </ListView.FooterTemplate>
    </ListView>
    

    Code-behind:

    public partial class LoadableListView : ListView
    {
        public LoadableListView()
        {
            InitializeComponent();
    
            this.ItemAppearing += OnItemAppearing;
        }
    
        public static readonly BindableProperty IsLoadingProperty = BindableProperty.Create(
            nameof(IsLoading),
            typeof(bool),
            typeof(LoadableListView),
            false,
            propertyChanged: (bindable, oldValue, newValue) => 
            {
                var element = (LoadableListView)bindable;
    
                element.Footer = (bool)newValue ? new object() : null;
            }
        );
        public bool IsLoading
        {
            set => SetValue(IsLoadingProperty, value);
            get => (bool)GetValue(IsLoadingProperty);
        }
    
        public static readonly BindableProperty ScrolledDownCommandProperty = BindableProperty.Create(
            nameof(ScrolledDownCommand),
            typeof(ICommand),
            typeof(LoadableListView)
        );
        public ICommand ScrolledDownCommand
        {
            set => SetValue(ScrolledDownCommandProperty, value);
            get => (ICommand)GetValue(ScrolledDownCommandProperty);
        }
    
        void OnItemAppearing(object sender, ItemVisibilityEventArgs e)
        {
            if (ItemsSource == null) return;
            if (ScrolledDownCommand == null) return;
    
            object last = null;
    
            if (ItemsSource is IList)
            {
                var length = (ItemsSource as IList).Count;
                last = (ItemsSource as IList)[length - 1];
            }
            else 
            {
                foreach (var item in ItemsSource)
                    last = item;
            }
    
            if (e.Item == last && ScrolledDownCommand.CanExecute(null))
                ScrolledDownCommand.Execute(null);
    
        }
    

    Consuming:

     <views:LoadableListView ItemsSource="{Binding ItemSource}"
                    RowHeight="120"
                    SeparatorColor="#c7c8c9" 
                    IsLoading="{Binding IsMoreLoading}"
                    ScrolledDownCommand="{Binding ScrolledDownCommand}"
                    IsPullToRefreshEnabled="true"
                    IsRefreshing="{Binding IsRefreshing}"
                    RefreshCommand="{Binding RefreshCommand}"
                    >
                    <views:LoadableListView.ItemTemplate>
                        <DataTemplate>
                            <cells:MagazinesListCell Name="{Binding Name}" 
                                Publisher="{Binding Publisher}"
                                Price="{Binding Price}"
                                Image="{Binding Converter={StaticResource UriToImageSourceConvertor}, Path=Image}"
                                Commands="{Binding Commands}"
                                />
                        </DataTemplate>
                    </views:LoadableListView.ItemTemplate>
                </views:LoadableListView>
    
    0 讨论(0)
  • 2021-02-09 18:31

    You can wrap your footer template in a ViewCell, then set the ViewCell's Height to 0 when you don't want it to show. If you do this, make sure to set the ListView.HasUnevenRows property to True:

    <ListView x:Name="ListViewChallenges" Header="{Binding .}" HasUnevenRows="True">
    
        <ListView.FooterTemplate>
            <DataTemplate>
                <ViewCell Height={Binding FooterHeight}>
                    <Label Text="No Elements found." IsVisible="{Binding FooterIsVisible}" />  
                </ViewCell>
            </DataTemplate>
        </ListView.FooterTemplate>
    
    <!-- ... -->
    
    </ListView>
    
    0 讨论(0)
  • 2021-02-09 18:31

    If you want to hide the footer because the listview is empty just set

    listview.footer = null
    
    0 讨论(0)
  • 2021-02-09 18:37

    I tried all variants with:
    1) Header property binding new object() or null
    2) Two stacklayouts with not converter (https://stackoverflow.com/a/53197844/7429947)
    3) DataTrigger and Trigger on change IsVisible set HeightRequest

    This is doesn't help me, and then I replaced MinimumHeightRequest on 'HeightRequest' and second variant help me for iOS and Android!

    Xamarin.Forms version: 4.6.0.726

    0 讨论(0)
  • 2021-02-09 18:51

    This works for me without temlpate(template will not work if you need refer elements from the header in the parent .cs code). So have to containers with 0 and not 0 height and switch their visibility.

      <ListView.Header>
    <StackLayout Style="{StaticResource DefaultStackLayout}">
        <StackLayout x:Name="ZeroHeaderContainer"
                     HeightRequest="0"
                     IsVisible="{Binding SomeBooleanField}"/>
    
    
        <StackLayout  x:Name="NormalHeaderContainer"
                 Style="{StaticResource DefaultStackLayout}"
                 HorizontalOptions="Fill" 
                 IsVisible="{Binding SomeBooleanField,Converter={StaticResource InverseBooleanConverter}}">
        </StackLayout>
    </StackLayout>      
    

    0 讨论(0)
  • 2021-02-09 18:54

    Here is the solution:

    <ListView.FooterTemplate>
      <DataTemplate>
    
        <!--VIEW-->
        <ActivityIndicator IsRunning="true" IsVisible="{Binding IsLoadingOnDemand}" HorizontalOptions="CenterAndExpand" Margin="15">
          <ActivityIndicator.Triggers>
            <Trigger TargetType="ActivityIndicator" Property="IsVisible" Value="False">
              <Setter Property="HeightRequest" Value="0" />
            </Trigger>
          </ActivityIndicator.Triggers>
        </ActivityIndicator>
    
      </DataTemplate>
    </ListView.FooterTemplate>

    0 讨论(0)
提交回复
热议问题