You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

.NET MAUI实现ListView条目点击缩放动画的问题

.NET MAUI ListView条目点击缩放动画失效的解决方法

在.NET MAUI中使用ListView时,想要实现点击条目时先放大再缩小的动画效果,已获取到ViewCell及其内部的Grid,但修改Scale属性后无效果,怀疑是ListView的渲染机制导致后续修改不触发重新渲染。

原XAML代码

<?xml version="1.0" encoding="utf-8" ?>
<ContentView xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="GakugoMAUI.Views.LessonListView">
    <ContentView.Resources>
        <ResourceDictionary>
            
            <DataTemplate x:Key="LessonButton">
                <ViewCell>
                    <Grid Scale="1">
                        <BoxView HorizontalOptions="Fill" 
                                 VerticalOptions="Fill"
                                 CornerRadius="10"
                                 Color="{AppThemeBinding Light={StaticResource Gray100}, Dark={StaticResource Gray750}}"/>
                        <Grid>
                            <Grid.ColumnDefinitions>
                                <ColumnDefinition Width="Auto"/>
                                <ColumnDefinition Width="20"/>
                                <ColumnDefinition Width="*"/>
                                <ColumnDefinition Width="10"/>
                                <ColumnDefinition Width="Auto"/>
                            </Grid.ColumnDefinitions>

                            <Image VerticalOptions="Fill"
                                   Margin="15,0,0,0"
                                   Scale="1.1"
                                   Grid.Column="0">
                                <Image.Source>
                                    <FontImageSource Glyph="{Binding Glyph}"
                                                     FontFamily="{Binding GlyphFontFamily}"
                                                     Color="{AppThemeBinding Light={StaticResource Primary}, Dark={StaticResource Secondary}}"/>
                                </Image.Source>
                            </Image>

                            <Grid Grid.Column="2">
                                <Grid.RowDefinitions>
                                    <RowDefinition Height="10"/>
                                    <RowDefinition Height="*"/>
                                    <RowDefinition Height="Auto"/>
                                    <RowDefinition Height="10"/>
                                </Grid.RowDefinitions>

                                <Label Text="{Binding TitleText}"
                                       FontSize="16"
                                       Grid.Row="1"/>
                                <Label Text="{Binding SubtitleText}"
                                       FontSize="12"
                                       FontAttributes="Italic"
                                       Grid.Row="2"/>
                            </Grid>
                        </Grid>
                    </Grid>
                </ViewCell>
            </DataTemplate>
            
        </ResourceDictionary>
    </ContentView.Resources>

    <Grid>
        <ListView x:Name="lessonsList" 
                    ItemsSource="{Binding LessonButtons}" 
                    ItemTemplate="{StaticResource LessonButton}"
                    ItemTapped="LessonButton_Clicked"
                    Margin="10"
                    Grid.Row="3"/>
    </Grid>
</ContentView>

原点击处理代码

public async void LessonButton_Clicked(object sender, ItemTappedEventArgs e)
{
    if (sender is ListView list)
    {
        var cells = list.GetVisualTreeDescendants().Where(x => x.GetType() == typeof(ViewCell));
        Grid currentItem = (Grid)((ViewCell)cells.ElementAt(e.ItemIndex)).View;
        await currentItem.ScaleTo(1.5);
        await currentItem.ScaleTo(1);
    }
}

解决方案

问题核心是获取当前点击Cell的方式错误:ListView采用ViewCell复用机制,通过遍历VisualTree并按索引取Cell的方法,无法保证拿到用户实际点击的条目(滚动后索引对应关系会混乱)。正确做法是使用ListView的GetCell方法获取当前Item对应的ViewCell。

修改后的点击处理代码

public async void LessonButton_Clicked(object sender, ItemTappedEventArgs e)
{
    if (sender is ListView listView && e.Item != null)
    {
        // 获取当前点击Item对应的ViewCell
        var viewCell = (ViewCell)listView.GetCell(e.Item);
        if (viewCell?.View is Grid itemGrid)
        {
            // 先重置缩放状态,避免重复点击出现异常
            itemGrid.Scale = 1;
            // 执行放大动画(150ms完成,可根据需求调整时间)
            await itemGrid.ScaleTo(1.5, 150);
            // 执行缩小动画
            await itemGrid.ScaleTo(1, 150);
        }
    }
}

优化补充

如果要避免重复点击导致的动画冲突,可以在动画开始前取消未完成的动画:

public async void LessonButton_Clicked(object sender, ItemTappedEventArgs e)
{
    if (sender is ListView listView && e.Item != null)
    {
        var viewCell = (ViewCell)listView.GetCell(e.Item);
        if (viewCell?.View is Grid itemGrid)
        {
            // 取消之前未完成的动画
            await itemGrid.CancelAnimations();
            itemGrid.Scale = 1;
            await itemGrid.ScaleTo(1.5, 150);
            await itemGrid.ScaleTo(1, 150);
        }
    }
}

内容的提问来源于stack exchange,提问作者joeatethebeans

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.17 12:25:56