【问题标题】:In Ios ListView automatically scroll to top when Item source is updated in xamarin.forms. Maintain scroll position in ios在 xamarin.forms 中更新项目源时,Ios ListView 会自动滚动到顶部。在ios中保持滚动位置
【发布时间】:2017-03-22 10:11:54
【问题描述】:

我正在研究 xamarin.forms。我面临一个问题。我有一个 ListView。我在没有任何 MVVM 模式 (不遵循 MVVM) 的情况下将 List 对象作为 ItemSource 提供给该 listView。 List 对象在 Item Tap 或 Image 手势点击上更新,然后我再次将 itemsource 提供给 Listview。

在 ios 中,当我将项目源重新绑定到 listview 时,会自动滚动到顶部。所以选定的项目对用户不可见。

在 Android 中完美运行。

<ListView x:Name="lstLeaveNotificationDetails" HorizontalOptions="FillAndExpand" HasUnevenRows="True"
                  VerticalOptions="FillAndExpand" SeparatorVisibility="None" BackgroundColor="Transparent"
                  AbsoluteLayout.LayoutFlags="All" AbsoluteLayout.LayoutBounds="0,0,1,1" IsVisible="false">
          <ListView.ItemTemplate>
            <DataTemplate>
              <ViewCell>
                <ViewCell.View>
                  <StackLayout x:Name="StkForListItems" ClassId="{Binding TapId}">
                    <!--Left Side Orange Color Padding-->
                    <StackLayout Padding="4,0,0,0" BackgroundColor="{Binding BgMainStackColor}">
                      <StackLayout  BackgroundColor="{Binding BgColor}" HorizontalOptions="Start">
                        <Grid Padding="3" HorizontalOptions="StartAndExpand" VerticalOptions="Center" RowSpacing="1" ColumnSpacing="0">
                          <Grid.RowDefinitions>
                            <RowDefinition Height="Auto" />
                            <RowDefinition Height="Auto" />
                            <RowDefinition Height="Auto" />
                            <RowDefinition Height="Auto" />
                            <RowDefinition Height="Auto" />
                          </Grid.RowDefinitions>
                          <Grid.ColumnDefinitions>
                            <ColumnDefinition Width="1*" />
                            <ColumnDefinition Width="3*" />
                            <ColumnDefinition Width="3*" />
                            <ColumnDefinition Width="3*" />
                          </Grid.ColumnDefinitions>

                          <StackLayout Grid.Row="0" Grid.Column="0"  Grid.RowSpan="5" HorizontalOptions="Center" VerticalOptions="Center" >
                            <ffimageloading:CachedImage Source="{Binding CheckSelect}" Aspect="Fill" ClassId="{Binding TapId}" HorizontalOptions="Center" VerticalOptions="Center" >
                              <ffimageloading:CachedImage.GestureRecognizers>
                                <TapGestureRecognizer Tapped="img_Tapped" NumberOfTapsRequired="1" />
                              </ffimageloading:CachedImage.GestureRecognizers>
                            </ffimageloading:CachedImage>
                          </StackLayout>

                          <StackLayout Grid.Row="0" Grid.Column="1" Grid.ColumnSpan="3">
                            <Label Text="{Binding EmpNm}" TextColor="Black" FontSize="Medium" FontAttributes="Bold"/>
                          </StackLayout>

                          <Label Text="From" Grid.Row="1" Grid.Column="1"  TextColor="#B0B0B0" HorizontalOptions="StartAndExpand" VerticalOptions="Start"  FontSize="Small"/>
                          <Label Text="To" Grid.Row="1" Grid.Column="2"  TextColor="#B0B0B0" HorizontalOptions="StartAndExpand" VerticalOptions="Start"  FontSize="Small"/>
                          <Label Text="Leave Days" Grid.Row="1"  Grid.Column="3"  TextColor="#B0B0B0" HorizontalOptions="StartAndExpand" VerticalOptions="Start"  FontSize="Small"/>

                          <Label Text="{Binding FromDate}" Grid.Row="2"  Grid.Column="1" TextColor="Black" HorizontalOptions="StartAndExpand"    FontSize="Small"  />
                          <Label Text="{Binding ToDate}" Grid.Row="2"   Grid.Column="2" TextColor="Black" HorizontalOptions="StartAndExpand"   FontSize="Small"  />
                          <Label Text="{Binding NoOfLeave}" Grid.Row="2"  Grid.Column="3" TextColor="Black" HorizontalOptions="StartAndExpand"   FontSize="Small"  />

                          <StackLayout  Grid.Row="3"  Grid.Column="1"  Grid.ColumnSpan="3" VerticalOptions="EndAndExpand" HorizontalOptions="Start">
                            <Label Text="Reason" TextColor="#b0b0b0"   FontSize="Small"/>
                          </StackLayout>

                          <StackLayout  Grid.Row="4" Grid.Column="1"   Grid.ColumnSpan="3" VerticalOptions="StartAndExpand" HorizontalOptions="StartAndExpand">
                            <Label Text="{Binding Reason}" TextColor="Black"   FontSize="Small" />
                          </StackLayout>
                        </Grid>
                      </StackLayout>
                    </StackLayout>
                    <BoxView  HorizontalOptions="FillAndExpand" VerticalOptions="FillAndExpand" HeightRequest="3"/>
                    <StackLayout.GestureRecognizers>
                      <TapGestureRecognizer Tapped="OnItemTapped" NumberOfTapsRequired="1" />
                    </StackLayout.GestureRecognizers>
                  </StackLayout>
                </ViewCell.View>
              </ViewCell>
            </DataTemplate>
          </ListView.ItemTemplate>
        </ListView>

