当isVisible设置为true时,ListView不会更新

我试图做一个ListView与可点击的行。 当你点击一行时,它将一个子堆栈布局设置为可见性true。 这在Android中正常工作,但不是在iOS中。 也许我做错了。 我仍然是一个初学者,任何想法如何解决这个或任何其他更好的方法? 问题是,它在iOS上打开,所以可见性更改,但它不会更新单元格的高度。 例如,如果向上滚动,直到看不到已打开的单元格,然后向下滚动,单元格将在屏幕外更新。 你会看到它已经更新了高度。

我尝试使用自定义渲染器,但我不知道从哪里开始。

这是我的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> 

这是一个如何在Android上工作的例子,以及我希望如何在iOS上工作。 Listview示例

我在一个小的testing项目中复制了你的问题。 我更喜欢通过数据绑定进行布局更改,而不是后面的代码。

让我们从模板开始:

 <?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> 

数据模板基本相同,但是:

  • StackLayout没有Click-Listener
  • StackLayout的可见性被绑定到IsSelectedIsVisible="{Binding IsSelected}"
  • ListViewSelectedItem绑定到ViewModel的SelectedItem

我们的页面只是将ViewModel设置为DataContext

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

ViewModel

  • 实现INotifyPropertyChanged通知视图关于数据变化
  • 为我们的Categoriescollections添加了一些虚拟物品
  • 有一个SelectedItem属性来更新Categories的IsSelected属性
 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()); } } 

最后但并非最不重要,但最重要的是,您需要一个覆盖默认的自定义渲染器 。 如果SelectedItem已经改变,我们调用ReloadData()

 [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()); } } } } 

结果

列表视图与动态单元格

Interesting Posts