Xamarin 表单:扩展和折叠不适用于 iOS 中的列表视图

Xamarin forms: Expansion and collapse is not working for list view in iOS

我在 UI 上列出了一些项目。如果我点击一个项目,它将展开并显示其详细信息。我在 UI 上设置了所有内容,包括最初的详细信息并隐藏了详细信息部分。当我点击该项目时,我更改了细节的可见性并将其显示在 UI 上。此功能在 android 上运行良好并在 ios 上运行良好。我已经上传了一个示例项目 here 以供参考。

截图:

Xaml.cs

    private void ItemTapped(object sender, ItemTappedEventArgs e)
    {
        var selectedItem = (Contact)e.Item;
        if (selectedItem != null)
        {
            if (phoneId == selectedItem.phoneOne)
            {
                Hide(selectedItem);
                phoneId = "";
            }
            else
            {
                Open(selectedItem);
            }
        }
        addressbook_listview.SelectedItem = null;
    }

    private void Open(Contact selectedItem)
    {
        
        foreach (var item in contactsList)
        {
            item.PhoneVisibility = false;
        }
        selectedItem.PhoneVisibility = true;
        phoneId = selectedItem.phoneOne;
    }
    
    private void Hide(Contact selectedItem)
    {
        selectedItem.PhoneVisibility = false;
    }

Xaml

    <ListView   
        x:Name="addressbook_listview"
        Grid.Row="1"
        BackgroundColor="Black"
        ItemTapped="addressbook_listview_ItemTapped"
        SelectionMode="None"
        HasUnevenRows="True">
        <ListView.ItemTemplate>
            <DataTemplate>
                <ViewCell>
                    <StackLayout 
                        Padding="10"
                        Orientation="Vertical">

                        <StackLayout
                                Grid.Column="1"
                                VerticalOptions="CenterAndExpand"
                                Margin="5,0,0,0">

                            <Label 
                                    Text="{Binding contactName}"
                                    TextColor="White">
                                <Label.FontSize>
                                    <OnIdiom x:TypeArguments="x:Double">
                                        <OnIdiom.Phone>15</OnIdiom.Phone>
                                        <OnIdiom.Tablet>20</OnIdiom.Tablet>
                                        <OnIdiom.Desktop>15</OnIdiom.Desktop>
                                    </OnIdiom>
                                </Label.FontSize>
                            </Label>

                            <Label 
                                    Text="{Binding phoneOne}"
                                    TextColor="White">
                                <Label.FontSize>
                                    <OnIdiom x:TypeArguments="x:Double">
                                        <OnIdiom.Phone>15</OnIdiom.Phone>
                                        <OnIdiom.Tablet>20</OnIdiom.Tablet>
                                        <OnIdiom.Desktop>15</OnIdiom.Desktop>
                                    </OnIdiom>
                                </Label.FontSize>
                            </Label>
                        </StackLayout>

                        <StackLayout 
                            HorizontalOptions="CenterAndExpand"
                            Margin="0,10,0,0"
                            IsVisible="{Binding PhoneVisibility}"
                            Orientation="Vertical">

                            <StackLayout 
                                Orientation="Horizontal">

                                <Label 
                                    Text="Phone 1"
                                    TextColor="White">
                                    <Label.FontSize>
                                        <OnIdiom x:TypeArguments="x:Double">
                                            <OnIdiom.Phone>15</OnIdiom.Phone>
                                            <OnIdiom.Tablet>20</OnIdiom.Tablet>
                                            <OnIdiom.Desktop>15</OnIdiom.Desktop>
                                        </OnIdiom>
                                    </Label.FontSize>
                                </Label>

                                    <Label 
                                    Text="{Binding phoneOne}"
                                    TextColor="White">
                                    <Label.FontSize>
                                        <OnIdiom x:TypeArguments="x:Double">
                                            <OnIdiom.Phone>15</OnIdiom.Phone>
                                            <OnIdiom.Tablet>20</OnIdiom.Tablet>
                                            <OnIdiom.Desktop>15</OnIdiom.Desktop>
                                        </OnIdiom>
                                    </Label.FontSize>
                                </Label>

                            </StackLayout>

                            <BoxView HeightRequest="0.5"
                                     HorizontalOptions="FillAndExpand"/>

                            <StackLayout
                                Orientation="Horizontal">

                                <Label 
                                    Text="Phone 2"
                                     TextColor="White">
                                    <Label.FontSize>
                                        <OnIdiom x:TypeArguments="x:Double">
                                            <OnIdiom.Phone>15</OnIdiom.Phone>
                                            <OnIdiom.Tablet>20</OnIdiom.Tablet>
                                            <OnIdiom.Desktop>15</OnIdiom.Desktop>
                                        </OnIdiom>
                                    </Label.FontSize>
                                </Label>

                                <Label 
                                    Text="{Binding phoneTwo}"
                                    TextColor="White">
                                    <Label.FontSize>
                                        <OnIdiom x:TypeArguments="x:Double">
                                            <OnIdiom.Phone>15</OnIdiom.Phone>
                                            <OnIdiom.Tablet>20</OnIdiom.Tablet>
                                            <OnIdiom.Desktop>15</OnIdiom.Desktop>
                                        </OnIdiom>
                                    </Label.FontSize>
                                </Label>
                            </StackLayout>
                        </StackLayout>
                    </StackLayout>
                </ViewCell>
            </DataTemplate>
        </ListView.ItemTemplate>
        <ListView.Footer>
            <Label/>
        </ListView.Footer>
    </ListView>

