【问题标题】:Make a ListView scroll to the bottom automatically when a new message is received?收到新消息时,让 ListView 自动滚动到底部?
【发布时间】:2019-04-09 16:54:06
【问题描述】:

我一直在使用 this example 在 xamarin 中构建一个移动应用程序来与我的聊天机器人交互。我遇到的问题是,显示机器人和用户之间消息的 ListView 不会在其中显示新消息时自动滚动到底部。代码如下:

<ContentPage.Content>
    <StackLayout Margin="5">
        <ListView x:Name="ChatListView"
            VerticalOptions="FillAndExpand"
            SelectedItem="{Binding SelectedMessage}"
            ItemsSource="{Binding BotMessages, Mode=TwoWay}"
            BackgroundColor="Azure"
            HasUnevenRows="True" 
            SeparatorVisibility="None"
            ItemTemplate="{StaticResource ChatDataTemplateSelector}"/>
        <StackLayout Orientation="Horizontal">
            <Entry Placeholder="Ask a question.."
                Margin="5"
                Keyboard="Chat"
                Text="{Binding CurrentMessage, Mode=TwoWay}"
                HorizontalOptions="FillAndExpand"
                Completed="Entry_Completed"/>
            <Button Text="Send" Command="{Binding SendCommand}"/>
        </StackLayout>
    </StackLayout>
</ContentPage.Content> 

有没有办法让 Listview 在收到新消息时自动滚动到底部?

【问题讨论】:

    标签: listview xamarin.forms


    【解决方案1】:

    要滚动到某个项目,您所要做的就是:

    ChatListView.ScrollTo(item, ScrollToPosition.MakeVisible, true);
    

    如果您想要一个在与可观察集合一起使用时自动滚动到新/更新项目的列表,您可以尝试使用此扩展:

    namespace Your.Namespace.For.Custom.Controls
    {
        public class AutoScrollListView : ListView
        {
            private INotifyCollectionChanged _previousObservableCollection;
    
            public AutoScrollListView(ListViewCachingStrategy cachingStrategy)
                : base(cachingStrategy)
            {
            }
    
            public AutoScrollListView()
                : base()
            {
            }
    
            protected override void OnPropertyChanged([CallerMemberName] string propertyName = null)
            {
                base.OnPropertyChanged(propertyName);
    
                if (propertyName == nameof(ItemsSource))
                {
                    if (_previousObservableCollection != null)
                    {
                        _previousObservableCollection.CollectionChanged -= OnItemsSourceCollectionChanged;
                        _previousObservableCollection = null;
                    }
    
                    if (ItemsSource is INotifyCollectionChanged newObservableCollection)
                    {
                        _previousObservableCollection = newObservableCollection;
                        newObservableCollection.CollectionChanged += OnItemsSourceCollectionChanged;
                    }
                }
            }
    
            private void OnItemsSourceCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
            {
                if (e.Action == NotifyCollectionChangedAction.Add || e.Action == NotifyCollectionChangedAction.Replace)
                {
                    foreach (var item in e.NewItems)
                    {
                        // Scroll to the item that has just been added/updated to make it visible
                        ScrollTo(item, ScrollToPosition.MakeVisible, true);
                    }
                }
            }
        }
    }
    

    要使用它,请记住将其命名空间添加到 XAML 文件中:

    <Page 
        xmlns="http://xamarin.com/schemas/2014/forms" 
        xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
        xmlns:custom="clr-namespace:Your.Namespace.For.Custom.Controls" 
        x:Class="Your.Namespace.YourPage">
    
        ...
    
        <ContentPage.Content>
            <StackLayout Margin="5">
                <custom:AutoScrollListView
                    x:Name="ChatListView"
                    VerticalOptions="FillAndExpand"
                    SelectedItem="{Binding SelectedMessage}"
                    ItemsSource="{Binding BotMessages, Mode=TwoWay}"
                    BackgroundColor="Azure"
                    HasUnevenRows="True" 
                    SeparatorVisibility="None"
                    ItemTemplate="{StaticResource ChatDataTemplateSelector}" />
                <StaLayout Orientation="Horizontal">
                    <Entry 
                        Placeholder="Ask a question.." 
                        Margin="5" 
                        Keyboard="Chat"
                        Text="{Binding CurrentMessage, Mode=TwoWay}"
                        HorizontalOptions="FillAndExpand"
                        Completed="Entry_Completed"/>
                    <Button Text="Send" Command="{Binding SendCommand}" />
                </StackLayout>
            </StackLayout>
        </ContentPage.Content> 
    
        ...
    
    </Page>
    

    请记住,如上所述,此自定义列表仅在属性 ItemsSource 绑定到可观察集合时才会自动滚动。

    希望对你有帮助!

    【讨论】:

    • 这看起来会有所帮助!为了清楚起见,我是否会在我的项目中创建一个“自定义”文件夹并将 AutoScrollListView 代码放在那里,然后只需将 xaml 元素从“Listview”更改为“AutoScrollListView”?
    • 太好了,感谢您的澄清!这将有很大帮助!
    • 很高兴为您提供帮助!请考虑到您可以通过许多其他方式实现此目的,以上只是一个建议。例如,您可以从视图订阅一些视图模型事件或属性,以了解何时添加了项目,然后手动调用ChatListView.ScrollTo(item, ScrollToPosition.MakeVisible, true)
    • 在我试验我的实现时,我会牢记这些。再次感谢!
    猜你喜欢
    • 2023-03-22
    • 2022-12-23
    • 2018-07-21
    • 2016-11-22
    • 1970-01-01
    • 1970-01-01
    • 2022-01-17
    • 2018-02-27
    • 1970-01-01
    相关资源
    最近更新 更多