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

Xamarin Forms:实现可打开下拉菜单的独立按钮技术求助

嘿,当然可以实现!在Xamarin Forms里做这种点击弹出下拉菜单的按钮,我给你分享两种实用方案,都能完美适配无导航栏的页面场景:

方案1:用Xamarin Community Toolkit的Popup快速实现

这个工具包封装了很多常用UI组件,用它做下拉菜单特别省心。首先先安装NuGet包 Xamarin.CommunityToolkit,然后直接写代码就行:

页面XAML代码

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:xct="http://xamarin.com/schemas/2020/toolkit"
             x:Class="YourAppNamespace.YourPage"
             NavigationPage.HasNavigationBar="False"> <!-- 开启无导航栏模式 -->

    <StackLayout Padding="20" VerticalOptions="Center">
        <!-- 触发下拉菜单的按钮 -->
        <Button x:Name="MenuButton" Text="菜单" Clicked="MenuButton_Clicked"
                HorizontalOptions="Start" />

        <!-- 下拉菜单弹窗 -->
        <xct:Popup x:Name="MenuPopup"
                   Size="200, 150"
                   HorizontalOptions="Start"
                   VerticalOptions="Start"
                   Margin="0, 5, 0, 0"> <!-- 让菜单紧贴按钮下方 -->
            <StackLayout BackgroundColor="White"
                         Padding="5"
                         CornerRadius="8"
                         ShadowColor="Gray"
                         ShadowOpacity="0.5"
                         ShadowRadius="4">
                <Label Text="选项1" Padding="10" FontSize="16">
                    <Label.GestureRecognizers>
                        <TapGestureRecognizer Tapped="Option1_Tapped" />
                    </Label.GestureRecognizers>
                </Label>
                <BoxView HeightRequest="1" BackgroundColor="#EEEEEE" />
                <Label Text="选项2" Padding="10" FontSize="16">
                    <Label.GestureRecognizers>
                        <TapGestureRecognizer Tapped="Option2_Tapped" />
                    </Label.GestureRecognizers>
                </Label>
                <BoxView HeightRequest="1" BackgroundColor="#EEEEEE" />
                <Label Text="选项3" Padding="10" FontSize="16">
                    <Label.GestureRecognizers>
                        <TapGestureRecognizer Tapped="Option3_Tapped" />
                    </Label.GestureRecognizers>
                </Label>
            </StackLayout>
        </xct:Popup>
    </StackLayout>
</ContentPage>

后台C#代码

using Xamarin.CommunityToolkit.UI.Views;

namespace YourAppNamespace
{
    public partial class YourPage : ContentPage
    {
        public YourPage()
        {
            InitializeComponent();
        }

        private async void MenuButton_Clicked(object sender, EventArgs e)
        {
            // 计算菜单位置,确保刚好在按钮下方
            var buttonBounds = MenuButton.Bounds;
            MenuPopup.Margin = new Thickness(buttonBounds.Left, buttonBounds.Top + buttonBounds.Height + 5, 0, 0);
            await MenuPopup.ShowAsync();
        }

        private async void Option1_Tapped(object sender, EventArgs e)
        {
            await DisplayAlert("提示", "你选择了选项1", "确定");
            await MenuPopup.DismissAsync(); // 选择后关闭菜单
        }

        private async void Option2_Tapped(object sender, EventArgs e)
        {
            await DisplayAlert("提示", "你选择了选项2", "确定");
            await MenuPopup.DismissAsync();
        }

        private async void Option3_Tapped(object sender, EventArgs e)
        {
            await DisplayAlert("提示", "你选择了选项3", "确定");
            await MenuPopup.DismissAsync();
        }
    }
}
方案2:纯原生自定义下拉菜单(无需额外依赖)

如果不想引入第三方包,自己写个自定义菜单也很简单,还能自由控制动画效果:

