Я использую несколько кнопок в представлении, и каждая кнопка приводит к ее собственной всплывающей странице. При одновременном нажатии нескольких кнопок он переходит на разные всплывающие окна за раз.
Я создал образец страницы контента с тремя кнопками (каждый из них идет на другую всплывающую страницу), чтобы продемонстрировать эту проблему:
Страница 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>
Обработчики событий С#:
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
всплывающее окно страницы и нажав кнопку назад в всплывающем окне скрывает раскрывающие страницы. Аналогично button3
button2
и button3
.
Актуально:
При нажатии нескольких кнопок (например. button1
и button2
) в то же время открывает как всплывающие страницы (page1
и page2
). Двойной щелчок одной кнопкой быстро может также запустить ту же кнопку дважды.
Некоторые исследования по избежанию двойного щелчка
При поиске похожих вопросов в stackoverflow (например, это и это) я пришел к выводу, что вы должны установить внешнюю переменную для управления тем, выполняются ли события или нет. Это моя реализация в Xamarin.forms:
С# 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 event to be fired after the wait specified in struct S
S.ResumeTap(); //##### * NEW * #####//
}
Это работает в целом довольно хорошо. Двойное нажатие одной и той же кнопки быстро запускает событие кнопки только один раз, и одновременное нажатие нескольких кнопок открывает только одну всплывающую страницу.
Реальная проблема
По-прежнему можно открыть более 1 всплывающих страниц после изменения кода (добавление общей переменной состояния AllowTap
в struct S
), как описано выше. Например, если пользователь, удерживая button1
и button2
с помощью 2 пальца, релиз 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 * #####//
}
Тем не менее, эта же проблема все еще сохраняется (возможность удерживать еще одну кнопку и отпускать ее позже, чтобы одновременно запустить две кнопки).
Отключение multi-touch в моем приложении не будет вариантом, так как мне это нужно на других страницах моего приложения. Кроме того, всплывающие страницы могут также содержать несколько кнопок, что также приводит к другим страницам, поэтому просто использовать кнопку "Назад" на всплывающей странице для установки переменной AllowTap
в struct S
также не будет.
Любая помощь будет оценена. Благодарю.
РЕДАКТИРОВАТЬ
"Реальная проблема" влияет как на Android, так и на iOS. На Android кнопка не может быть активирована, как только кнопка будет отключена некоторое время, когда пользователь удерживает кнопку. Эта проблема с нажатием кнопки-выключенной кнопки не влияет на кнопки в iOS.