简而言之:使用 CollectionView 而不是 ListView

我认为这是一个已知问题,如问题 this and this,但没有得到正确回答。
所以决定迁移到 CollectionView,因为应该是官方推荐的。

我在这里更改的内容:

  • 使用CollectionView
  • 将点击事件移动到 TapGestureRecognizer
  • 删除 xaml
  • 中的“网格”
  • 使列表绑定到 xaml,并在 xaml.cs
  • 中绑定到自身
  • 绑定列表应该是public属性,而不是字段
  • 最后一件事:更新到 Xamarin.Forms 5.0.0.2012(和 Android 设置)

没有新的 XF 包,集合视图在更新高度时有另一个问题(运行 没有在 iOS 上更新 XF,虽然解决了这个问题)。
我认为这也是一个已知问题,因此升级 XF 包修复了该问题,
但这也需要更新“目标 Android 版本”。
(一些代码仍然可以重构,但现在可以使用)

MainPage.xaml

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage
    x:Class="ExpanderDemo.MainPage"
    xmlns="http://xamarin.com/schemas/2014/forms"
    xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml">
    <StackLayout>
        <CollectionView
            x:Name="addressbook_listview"
            BackgroundColor="Black"
            ItemSizingStrategy="MeasureAllItems"
            ItemsSource="{Binding contactsList}"
            SelectionMode="None">
            <CollectionView.ItemTemplate>
                <DataTemplate>
                    <StackLayout Padding="10" Orientation="Vertical">
                        <StackLayout.GestureRecognizers>
                            <TapGestureRecognizer Tapped="addressbook_listview_ItemTapped" />
                        </StackLayout.GestureRecognizers>

                        <StackLayout Margin="5,0,0,0">

                            <Label Text="{Binding contactName}" TextColor="White">
                                <Label.FontSize>
                                    <OnIdiom x:TypeArguments="x:Double">
                                        <OnIdiom.Phone>15</OnIdiom.Phone>
                                        <OnIdiom.Tablet>20</OnIdiom.Tablet>
                                        <OnIdiom.Desktop>15</OnIdiom.Desktop>
                                    </OnIdiom>
                                </Label.FontSize>
                            </Label>

                            <Label Text="{Binding phoneOne}" TextColor="White">
                                <Label.FontSize>
                                    <OnIdiom x:TypeArguments="x:Double">
                                        <OnIdiom.Phone>15</OnIdiom.Phone>
                                        <OnIdiom.Tablet>20</OnIdiom.Tablet>
                                        <OnIdiom.Desktop>15</OnIdiom.Desktop>
                                    </OnIdiom>
                                </Label.FontSize>
                            </Label>
                        </StackLayout>

                        <StackLayout
                            Margin="0,10,0,0"
                            HorizontalOptions="CenterAndExpand"
                            IsVisible="{Binding PhoneVisibility}"
                            Orientation="Vertical">

                            <StackLayout Orientation="Horizontal">

                                <Label Text="Phone 1" TextColor="White">
                                    <Label.FontSize>
                                        <OnIdiom x:TypeArguments="x:Double">
                                            <OnIdiom.Phone>15</OnIdiom.Phone>
                                            <OnIdiom.Tablet>20</OnIdiom.Tablet>
                                            <OnIdiom.Desktop>15</OnIdiom.Desktop>
                                        </OnIdiom>
                                    </Label.FontSize>
                                </Label>

                                <Label Text="{Binding phoneOne}" TextColor="White">
                                    <Label.FontSize>
                                        <OnIdiom x:TypeArguments="x:Double">
                                            <OnIdiom.Phone>15</OnIdiom.Phone>
                                            <OnIdiom.Tablet>20</OnIdiom.Tablet>
                                            <OnIdiom.Desktop>15</OnIdiom.Desktop>
                                        </OnIdiom>
                                    </Label.FontSize>
                                </Label>

                            </StackLayout>

                            <BoxView HeightRequest="0.5" HorizontalOptions="FillAndExpand" />

                            <StackLayout Orientation="Horizontal">

                                <Label Text="Phone 2" TextColor="White">
                                    <Label.FontSize>
                                        <OnIdiom x:TypeArguments="x:Double">
                                            <OnIdiom.Phone>15</OnIdiom.Phone>
                                            <OnIdiom.Tablet>20</OnIdiom.Tablet>
                                            <OnIdiom.Desktop>15</OnIdiom.Desktop>
                                        </OnIdiom>
                                    </Label.FontSize>
                                </Label>

                                <Label Text="{Binding phoneTwo}" TextColor="White">
                                    <Label.FontSize>
                                        <OnIdiom x:TypeArguments="x:Double">
                                            <OnIdiom.Phone>15</OnIdiom.Phone>
                                            <OnIdiom.Tablet>20</OnIdiom.Tablet>
                                            <OnIdiom.Desktop>15</OnIdiom.Desktop>
                                        </OnIdiom>
                                    </Label.FontSize>
                                </Label>
                            </StackLayout>
                        </StackLayout>
                    </StackLayout>
                </DataTemplate>
            </CollectionView.ItemTemplate>
            <CollectionView.Footer>
                <Label />
            </CollectionView.Footer>
        </CollectionView>
    </StackLayout>
