首页 > 解决方案 > 奇怪的视觉伪影

问题描述

在修复一个看起来像 xamarin.forms 在由 DataTemplateSelector 控制时不正确地释放列表视图的 ViewCell 的错误的过程中,我遇到了一个奇怪的视觉伪影,它同时出现在 iOS 和 Android 上。有趣的是,当用户充分向上滚动然后回到有问题的区域时,这个问题就会消失。

IOS: 在此处输入图像描述

安卓: 在此处输入图像描述

有趣的事情之一,没有显示在图片中,是在 iOS 上,看起来需要遵循的另外两个模板隐藏在控件后面。在图像中,我们有 3 种颜色: 海蓝宝石用于外部堆栈布局。Azure 用于我们应用 BindableLayout 的 stacklayout,然后是 Beige 用于 DataTemplate 内部的内部 stacklayout。

后台代码:

<?xml version="1.0" encoding="utf-8" ?>
<ViewCell xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:d="http://xamarin.com/schemas/2014/forms/design"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
          xmlns:customcontrols="clr-namespace:DataFinch.Catalyst.CustomControls"
          mc:Ignorable="d"
          x:Name="root"
             x:Class="DataFinch.Catalyst.DataTemplates.SoapNoteDataTemplates.SelectListTemplate">
    <StackLayout Orientation="Vertical" 
                Padding="0, 20, 0, 0"
                HorizontalOptions="FillAndExpand"
                VerticalOptions="FillAndExpand"
                 MinimumHeightRequest="60"
                 BackgroundColor="Aquamarine">

        <Label 
            x:Name="LabelName"
            FontAttributes="Bold"
            TextColor="Black"
            FontSize="14"
            VerticalOptions="Start"
            HorizontalOptions="FillAndExpand"/>

        <StackLayout x:Name="MultiselectList"
               Margin="0, 10, 0, 0"
               VerticalOptions="FillAndExpand"
               HorizontalOptions="StartAndExpand"
                     BackgroundColor="Azure">
            <BindableLayout.ItemTemplate>
                <DataTemplate>
                    <StackLayout HorizontalOptions="FillAndExpand" VerticalOptions="Start" Padding="0" BackgroundColor="Beige">
                        <StackLayout Orientation="Horizontal" 
                                         HorizontalOptions="FillAndExpand"
                                         VerticalOptions="Start">

                            <Image 
                                x:Name="image"
                                Source="{Binding ImageUrl}"  
                                VerticalOptions="StartAndExpand"
                                HorizontalOptions="Start"
                                Margin="0, 2, 0, 0"
                                WidthRequest="15" 
                                HeightRequest="15">
                                <Image.GestureRecognizers>
                                    <TapGestureRecognizer Command="{Binding BindingContext.SelectedItemCommand, Source={x:Reference root}}" CommandParameter="{Binding .}"/>
                                </Image.GestureRecognizers>
                            </Image>

                            <Label        
                                x:Name="name"
                                Text="{Binding Name}"  
                                TextColor="Black"
                                VerticalOptions="StartAndExpand"
                                FontSize="14"
                                HorizontalOptions="Start"/>
                        </StackLayout>
                    </StackLayout>
                </DataTemplate>
            </BindableLayout.ItemTemplate>
        </StackLayout>


        <Label Text="Selection required"
                   TextColor="Red"
                   Margin="0, 10, 0, 0"
                   IsVisible="{Binding ValidationRequired}"
                   VerticalOptions="StartAndExpand"
                   HorizontalOptions="FillAndExpand"
                   FontSize="14"/>

    </StackLayout>
</ViewCell>

xml.cs:

using System;

using Xamarin.Forms;
using Xamarin.Forms.Xaml;

{
    [XamlCompilation(XamlCompilationOptions.Compile)]
    public partial class SelectListTemplate : ViewCell
    {
        private SoapNoteControlsViewModel viewModel;

        public SelectListTemplate()
        {
            InitializeComponent();
        }

        protected override void OnDisappearing()
        {
            base.OnDisappearing();
        }

        protected override void OnAppearing()
        {
            base.OnAppearing();

            LabelName.Text = viewModel.Label;
            MultiselectList.HeightRequest = (30 * viewModel.CheckboxItems.Count) + 10;
            
            MultiselectList.SetBinding(BindableLayout.ItemsSourceProperty, nameof(viewModel.CheckboxItems), BindingMode.TwoWay);

        }

        protected override void OnBindingContextChanged()
        {
            try
            {
                base.OnBindingContextChanged();

                if(BindingContext == null)
                {
                    return;
                }

                viewModel = BindingContext as SoapNoteControlsViewModel;

            } catch (Exception e)
            {
                Console.WriteLine(e);
            }
        }
    }
}

最后,引用模板选择器的整体父列表视图:

<ListView x:Name="lv" ItemsSource="{Binding SoapNoteObjects}" ItemTemplate="{StaticResource SoapNoteDataTemplateSelector}"                      
                                  WidthRequest="500"
                                  SeparatorVisibility="None"
                                  HasUnevenRows="True"
                                  HorizontalOptions="FillAndExpand"
                                  VerticalOptions="FillAndExpand">
                    <ListView.Margin>
                        <OnPlatform x:TypeArguments="Thickness">
                            <On Platform="iOS" Value="30, 0, 0, 0" />
                            <On Platform="Android" Value="30, 0, 0, 0"/>
                        </OnPlatform>
                    </ListView.Margin>
                </ListView>

如果我用视图单元内的 Listview 替换 Stacklayout,那么视觉错误就会消失,但是,它会引入一个问题,即 Xamarin 持有不正确的单元格然后抛出异常(仅在 iOS 上)像这样:NSRangeException Reason: Attempted to scroll the table view to an out-of-bounds row (8) when there are only 2 rows in section 0

我究竟在我的视单元中做错了什么,这导致了这种奇怪的行为,即元素具有混乱的视觉状态,只能通过上下滚动来轻松修复?

标签: c#xamarin.forms

解决方案


推荐阅读