Listview does not update when isVisible is set to true

I am trying to make a ListView with click buttons. When you click on a line, it sets the child stack for visibility to true. This works fine on Android, but not on ios. Maybe I'm doing it wrong. I'm still a beginner, any idea how to fix this or any other better approach? The problem is that it opens on ios, so visibility changes, but it does not update the cell height. The cell is updated off-screen, for example, if you scroll up until you can no longer see the open cell, and then scroll back. You will see that he updated the height.

I tried using my own renderer, but I donโ€™t know where to start.

This is my 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="Lisa.Excelsis.Mobile.AssessmentPage" xmlns:local="clr-namespace:Lisa.Excelsis.Mobile;assembly=Lisa.Excelsis.Mobile"> <StackLayout> <local:SpecialListView x:Name="CategoryList" ItemsSource = "{Binding Categories}" HasUnevenRows="true" RowHeight="-1" GroupDisplayBinding="{Binding Name}" IsGroupingEnabled="true"> <local:SpecialListView.ItemTemplate> <DataTemplate> <ViewCell x:Name="ObservationCell"> <ViewCell.View> <StackLayout x:Name="ObservationContainer" HorizontalOptions="FillAndExpand" Orientation="Vertical" VerticalOptions="StartAndExpand" BackgroundColor="White"> <StackLayout x:Name="Observation" HorizontalOptions="FillAndExpand" VerticalOptions="StartAndExpand" Padding="15, 10, 10, 10" BackgroundColor="White"> <StackLayout.GestureRecognizers> <TapGestureRecognizer Tapped="OpenItem"/> </StackLayout.GestureRecognizers> <Grid HorizontalOptions="FillAndExpand" > <Grid.RowDefinitions> <RowDefinition Height="Auto" /> <RowDefinition Height="Auto" /> </Grid.RowDefinitions> <Grid.ColumnDefinitions> <ColumnDefinition Width="35" /> <ColumnDefinition Width="*" /> </Grid.ColumnDefinitions> <Label x:Name="ObservationOrder" Text="{Binding Criterion.Order, StringFormat='{0}.'}" FontSize="18" VerticalOptions="StartAndExpand" Grid.Column="0" Grid.Row="0"/> <Label x:Name="ObservationTitle" Text="{Binding Criterion.Title}" FontSize="18" VerticalOptions="StartAndExpand" Grid.Column="1" Grid.Row="0"/> </Grid> </StackLayout> <StackLayout x:Name="ObservationButtons" HorizontalOptions="FillAndExpand" VerticalOptions="StartAndExpand" BackgroundColor="White" IsVisible="false" Padding="0, 0, 0, 20" ClassId = "{Binding Id, StringFormat='ObservationButtons_{0}'}"> <Grid HorizontalOptions="Center" Grid.Column="0" Grid.Row="1" Grid.ColumnSpan="2"> <Grid.RowDefinitions> <RowDefinition Height="Auto" /> </Grid.RowDefinitions> <Grid.ColumnDefinitions> <ColumnDefinition Width="80" /> <ColumnDefinition Width="80" /> <ColumnDefinition Width="10" /> <ColumnDefinition Width="80" /> <ColumnDefinition Width="80" /> <ColumnDefinition Width="80" /> <ColumnDefinition Width="80" /> </Grid.ColumnDefinitions> <StackLayout Grid.Column="0" Grid.Row="0" > <Image Source="yesnobutton0.png" HeightRequest="60" WidthRequest="60" HorizontalOptions="Center" VerticalOptions="Start" x:Name="yesImage"> <Image.GestureRecognizers> <TapGestureRecognizer Tapped="SetYesImage"/> </Image.GestureRecognizers> </Image> <Label Text="Ja" VerticalOptions="End" HorizontalOptions="Center"/> </StackLayout> <StackLayout Grid.Column="1" Grid.Row="0"> <Image Source="yesnobutton0.png" HeightRequest="60" WidthRequest="60" HorizontalOptions="Center" VerticalOptions="Start" x:Name="noImage"> <Image.GestureRecognizers> <TapGestureRecognizer Tapped="SetNoImage"/> </Image.GestureRecognizers> </Image> <Label Text="Nee" VerticalOptions="End" HorizontalOptions="Center"/> </StackLayout> <Image Source="maybenot.png" HeightRequest="60" WidthRequest="60" HorizontalOptions="Center" VerticalOptions="Start" Grid.Column="3" Grid.Row="0"> <Image.GestureRecognizers> <TapGestureRecognizer Tapped="SetMark"/> </Image.GestureRecognizers> </Image> <Image Source="skip.png" HeightRequest="60" WidthRequest="60" HorizontalOptions="Center" VerticalOptions="Start" Grid.Column="4" Grid.Row="0"> <Image.GestureRecognizers> <TapGestureRecognizer Tapped="SetMark"/> </Image.GestureRecognizers> </Image> <Image Source="unclear.png" HeightRequest="60" WidthRequest="60" HorizontalOptions="Center" VerticalOptions="Start" Grid.Column="5" Grid.Row="0"> <Image.GestureRecognizers> <TapGestureRecognizer Tapped="SetMark"/> </Image.GestureRecognizers> </Image> <Image Source="change.png" HeightRequest="60" WidthRequest="60" HorizontalOptions="Center" VerticalOptions="Start" Grid.Column="6" Grid.Row="0"> <Image.GestureRecognizers> <TapGestureRecognizer Tapped="SetMark"/> </Image.GestureRecognizers> </Image> </Grid> </StackLayout> </StackLayout> </ViewCell.View> </ViewCell> </DataTemplate> </local:SpecialListView.ItemTemplate> </local:SpecialListView> </StackLayout> 