页面XAML代码

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="YourAppNamespace.YourPage"
             NavigationPage.HasNavigationBar="False">

    <RelativeLayout Padding="20">
        <!-- 触发按钮 -->
        <Button x:Name="MenuButton" Text="菜单"
                RelativeLayout.XConstraint="{ConstraintExpression Type=Constant, Constant=0}"
                RelativeLayout.YConstraint="{ConstraintExpression Type=Constant, Constant=20}" 
                Clicked="MenuButton_Clicked"/>

        <!-- 自定义下拉菜单容器 -->
        <ContentView x:Name="DropDownMenu"
                     IsVisible="False"
                     BackgroundColor="White"
                     CornerRadius="8"
                     ShadowColor="Gray"
                     ShadowOpacity="0.5"
                     ShadowRadius="4"
                     RelativeLayout.XConstraint="{ConstraintExpression Type=Constant, Constant=0}"
                     RelativeLayout.YConstraint="{ConstraintExpression Type=Constant, Constant=70}"
                     WidthRequest="200">
            <StackLayout Padding="5">
                <Label Text="选项A" Padding="10" FontSize="16">
                    <Label.GestureRecognizers>
                        <TapGestureRecognizer Tapped="OptionA_Tapped" />
                    </Label.GestureRecognizers>
                </Label>
                <BoxView HeightRequest="1" BackgroundColor="#EEEEEE" />
                <Label Text="选项B" Padding="10" FontSize="16">
                    <Label.GestureRecognizers>
                        <TapGestureRecognizer Tapped="OptionB_Tapped" />
                    </Label.GestureRecognizers>
                </Label>
            </StackLayout>
        </ContentView>
    </RelativeLayout>
</ContentPage>

后台C#代码(带动画效果)

namespace YourAppNamespace
{
    public partial class YourPage : ContentPage
    {
        public YourPage()
        {
            InitializeComponent();
            // 点击页面空白区域自动关闭菜单
            var tapOutside = new TapGestureRecognizer();
            tapOutside.Tapped += TapOutside_Tapped;
            this.GestureRecognizers.Add(tapOutside);
        }

        private async void MenuButton_Clicked(object sender, EventArgs e)
        {
            DropDownMenu.IsVisible = !DropDownMenu.IsVisible;
            if (DropDownMenu.IsVisible)
            {
                // 添加入场动画:从透明到显示,从小变大
                DropDownMenu.Opacity = 0;
                DropDownMenu.Scale = 0.8;
                await Task.WhenAll(
                    DropDownMenu.FadeTo(1, 200),
                    DropDownMenu.ScaleTo(1, 200, Easing.SinOut)
                );
            }
            else
            {
                // 退场动画:从显示到透明,从大变小
                await Task.WhenAll(
                    DropDownMenu.FadeTo(0, 200),
                    DropDownMenu.ScaleTo(0.8, 200, Easing.SinIn)
                );
            }
        }

        private async void OptionA_Tapped(object sender, EventArgs e)
        {
            await DisplayAlert("提示", "你选择了选项A", "确定");
            await CloseMenu();
        }

        private async void OptionB_Tapped(object sender, EventArgs e)
        {
            await DisplayAlert("提示", "你选择了选项B", "确定");
            await CloseMenu();
        }

        private async void TapOutside_Tapped(object sender, EventArgs e)
        {
            await CloseMenu();
        }

        // 封装关闭菜单的逻辑
        private async Task CloseMenu()
        {
            if (DropDownMenu.IsVisible)
            {
                await Task.WhenAll(
                    DropDownMenu.FadeTo(0, 200),
                    DropDownMenu.ScaleTo(0.8, 200, Easing.SinIn)
                );
                DropDownMenu.IsVisible = false;
            }
        }
    }
}

两种方案都能满足你的需求:第一种省事儿,适合快速开发;第二种更灵活,能自定义各种样式和动画,你可以根据项目情况选择~

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.21 06:55:16