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

MAUI中ScrollView嵌套Grid时比例行ListView布局异常问题求助

解决MAUI中ScrollView与ListView的布局冲突问题

我完全懂你遇到的糟心事——给外层加了ScrollView后,原本设置Height="*"的ListView直接撑满整个屏幕,把其他元素都挤到看不见的地方了。这本质是因为ScrollView不会给子元素设置固定高度上限,Grid的*行根本没法算出“剩余空间”,只能让ListView无限制扩展。

结合你需要动态添加元素、整体页面可滚动的需求,这里有两个实用的解决方案:

方案一:改用CollectionView(MAUI官方推荐)

CollectionView比ListView更灵活,在ScrollView里的表现也更稳定。我们只需要把Grid第三行的*改成Auto,让CollectionView自适应内容高度,当整个页面总内容超过屏幕时,ScrollView自然会触发滚动。

修改后的完整代码如下:

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui" 
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" 
             x:Class="MauiApp4.MainPage">
    <ScrollView VerticalOptions="Fill">
        <Grid HorizontalOptions="Fill" VerticalOptions="Fill">
            <Grid.RowDefinitions>
                <RowDefinition Height="Auto"/>
                <RowDefinition Height="Auto"/>
                <!-- 将*改为Auto,让列表自适应内容高度 -->
                <RowDefinition Height="Auto"/>
                <RowDefinition Height="Auto"/>
                <RowDefinition Height="Auto"/>
            </Grid.RowDefinitions>
            <Image Source="dotnet_bot.png" 
                   SemanticProperties.Description="Cute dot net bot waving hi to you!" 
                   HeightRequest="200" 
                   HorizontalOptions="Center" />
            <Label Grid.Row="1" 
                   Text="Hello, World!" 
                   SemanticProperties.HeadingLevel="Level1" 
                   FontSize="32" 
                   HorizontalOptions="Center" />
            <!-- 替换为CollectionView,用SwipeView替代原有的ContextActions -->
            <CollectionView x:Name="collectionView" 
                            Grid.Row="2" 
                            VerticalOptions="Fill" 
                            ItemsSource="{Binding Monkeys}"
                            MinimumHeightRequest="200">
                <CollectionView.ItemTemplate>
                    <DataTemplate>
                        <SwipeView>
                            <SwipeView.LeftItems>
                                <SwipeItems>
                                    <SwipeItem Text="Favorite" 
                                               IconImageSource="favorite.png" 
                                               Command="{Binding Source={x:Reference collectionView}, Path=BindingContext.FavoriteCommand}" 
                                               CommandParameter="{Binding}" />
                                    <SwipeItem Text="Delete" 
                                               IconImageSource="delete.png" 
                                               Command="{Binding Source={x:Reference collectionView}, Path=BindingContext.DeleteCommand}" 
                                               CommandParameter="{Binding}" />
                                </SwipeItems>
                            </SwipeView.LeftItems>
                            <Grid Padding="10">
                                <Grid.RowDefinitions>
                                    <RowDefinition Height="Auto" />
                                    <RowDefinition Height="Auto" />
                                </Grid.RowDefinitions>
                                <Grid.ColumnDefinitions>
                                    <ColumnDefinition Width="Auto" />
                                    <ColumnDefinition Width="Auto" />
                                </Grid.ColumnDefinitions>
                                <Image Grid.RowSpan="2" 
                                       Source="{Binding ImageUrl}" 
                                       Aspect="AspectFill" 
                                       HeightRequest="60" 
                                       WidthRequest="60" />
                                <Label Grid.Column="1" 
                                       Text="{Binding Name}" 
                                       FontAttributes="Bold" />
                                <Label Grid.Row="1" 
                                       Grid.Column="1" 
                                       Text="{Binding Location}" 
                                       FontAttributes="Italic" 
                                       VerticalOptions="End" />
                            </Grid>
                        </SwipeView>
                    </DataTemplate>
                </CollectionView.ItemTemplate>
            </CollectionView>
            <Label Grid.Row="3" 
                   Text="Welcome to .NET Multi-platform App UI" 
                   SemanticProperties.HeadingLevel="Level2" 
                   SemanticProperties.Description="Welcome to dot net Multi platform App U I" 
                   FontSize="18" 
                   HorizontalOptions="Center" />
            <Button Grid.Row="4" 
                    x:Name="CounterBtn" 
                    Text="Click me" 
                    SemanticProperties.Hint="Counts the number of times you click" 
                    Clicked="OnCounterClicked" 
                    HorizontalOptions="Center" />
        </Grid>
    </ScrollView>
</ContentPage>

方案二:保留ListView,动态计算最大高度

如果你不想替换ListView,可以通过代码动态计算它的最大高度(屏幕可用高度减去其他固定元素的总高度),这样ListView不会无限拉伸,内容超过最大高度时自己滚动;当整个页面(包括动态添加的元素)超过屏幕时,ScrollView再整体滚动。

步骤1:后台代码计算高度

using Microsoft.Maui.Devices;

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

private void SetListViewMaxHeight()
{
    // 获取屏幕有效高度(减去状态栏、导航栏)
    var screenDensity = DeviceDisplay.MainDisplayInfo.Density;
    var screenHeight = DeviceDisplay.MainDisplayInfo.Height / screenDensity;
    var navBarHeight = Application.Current?.MainPage?.Navigation?.NavigationBarHeight ?? 0;
    var statusBarHeight = DeviceDisplay.MainDisplayInfo.StatusBarHeight / screenDensity;
    
    // 计算其他固定元素的总高度(根据你实际元素高度调整)
    var fixedElementsTotal = 200 + 32 + 18 + 44;
    
    // 设置ListView的最大高度
    listView.MaxHeightRequest = screenHeight - navBarHeight - statusBarHeight - fixedElementsTotal;
}

步骤2:修改XAML中的ListView

<ListView x:Name="listView" 
          Grid.Row="2" 
          VerticalOptions="Fill" 
          ItemsSource="{Binding Monkeys}" 
          MinimumHeightRequest="200"
          MaxHeightRequest="0"> <!-- 后台动态赋值 -->
    <!-- 原有ItemTemplate内容保持不变 -->
</ListView>

方案对比

  • 方案一更贴合MAUI的设计趋势,CollectionView性能更好、布局更灵活,用SwipeView替代ContextActions的交互也更统一。
  • 方案二适合需要保留原有ListView逻辑的场景,但需要手动适配不同设备的元素高度,相对繁琐。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.27 13:28:16