后端代码:在 Image Tap 上我调用了以下函数。更新 List 对象并将其提供给 itemSource

public void ItemSelectionChanged(CachedImage source, StackLayout lstView)
        {
            var objClassId = "";
            if (source != null)
            {
                objClassId = source.ClassId;
            }
            else
            {
                objClassId = lstView.ClassId;
            }

            switch (Key)
            {
                case "LA":
                    if (objLstLeaveLst != null)
                    {
                        LeaveLst objtempLeaveLst = objLstLeaveLst.Find(s => s.TapId.ToString() == objClassId);
                        int index = objLstLeaveLst.IndexOf(objtempLeaveLst);

                        if (objLstLeaveLst[index].CheckSelect.ToString() == AppResources.ImgNotificationSelectionFalse)
                        {
                            objLstLeaveLst[index].CheckSelect = AppResources.ImgNotificationSelectionTrue;
                            List<bool> ImageSelectionFlag = objLstLeaveLst.Select(s => s.CheckSelect.ToString() == "check_sel.png").ToList();
                            ChangeSelectionImage(ImageSelectionFlag);
                        }
                        else
                        {
                            objLstLeaveLst[index].CheckSelect = AppResources.ImgNotificationSelectionFalse;
                            imgSelectAll.Source = "check_nor.png";
                            imgSelectAll.ClassId = "false";
                            lblSelectAll.ClassId = "false";
                        }

                        if (objLstLeaveLst[index].BgMainStackColor.Equals(Color.FromHex("#dddddd")))
                        {
                            objLstLeaveLst[index].BgMainStackColor = Color.FromHex("#f15a23");
                        }
                        else
                        {
                            objLstLeaveLst[index].BgMainStackColor = Color.FromHex("#dddddd");
                        }

                        lstLeaveNotificationDetails.ItemsSource = null;
                        lstLeaveNotificationDetails.ItemsSource = objLstLeaveLst;
                        if (Device.OS == TargetPlatform.iOS)
                        {
                            lstLeaveNotificationDetails.ScrollTo(objtempLeaveLst, ScrollToPosition.MakeVisible, false);
                        }
                    }
                    break;
}
}

为了解决这个问题,我写了以下代码

if (Device.OS == TargetPlatform.iOS)
                            {
                                lstLeaveNotificationDetails.ScrollTo(objtempLeaveLst, ScrollToPosition.MakeVisible, false);
                            }

但它没有给我正确的输出。如何在ios中保持滚动位置。请帮我在 ios 中渲染 listView。当我更新项目源时不想滚动列表视图。

我也尝试过 ObservableCollection,但我的 GUI 在项目点击(图像点击和堆栈点击)时没有更新。

【问题讨论】:

  • 你能分享一下你的 LeaveLst 课程吗?

标签: ios uitableview xamarin xamarin.ios xamarin.forms


【解决方案1】:

iOS 处理更新ListView 及其ItemsSource 的方式是更新UITableView 底层的ViewSource。在 Xamarin.Forms 或本机 iOS 上,这将清除您的整个列表,并重新添加项目。

完成您想要做的事情的方法是使用ObservableCollection AND 让您的模型实现INotifyPropertyChanged

如果您的行为模型和您的个人CellBindingContext 更新绑定到视图的属性,那么它将更新该单个Cell,而无需重新绑定整个列表。

此外,在 UI 上重新应用 ItemsSource 是一个代价高昂的过程,而更新单个单元格的代价却很便宜!

这是一个例子:

模型-

public class TodoItem : INotifyPropertyChanged
{
    private string _text;
    public string Text
    {
        get
        {
            return _text;
        }
        set
        {
            _text = value;
            PropertyChanged?.Invoke(new PropertyChangedEventArgs("Text"));
        }
    }
}

那么你的看法:

<ListView x:Name="MyListView" ItemsSource="{Binding TodoItems}">
    <ListView.ItemTemplate>
        <DataTemplate>
           <TextCell Text="{Binding Text}"/>
        </DataTemplate>
    </ListView.ItemTemplate>
</ListView>

然后你的代码在后面:

...
MyListView.BindingContext = this;
...
public ObservableCollection<TodoItem> TodoItems { get; set; }
...
// change the text of one item
TodoItems[1].Text = "New Text!";
...

然后您将看到正确的单元格更新文本字段,而无需更新任何其他项目,并且还保持滚动位置!

【讨论】:

    【解决方案2】:

    使用listView.ScrollTo()方法,见下文:

     listView.ItemSelected += (sender, e) =>
                { 
         listView.ScrollTo(e.SelectedItem, ScrollToPosition.MakeVisible, false);               
    };
    

    【讨论】:

      猜你喜欢
      • 2019-01-21
      • 1970-01-01
      • 1970-01-01
      • 2012-03-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-02-24
      相关资源
      最近更新 更多