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

Xamarin.Forms布局添加ScrollView及控件自适应尺寸问题求助

Fixing CustomControl Full-Screen Issue & Adding ScrollView in Xamarin.Forms

Let's break down why your CustomControl is hogging the entire screen and how to fix it so you can properly add a ScrollView and other elements to your layout.

Root Cause

The main culprit is your CustomControl's root AbsoluteLayout — you set AbsoluteLayout.LayoutBounds="0,1,1,1" which forces it to occupy the full height and width of its parent. On top of that, your MainPage uses an AbsoluteLayout that doesn't properly constrain the StackLayout holding the CustomControl, leading to the full-screen takeover.

Step-by-Step Fixes

1. Adjust CustomControl's Root Layout

First, modify the CustomControl's root to only take the height it needs, not the entire screen. We'll ditch the full-screen bounds and use proper size constraints:

Modified CustomControl XAML

<?xml version="1.0" encoding="UTF-8" ?>
<ContentView x:Class="ControlProject.CustomControl" 
             xmlns="http://xamarin.com/schemas/2014/forms" 
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" 
             x:Name="CustomView">
    <!-- Let the content determine the control's height -->
    <AbsoluteLayout BackgroundColor="White">
        <!-- bottomBar uses auto-sizing for initial height -->
        <StackLayout x:Name="bottomBar" 
                     AbsoluteLayout.LayoutBounds="0,1,1,AutoSize" 
                     AbsoluteLayout.LayoutFlags="PositionProportional,WidthProportional"
                     BackgroundColor="Olive">
            <!-- Keep your existing entry bar layout -->
            <StackLayout x:Name="STACK" Orientation="Horizontal">
                <Frame Margin="0,0,0,2" 
                       Padding="0,0,0,0" 
                       BackgroundColor="{Binding Source={x:Reference CustomView}, Path=FrameColor}" 
                       BorderColor="{Binding Source={x:Reference CustomView}, Path=BorderColor}" 
                       CornerRadius="{Binding Source={x:Reference CustomView}, Path=CornerRadius}" 
                       HasShadow="False" 
                       HorizontalOptions="FillAndExpand">
                    <Grid>
                        <Grid.ColumnDefinitions>
                            <ColumnDefinition Width="Auto" />
                            <ColumnDefinition Width="*" />
                        </Grid.ColumnDefinitions>
                        <ImageButton Grid.Column="0" 
                                     Margin="5,0,0,0" 
                                     BackgroundColor="Transparent" 
                                     Clicked="Button_Clicked" 
                                     HeightRequest="25" 
                                     Source="{Binding Source={x:Reference CustomView}, Path=LeftSideIcon}" />
                        <Entry x:Name="EntryControl" 
                               Grid.Column="1" 
                               Margin="0,0,55,0" 
                               HeightRequest="25" 
                               HorizontalOptions="FillAndExpand" 
                               Keyboard="Chat" 
                               Placeholder="{Binding Source={x:Reference CustomView}, Path=Placeholder}" 
                               Text="{Binding EntryText}" 
                               TextColor="{Binding Source={x:Reference CustomView}, Path=EntryTextColor}" />
                        <ImageButton Grid.Column="1" 
                                     Margin="0,0,40,0" 
                                     BackgroundColor="Transparent" 
                                     Command="{Binding Source={x:Reference CustomView}, Path=DeleteMsgCommand}" 
                                     HeightRequest="25" 
                                     HorizontalOptions="End" 
                                     Source="{Binding Source={x:Reference CustomView}, Path=DeleteMessageIcon}" />
                        <ImageButton Grid.Column="1" 
                                     Margin="0,0,10,0" 
                                     Padding="1" 
                                     BackgroundColor="Transparent" 
                                     Command="{Binding Source={x:Reference CustomView}, Path=InsertImgCommand}" 
                                     HeightRequest="25" 
                                     HorizontalOptions="End" 
                                     Source="{Binding Source={x:Reference CustomView}, Path=InsertImgIcon}" />
                    </Grid>
                </Frame>
                <ImageButton Margin="0,0,5,2" 
                             Padding="15,0,10,0" 
                             BackgroundColor="{Binding Source={x:Reference CustomView}, Path=SendBtnColor}" 
                             Command="{Binding Source={x:Reference CustomView}, Path=SendMsgCommand}" 
                             CornerRadius="30" 
                             HeightRequest="45" 
                             HorizontalOptions="End" 
                             Source="{Binding Source={x:Reference CustomView}, Path=RightSideIcon}" 
                             WidthRequest="45" />
            </StackLayout>

            <!-- Emoji panel: adjust layout to sit above the entry bar -->
            <StackLayout x:Name="frameemojis" 
                         TranslationY="{Binding Height, Source={x:Reference frameemojis}}">
                <Frame>
                    <CollectionView Margin="-10,-15,-10,-10" 
                                    HeightRequest="270" 
                                    ItemsSource="{Binding Source={x:Reference CustomView}, Path=EmojiItemSource}" 
                                    VerticalScrollBarVisibility="Never">
                        <CollectionView.ItemsLayout>
                            <GridItemsLayout Orientation="Horizontal" Span="5" />
                        </CollectionView.ItemsLayout>
                        <CollectionView.ItemTemplate>
                            <DataTemplate>
                                <ImageButton Padding="5" 
                                             BackgroundColor="Transparent" 
                                             Command="{Binding Source={x:Reference CustomView}, Path=EmojiTappedCommand}" 
                                             CommandParameter="{Binding EmojiMethodCommand}" 
                                             HeightRequest="44" 
                                             Source="{Binding EmojiSource}" 
                                             WidthRequest="44" />
                            </DataTemplate>
                        </CollectionView.ItemTemplate>
                    </CollectionView>
                </Frame>
            </StackLayout>
        </StackLayout>
    </AbsoluteLayout>
