问题描述
我正在尝试使用可点击的行制作 ListView
。当您单击某一行时,它会将子堆栈布局设置为可见性为true。这在android中运行良好,但在ios中不行。也许我做错了。我仍然是初学者,任何想法如何解决这个或任何其他更好的方法?
问题是它在ios上打开,因此可见性发生了变化,但它没有更新单元格的高度。例如,如果向上滚动直到无法再看到打开的单元格,然后向下滚动,则单元格会在屏幕外更新。你会看到它已经更新了高度。
I'm trying to make a ListView
with clickable rows. When you click on a row it sets a child stacklayout to visibility true. This works fine in android, but not in ios. Maybe I'm doing it the wrong way. I am still a beginner, any idea how to fix this or any other better approach?The problem is that it opens on ios so the visibility changes, but it does not update the height of the cell. The cell updates off-screen for example if you scroll up until you can't see the opened cell anymore and then scroll back down. You'll see it has updated the height.
我尝试使用自定义渲染器,但我不知道从哪里开始。
I tried using a custom renderer, but i have no idea where to start.
这是我的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上工作。
This is an example of how it works on android and how i want it to work on ios.
推荐答案
我在一个小型Testproject中重现了您的问题。我更喜欢通过数据绑定进行布局更改,而不是代码隐藏。
I reproduced your Problem in a small Testproject. I prefer doing layout changes via data binding, instead of code behind.
让我们从模板开始:
<?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>
Datatemplate基本相同,但是:
The Datatemplate is basicaly the same, but:
-
StackLayout
没有Click-Listener - StackLayout的可见性绑定到
IsSelected
(IsVisible ={Binding IsSelected}
) - <$
ListView
的c $ c> SelectedItem 绑定到ViewModel的SelectedItem
- the
StackLayout
has no Click-Listener - the Visbility of the StackLayout is bound to
IsSelected
(IsVisible="{Binding IsSelected}"
) - the
SelectedItem
of theListView
is bound toSelectedItem
of our ViewModel
我们的页面只是将 ViewModel
设置为 DataContext
public partial class Page1 : ContentPage
{
public Page1()
{
InitializeComponent();
BindingContext = new Page1ViewModel();
}
}
ViewModel
- 实现
INotifyPropertyChanged
通知视图有关数据更改 - 将一些虚拟物品添加到我们的
类别
集合 - 有一个
SelectedItem
更新类别的IsSelected
属性的属性
- implements
INotifyPropertyChanged
to notify the view about data changes - adds some dummy items to our
Categories
Collection - has a
SelectedItem
property that updates theIsSelected
property of the 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());
}
}
最后但并非最不重要,但最重要的是,你需要一个小的自定义渲染器来覆盖默认渲染器。如果 SelectedItem
已更改,我们调用 ReloadData()
。
Last, but not least, but most important, you need a tiny custom renderer that overwrites the default one. 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());
}
}
}
}
结果
这篇关于当isVisible设置为true时,Listview未更新的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!