Xamarin Forms ListView:编程选择和自定义渲染器的问题
Xamarin Forms ListView: Issues with programmatic selection and custom renderer
我在使用 XF 列表视图和自定义呈现器时遇到问题。
我需要:
- 更改 selected 项目的背景颜色
- 以编程方式在启动时预先select一个项目。
我已经能够更改 selected 项目的背景颜色并且一切正常,除非我预先 select 一个项目。
对于自定义控件和渲染器,我使用了在许多示例中找到的 "standard" 代码:
自定义控件:
public class RRViewCell : ViewCell
{
public static readonly BindableProperty SelectedItemBackgroundColorProperty = BindableProperty.Create("SelectedItemBackgroundColor", typeof(Color), typeof(RRViewCell), Color.Default);
public Color SelectedItemBackgroundColor
{
get { return (Color)GetValue(SelectedItemBackgroundColorProperty); }
set { SetValue(SelectedItemBackgroundColorProperty, value); }
}
}
Android 渲染器:
public class RRViewCellRendererAndroid : ViewCellRenderer
{
private Android.Views.View _cellCore;
private Drawable _unselectedBackground;
private bool _selected;
protected override Android.Views.View GetCellCore(Cell item, Android.Views.View convertView, ViewGroup parent, Context context)
{
_cellCore = base.GetCellCore(item, convertView, parent, context);
_selected = false;
_unselectedBackground = _cellCore.Background;
return _cellCore;
}
protected override void OnCellPropertyChanged(object sender, PropertyChangedEventArgs args)
{
base.OnCellPropertyChanged(sender, args);
if (args.PropertyName == "IsSelected")
{
_selected = !_selected;
if (_selected)
{
var extendedViewCell = sender as RRViewCell;
_cellCore.SetBackgroundColor(extendedViewCell.SelectedItemBackgroundColor.ToAndroid());
}
else
{
_cellCore.SetBackground(_unselectedBackground);
}
}
}
}
XAML:
<ctrl:RRViewCell SelectedItemBackgroundColor="{StaticResource NavigationPrimary}">
(NavigationPrimary 设置为蓝色阴影)。
正如我所说,如果没有项目以编程方式 select 一切正常,但如果我这样做:
MyList.SelectedItem = loc[0];
这是结果:
(敏感数据被屏蔽!)
在这种情况下,使用默认背景颜色而不是自定义颜色。
此外,如果我点击另一个项目,会发生这种情况:
请注意:
- 如果我重复点击不同的项目(除了第一个):
- 第一项保持蓝色
- 最后点击的项目设置为蓝色,前一个设置为白色,所以我总是让第一个项目和最后一个点击的项目为蓝色。
- 如果我点击第一个项目,它会变成橙色,并在随后的点击中保持橙色。
- 在点击第一个项目后点击另一个项目会将第一个项目从橙色变为蓝色。
这可能会非常令人沮丧,但是有很多 Xamarin 的东西需要横向思考,但是有很多方法可以实现这一点。
我通过在内置 selection 进程中禁用 ListView 实现了类似的效果,而是让 selected 项目始终以编程方式 selected 和 none它是特定于平台的。通过这种方式,我还可以防止用户 selection 在我 运行 一个漫长的过程(例如更新列表)时产生影响。
我将 ListView.SelectionMode
设置为 None,而是让 ListView.ItemTapped
触发我的 selection 代码。
我的每个 ListView 源项目都有一个 IsSelected 属性,每当一个项目被 selected 以供查看时就会设置它。
我没有更改 ListView.Item 的背景颜色,而是使用具有固定背景颜色的 BoxView,它的 IsVisible 绑定到 IsSelected,例如
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<Grid RowSpacing="0" >
<Grid.ColumnDefinitions>
<ColumnDefinition Width="1"/>
<ColumnDefinition Width="60"/>
<ColumnDefinition Width="120"/>
<ColumnDefinition Width="100*"/>
<ColumnDefinition Width="40"/>
<ColumnDefinition Width="1" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="30*"/>
</Grid.RowDefinitions>
<BoxView Grid.Column="0" Grid.Row="0" Grid.ColumnSpan="6" BackgroundColor="{StaticResource Primary}" IsVisible="{Binding IsSelected}" />
<Label Grid.Column="1" Grid.Row="0" HorizontalTextAlignment="Center" VerticalOptions="Center" Text="{Binding Destination}"/>
<Label Grid.Column="2" Grid.Row="0" HorizontalTextAlignment="Start" VerticalOptions="Center" Text="{Binding Description}"/>
<Label Grid.Column="3" Grid.Row="0" HorizontalTextAlignment="End" HorizontalOptions="End" VerticalOptions="Center" Text="{Binding ScaledValue}" FontAttributes="Bold" FontSize="Medium" BackgroundColor="{Binding StoredValueDiffers, Converter={x:StaticResource StoredDiffersConverter}}"/>
<Label Grid.Column="4" Grid.Row="0" HorizontalTextAlignment="Start" VerticalOptions="Center" Text="{Binding Units}"/>
</Grid>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
因为首先声明了 BoxView,所以它位于最低层,其他组件都绘制在它上面。
我想在你的情况下你可以使用一个非布尔值来显示一个项目是否已经被手动(点击)编辑,以编程方式或根本没有编辑,然后转换器将 select 你的背景颜色。
我希望这能给你一些想法。
在 Android 中,最简单的方法是在 Resources\values
下编辑:
在 styles.xml
中添加这一行:
<style name="MainTheme.Base" parent="Theme.AppCompat.Light.DarkActionBar">
...
<item name="android:colorActivatedHighlight">@color/ListViewSelected</item>
...
</style>
然后在colors.xml
里面添加color/ListViewSelected
:
<color name="ListViewSelected">#96BCE3</color>
缺点是一旦设置,所有列表视图都会启用此效果
我在使用 XF 列表视图和自定义呈现器时遇到问题。 我需要:
- 更改 selected 项目的背景颜色
- 以编程方式在启动时预先select一个项目。
我已经能够更改 selected 项目的背景颜色并且一切正常,除非我预先 select 一个项目。
对于自定义控件和渲染器,我使用了在许多示例中找到的 "standard" 代码:
自定义控件:
public class RRViewCell : ViewCell
{
public static readonly BindableProperty SelectedItemBackgroundColorProperty = BindableProperty.Create("SelectedItemBackgroundColor", typeof(Color), typeof(RRViewCell), Color.Default);
public Color SelectedItemBackgroundColor
{
get { return (Color)GetValue(SelectedItemBackgroundColorProperty); }
set { SetValue(SelectedItemBackgroundColorProperty, value); }
}
}
Android 渲染器:
public class RRViewCellRendererAndroid : ViewCellRenderer
{
private Android.Views.View _cellCore;
private Drawable _unselectedBackground;
private bool _selected;
protected override Android.Views.View GetCellCore(Cell item, Android.Views.View convertView, ViewGroup parent, Context context)
{
_cellCore = base.GetCellCore(item, convertView, parent, context);
_selected = false;
_unselectedBackground = _cellCore.Background;
return _cellCore;
}
protected override void OnCellPropertyChanged(object sender, PropertyChangedEventArgs args)
{
base.OnCellPropertyChanged(sender, args);
if (args.PropertyName == "IsSelected")
{
_selected = !_selected;
if (_selected)
{
var extendedViewCell = sender as RRViewCell;
_cellCore.SetBackgroundColor(extendedViewCell.SelectedItemBackgroundColor.ToAndroid());
}
else
{
_cellCore.SetBackground(_unselectedBackground);
}
}
}
}
XAML:
<ctrl:RRViewCell SelectedItemBackgroundColor="{StaticResource NavigationPrimary}">
(NavigationPrimary 设置为蓝色阴影)。
正如我所说,如果没有项目以编程方式 select 一切正常,但如果我这样做:
MyList.SelectedItem = loc[0];
这是结果:
(敏感数据被屏蔽!)
在这种情况下,使用默认背景颜色而不是自定义颜色。
此外,如果我点击另一个项目,会发生这种情况:
请注意:
- 如果我重复点击不同的项目(除了第一个):
- 第一项保持蓝色
- 最后点击的项目设置为蓝色,前一个设置为白色,所以我总是让第一个项目和最后一个点击的项目为蓝色。
- 如果我点击第一个项目,它会变成橙色,并在随后的点击中保持橙色。
- 在点击第一个项目后点击另一个项目会将第一个项目从橙色变为蓝色。
这可能会非常令人沮丧,但是有很多 Xamarin 的东西需要横向思考,但是有很多方法可以实现这一点。
我通过在内置 selection 进程中禁用 ListView 实现了类似的效果,而是让 selected 项目始终以编程方式 selected 和 none它是特定于平台的。通过这种方式,我还可以防止用户 selection 在我 运行 一个漫长的过程(例如更新列表)时产生影响。
我将 ListView.SelectionMode
设置为 None,而是让 ListView.ItemTapped
触发我的 selection 代码。
我的每个 ListView 源项目都有一个 IsSelected 属性,每当一个项目被 selected 以供查看时就会设置它。
我没有更改 ListView.Item 的背景颜色,而是使用具有固定背景颜色的 BoxView,它的 IsVisible 绑定到 IsSelected,例如
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<Grid RowSpacing="0" >
<Grid.ColumnDefinitions>
<ColumnDefinition Width="1"/>
<ColumnDefinition Width="60"/>
<ColumnDefinition Width="120"/>
<ColumnDefinition Width="100*"/>
<ColumnDefinition Width="40"/>
<ColumnDefinition Width="1" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="30*"/>
</Grid.RowDefinitions>
<BoxView Grid.Column="0" Grid.Row="0" Grid.ColumnSpan="6" BackgroundColor="{StaticResource Primary}" IsVisible="{Binding IsSelected}" />
<Label Grid.Column="1" Grid.Row="0" HorizontalTextAlignment="Center" VerticalOptions="Center" Text="{Binding Destination}"/>
<Label Grid.Column="2" Grid.Row="0" HorizontalTextAlignment="Start" VerticalOptions="Center" Text="{Binding Description}"/>
<Label Grid.Column="3" Grid.Row="0" HorizontalTextAlignment="End" HorizontalOptions="End" VerticalOptions="Center" Text="{Binding ScaledValue}" FontAttributes="Bold" FontSize="Medium" BackgroundColor="{Binding StoredValueDiffers, Converter={x:StaticResource StoredDiffersConverter}}"/>
<Label Grid.Column="4" Grid.Row="0" HorizontalTextAlignment="Start" VerticalOptions="Center" Text="{Binding Units}"/>
</Grid>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
因为首先声明了 BoxView,所以它位于最低层,其他组件都绘制在它上面。
我想在你的情况下你可以使用一个非布尔值来显示一个项目是否已经被手动(点击)编辑,以编程方式或根本没有编辑,然后转换器将 select 你的背景颜色。
我希望这能给你一些想法。
在 Android 中,最简单的方法是在 Resources\values
下编辑:
在 styles.xml
中添加这一行:
<style name="MainTheme.Base" parent="Theme.AppCompat.Light.DarkActionBar">
...
<item name="android:colorActivatedHighlight">@color/ListViewSelected</item>
...
</style>
然后在colors.xml
里面添加color/ListViewSelected
:
<color name="ListViewSelected">#96BCE3</color>
缺点是一旦设置,所有列表视图都会启用此效果