</ContentView>

2. Update CustomControl Code-Behind for Smooth Animation

Change the animation to use fixed height values instead of proportional ones, so the control doesn't expand beyond its needed space:

bool isShow;
const double maxEmojiHeight = 270; // Matches CollectionView's HeightRequest
const double bottomBarMinHeight = 50; // Approx height of your entry bar

private void Button_Clicked(object sender, EventArgs e)
{
    if (!isShow)
    {
        // Show emoji panel with smooth slide
        Device.BeginInvokeOnMainThread(async () =>
        {
            var currentHeight = bottomBarMinHeight;
            while (currentHeight < bottomBarMinHeight + maxEmojiHeight)
            {
                await Task.Delay(1);
                currentHeight += 8; // Adjust speed as needed
                bottomBar.HeightRequest = currentHeight;
            }
            frameemojis.TranslationY = 0; // Slide emoji panel into view
        });
    }
    else
    {
        // Hide emoji panel
        Device.BeginInvokeOnMainThread(async () =>
        {
            frameemojis.TranslationY = frameemojis.Height; // Slide out first
            var currentHeight = bottomBarMinHeight + maxEmojiHeight;
            while (currentHeight > bottomBarMinHeight)
            {
                await Task.Delay(1);
                currentHeight -= 8;
                bottomBar.HeightRequest = currentHeight;
            }
        });
    }
    isShow = !isShow;
}

3. Fix MainPage Layout to Add ScrollView

Now you can properly add a ScrollView above the CustomControl. We'll use a Grid instead of AbsoluteLayout for predictable layout behavior:

Modified MainPage XAML

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage x:Class="App24.MainPage" 
             xmlns="http://xamarin.com/schemas/2014/forms" 
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" 
             xmlns:fav="clr-namespace:ControlProject;assembly=ControlProject">
    <!-- Grid splits screen into scrollable area and fixed bottom control -->
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="*" /> <!-- ScrollView takes remaining space -->
            <RowDefinition Height="Auto" /> <!-- CustomControl fits its own height -->
        </Grid.RowDefinitions>

        <!-- Scrollable content area -->
        <ScrollView Grid.Row="0" BackgroundColor="#4DFF0000">
            <StackLayout>
                <!-- Add your scrollable elements here -->
                <Label Text="Sample Scrollable Content" Margin="20" FontSize="Large"/>
                <Label Text="More content to scroll through..." Margin="20" FontSize="Medium"/>
                <!-- Add as many elements as you need -->
            </StackLayout>
        </ScrollView>

        <!-- CustomControl anchored to the bottom -->
        <fav:CustomControl Grid.Row="1"
                           x:Name="entrycontrol" 
                           BorderColor="{Binding EntryBorderColor}" 
                           CornerRadius="{Binding EntryRadius}" 
                           DeleteMessageIcon="crossblack.png" 
                           DeleteMsgCommand="{Binding DeleteMsgCommand}" 
                           EmojiItemSource="{Binding EmojiList}" 
                           EmojiTappedCommand="{Binding EmojiTappedCommand}" 
                           EntryTextColor="{Binding TextColor}" 
                           FrameColor="{Binding EntryBGColor}" 
                           InsertImgCommand="{Binding InsertImgCommand}" 
                           InsertImgIcon="insertimage.png" 
                           LeftSideIcon="icon.png" 
                           Placeholder="Escribddame" 
                           RightSideIcon="send.png" 
                           SendBtnColor="{Binding SendBtnColor}" 
                           SendMsgCommand="{Binding SendMsgCommand}" />
    </Grid>
</ContentPage>

Key Changes Explained

  • CustomControl: Removed the full-screen AbsoluteLayout bounds, switched to AutoSize so the control only takes the height of its content. Updated animation to use fixed heights instead of proportional values for more predictable behavior.
  • MainPage: Replaced AbsoluteLayout with a Grid, which is ideal for splitting the screen into a scrollable upper section and a fixed bottom control. The Grid's second row uses Auto height to fit the CustomControl exactly.

This setup ensures your CustomControl doesn't take up the entire screen, allowing you to add a ScrollView and other elements above it while keeping the emoji panel animation intact.

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.09 20:33:11