</ContentPage>

MainPage.xaml.cs

using System;
using System.Collections.ObjectModel;
using Xamarin.Forms;

namespace ExpanderDemo
{
    public partial class MainPage : ContentPage
    {
        private string phoneId;

        public MainPage()
        {
            InitializeComponent();
            contactsList = new ObservableCollection<Contact>();
            AddNumber();
            BindingContext = this;
        }

        public ObservableCollection<Contact> contactsList { get; set; }

        private void AddNumber()
        {
            contactsList.Add(new Contact() { contactName = "Smith", phoneOne = "+1 1234567952", phoneTwo = "1478523690", PhoneVisibility = false });
            contactsList.Add(new Contact() { contactName = "Brent", phoneOne = "+1 1234568852", phoneTwo = "1478577690", PhoneVisibility = false });
            contactsList.Add(new Contact() { contactName = "Finch", phoneOne = "+1 1234560052", phoneTwo = "1478529690", PhoneVisibility = false });
            //addressbook_listview.ItemsSource = contactsList;
        }

        private void addressbook_listview_ItemTapped(object sender, EventArgs e)
        {
            var layout = sender as StackLayout;
            var selectedItem = layout.BindingContext as Contact;

            //var selectedItem = (Contact)e.Item;
            if (selectedItem != null)
            {
                if (phoneId == selectedItem.phoneOne)
                {
                    HideMessageBody(selectedItem);
                    phoneId = "";
                }
                else
                {
                    OpenMessageBody(selectedItem);
                }
            }
            addressbook_listview.SelectedItem = null;
        }

        private void HideMessageBody(Contact selectedItem)
        {
            selectedItem.PhoneVisibility = false;
        }

        private void OpenMessageBody(Contact selectedItem)
        {
            foreach (var item in contactsList)
            {
                item.PhoneVisibility = false;
            }
            selectedItem.PhoneVisibility = true;
            phoneId = selectedItem.phoneOne;
        }
    }
}

Android更新XF后的两个设置


测试结果

(我在本地测试时请忽略ios上的颜色。)

这是@Shaw 指出的已知问题。

可以调用ViewCell.ForceUpdateSize强制更新单元格的高度。

第一步是删除 ItemTapped 并使用 Tap gesture 代替。

在 ItemTemplate 的根 stackLayout 上添加一个 TapGestureRecognizer

xaml
<ViewCell x:Name="cell" >
        <StackLayout 
             Padding="10"
             Orientation="Vertical">
             <StackLayout.GestureRecognizers>
                  <TapGestureRecognizer Tapped="TapGestureRecognizer_Tapped"/>
             </StackLayout.GestureRecognizers>
代码隐藏。
  private void TapGestureRecognizer_Tapped(object sender, EventArgs e)
        {

            var stack = sender as StackLayout;
            var selectedItem = stack.BindingContext as Contact;

            if (selectedItem != null)
            {
                if (phoneId == selectedItem.phoneOne)
                {
                    HideMessageBody(selectedItem);
                    phoneId = "";
                }
                else
                {
                    OpenMessageBody(selectedItem);
                }
            }
            addressbook_listview.SelectedItem = null;         

            (stack.Parent as ViewCell).ForceUpdateSize();   //add this line 
        }