This is an example of how it works on Android and how I want it to work on ios. List Example

+6
source share
1 answer

I reproduced your problem in a small test project. I prefer to make layout changes through data binding rather than behind the code.

Let's start with the Template :

 <?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="App6.Page1"> <ListView x:Name="CategoryList" BackgroundColor="Gray" ItemsSource="{Binding Categories}" SelectedItem="{Binding SelectedItem}" HasUnevenRows="true" RowHeight="-1"> <ListView.ItemTemplate> <DataTemplate> <ViewCell x:Name="ObservationCell"> <ViewCell.View> <StackLayout x:Name="Observation" HorizontalOptions="FillAndExpand" VerticalOptions="StartAndExpand" Padding="15, 10, 10, 10" BackgroundColor="White"> <Label x:Name="ObservationTitle" Text="{Binding Title}" FontSize="18" TextColor="Black" VerticalOptions="StartAndExpand"/> <StackLayout Orientation="Horizontal" IsVisible="{Binding IsSelected}"> <Image BackgroundColor="Fuchsia" WidthRequest="40" HeightRequest="40"></Image> <Image BackgroundColor="Green" WidthRequest="40" HeightRequest="40"></Image> <Image BackgroundColor="Yellow" WidthRequest="40" HeightRequest="40"></Image> <Image BackgroundColor="Blue" WidthRequest="40" HeightRequest="40"></Image> <Image BackgroundColor="Black" WidthRequest="40" HeightRequest="40"></Image> </StackLayout> </StackLayout> </ViewCell.View> </ViewCell> </DataTemplate> </ListView.ItemTemplate> </ListView> </ContentPage> 

The Datatemplate parameter is basic, but:

  • StackLayout does not have Click-Listener
  • Viscosity StackLayout bound to IsSelected ( IsVisible="{Binding IsSelected}" )
  • SelectedItem ListView bound to SelectedItem our ViewModel

Our Page simply sets the ViewModel as a DataContext

 public partial class Page1 : ContentPage { public Page1() { InitializeComponent(); BindingContext = new Page1ViewModel(); } } 

ViewModel

  • implements INotifyPropertyChanged for notification of data changes.
  • adds some dummy elements to our Categories collection
  • has a SelectedItem property that updates the IsSelected property of categories
 class Page1ViewModel : INotifyPropertyChanged { private Category _selectedItem; private ObservableCollection<Category> _categories = new ObservableCollection<Category>(); public event PropertyChangedEventHandler PropertyChanged; public ObservableCollection<Category> Categories { get { return _categories; } set { _categories = value; OnPropertyChanged(); } } public Category SelectedItem { get { return _selectedItem; } set { if (_selectedItem == value) return; if (_selectedItem != null) { _selectedItem.IsSelected = false; } _selectedItem = value; if (_selectedItem != null) { _selectedItem.IsSelected = true; } } } [NotifyPropertyChangedInvocator] protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null) { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); } public Page1ViewModel() { Categories.Add(new Category()); Categories.Add(new Category()); Categories.Add(new Category()); Categories.Add(new Category()); Categories.Add(new Category()); } } 

And last but not least, but most importantly, you need a small custom renderer that overwrites the default value. We call ReloadData() if the SelectedItem has changed.

 [assembly: ExportRenderer(typeof(ListView), typeof(MyListViewRenderer))] namespace App6.iOS.CustomRenderer { public class MyListViewRenderer : ListViewRenderer { protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e) { base.OnElementPropertyChanged(sender, e); if (e.PropertyName == ListView.SelectedItemProperty.PropertyName) { Device.BeginInvokeOnMainThread(() => Control.ReloadData()); } } } } 

Result

View a list with dynamic cells

+5
source

All Articles