我在视图中使用多个按钮,每个按钮都会打开自己的弹出页面。当同时点击多个按钮时,它们会同时打开不同的弹出页面。
我创建了一个示例内容页面,其中包含3个按钮(每个按钮都会打开不同的弹出页面),以演示此问题:
XAML页面:
<ContentPage.Content>
<AbsoluteLayout>
<!-- button 1 -->
<Button x:Name="button1" Text="Button 1"
BackgroundColor="White" Clicked="Button1Clicked"
AbsoluteLayout.LayoutFlags="All"
AbsoluteLayout.LayoutBounds="0.5, 0.3, 0.5, 0.1"/>
<!-- button 2 -->
<Button x:Name="button2" Text="Button 2"
BackgroundColor="White" Clicked="Button2Clicked"
AbsoluteLayout.LayoutFlags="All"
AbsoluteLayout.LayoutBounds="0.5, 0.5, 0.5, 0.1"/>
<!-- button 3 -->
<Button x:Name="button3" Text="Button 3"
BackgroundColor="White" Clicked="Button3Clicked"
AbsoluteLayout.LayoutFlags="All"
AbsoluteLayout.LayoutBounds="0.5, 0.7, 0.5, 0.1"/>
<!-- popup page 1 -->
<AbsoluteLayout x:Name="page1" BackgroundColor="#7f000000" IsVisible="false"
AbsoluteLayout.LayoutFlags="All"
AbsoluteLayout.LayoutBounds="0.5, 0.5, 1.0, 1.0">
<BoxView Color="Red"
AbsoluteLayout.LayoutFlags="All"
AbsoluteLayout.LayoutBounds="0.5, 0.5, 0.75, 0.3"/>
<Label Text="Button 1 clicked" TextColor="White"
HorizontalTextAlignment="Center"
AbsoluteLayout.LayoutFlags="All"
AbsoluteLayout.LayoutBounds="0.5, 0.45, 0.75, 0.05"/>
<Button Text="Back" BackgroundColor="White" Clicked="Back1Clicked"
AbsoluteLayout.LayoutFlags="All"
AbsoluteLayout.LayoutBounds="0.5, 0.6, 0.5, 0.1"/>
</AbsoluteLayout>
<!-- popup page 2 -->
<AbsoluteLayout x:Name="page2" BackgroundColor="#7f000000" IsVisible="false"
AbsoluteLayout.LayoutFlags="All"
AbsoluteLayout.LayoutBounds="0.5, 0.5, 1.0, 1.0">
<BoxView Color="Green"
AbsoluteLayout.LayoutFlags="All"
AbsoluteLayout.LayoutBounds="0.5, 0.5, 0.75, 0.3"/>
<Label Text="Button 2 clicked" TextColor="White"
HorizontalTextAlignment="Center"
AbsoluteLayout.LayoutFlags="All"
AbsoluteLayout.LayoutBounds="0.5, 0.45, 0.75, 0.05"/>
<Button Text="Back" BackgroundColor="White" Clicked="Back2Clicked"
AbsoluteLayout.LayoutFlags="All"
AbsoluteLayout.LayoutBounds="0.5, 0.6, 0.5, 0.1"/>
</AbsoluteLayout>
<!-- popup page 3 -->
<AbsoluteLayout x:Name="page3" BackgroundColor="#7f000000" IsVisible="false"
AbsoluteLayout.LayoutFlags="All"
AbsoluteLayout.LayoutBounds="0.5, 0.5, 1.0, 1.0">
<BoxView Color="Blue"
AbsoluteLayout.LayoutFlags="All"
AbsoluteLayout.LayoutBounds="0.5, 0.5, 0.75, 0.3"/>
<Label Text="Button 3 clicked" TextColor="White"
HorizontalTextAlignment="Center"
AbsoluteLayout.LayoutFlags="All"
AbsoluteLayout.LayoutBounds="0.5, 0.45, 0.75, 0.05"/>
<Button Text="Back" BackgroundColor="White" Clicked="Back3Clicked"
AbsoluteLayout.LayoutFlags="All"
AbsoluteLayout.LayoutBounds="0.5, 0.6, 0.5, 0.1"/>
</AbsoluteLayout>
</AbsoluteLayout>
</ContentPage.Content>
C#事件处理程序:
void Button1Clicked(object sender, EventArgs e)
{
// ... do something first ...
page1.IsVisible = true;
Console.WriteLine("Button 1 Clicked!");
}
void Button2Clicked(object sender, EventArgs e)
{
// ... do something first ...
page2.IsVisible = true;
Console.WriteLine("Button 2 Clicked!");
}
void Button3Clicked(object sender, EventArgs e)
{
// ... do something first ...
page3.IsVisible = true;
Console.WriteLine("Button 3 Clicked!");
}
void Back1Clicked(object sender, EventArgs e)
{
page1.IsVisible = false;
}
void Back2Clicked(object sender, EventArgs e)
{
page2.IsVisible = false;
}
void Back3Clicked(object sender, EventArgs e)
{
page3.IsVisible = false;
}
预期:
点击 button1
将打开 page1
弹出页面,点击弹出窗口中的返回按钮将隐藏弹出页面。button2
和 button3
也有类似的行为。
实际:
同时点击多个按钮(例如button1
和button2
)会打开两个弹出页面(page1
和page2
)。 快速双击单个按钮也会触发同一个按钮两次。
避免双击的一些研究
通过在stackoverflow上搜索类似的问题(例如这个和这个),我得出了一个结论:应该设置一个外部变量来控制事件是否执行。 这是我的Xamarin.forms中的实现:
使用C# struct作为外部变量,以便我可以在不同的类中访问此变量:
// struct to avoid multiple button click at the same time
public struct S
{
// control whether the button events are executed
public static bool AllowTap = true;
// wait for 200ms after allowing another button event to be executed
public static async void ResumeTap() {
await Task.Delay(200);
AllowTap = true;
}
}
然后每个按钮事件处理程序都像这样进行修改(Button2Clicked()
和Button3Clicked()
同样适用):
void Button1Clicked(object sender, EventArgs e)
{
// if some buttons are clicked recently, stop executing the method
if (!S.AllowTap) return; S.AllowTap = false; //##### * NEW * #####//
// ... do something first ...
page1.IsVisible = true;
Console.WriteLine("Button 1 Clicked!");
// allow other button's event to be fired after the wait specified in struct S
S.ResumeTap(); //##### * NEW * #####//
}
这个功能基本上相当不错。双击同一个按钮会快速触发一次按钮事件,同时点击多个按钮也只会打开1个弹出页面。
真正的问题
就像上面所描述的那样,在修改代码(在struct S
中添加共享状态变量AllowTap
)后,仍然有可能打开多个弹出页面。例如,如果用户用两个手指按住button1
和button2
,释放button1
,等待大约一秒钟,然后释放button2
,那么page1
和page2
都会被打开。
解决问题的失败尝试
我曾试图在单击button1
、button2
或button3
时禁用所有按钮,并在单击返回按钮时启用所有按钮。
void disableAllButtons()
{
button1.IsEnabled = false;
button2.IsEnabled = false;
button3.IsEnabled = false;
}
void enableAllButtons()
{
button1.IsEnabled = true;
button2.IsEnabled = true;
button3.IsEnabled = true;
}
然后每个按钮事件处理程序都像这样进行修改(对Button2Clicked()
和Button3Clicked()
同样适用):
void Button1Clicked(object sender, EventArgs e)
{
if (!S.AllowTap) return; S.AllowTap = false;
// ... do something first ...
disableAllButtons(); //##### * NEW * #####//
page1.IsVisible = true;
Console.WriteLine("Button 1 Clicked!");
S.ResumeTap();
}
并且每个后退按钮事件处理程序都像这样进行修改(Back2Clicked()
和 Back3Clicked()
同样适用):
void Back1Clicked(object sender, EventArgs e)
{
page1.IsVisible = false;
enableAllButtons(); //##### * NEW * #####//
}
然而,相同的问题仍然存在(能够按住另一个按钮并稍后释放它们以同时触发2个按钮)。
在我的应用程序中禁用多点触控不是选项,因为我需要在应用程序的其他页面中使用它。此外,弹出页面可能还包含多个按钮,这些按钮也会导致其他页面,因此无法仅在弹出页面中使用返回按钮来设置
结构体S
中的变量AllowTap
。任何帮助将不胜感激。谢谢。 编辑
"真正的问题"影响安卓和iOS. 在安卓设备上,当用户按住按钮时,一旦按钮被禁用就不能再次激活该按钮。但这个"按住已禁用的按钮"的问题不会影响到iOS设备上的按钮。