Xamarin.Forms布局添加ScrollView及控件自适应尺寸问题求助
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
AutoSizeso 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
Autoheight 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

