前回の記事で、やりたい事が出来ねーよって諦めてたけど
やり方わかった
PanGestureRecognizerを使う・・・のだけど、AndroidとWindowsで違うコードが必要になるのはなぁ・・・・
xamlのソースがこれ↓
- PanGestureRecognizerをGridに追加(Windows用)
- PanGestureRecognizerをImageに追加(Android用)
- Gridは好きなように・・・
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="PanGestureTest.MainPage">
<Grid x:Name="baseGrid">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="*" />
<RowDefinition Height="*" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<!-- GridのPANはWindows専用(Androidではイベントが上がらない) -->
<Grid.GestureRecognizers>
<PanGestureRecognizer PanUpdated="PanGestureRecognizer_PanUpdated" />
</Grid.GestureRecognizers>
<Image x:Name="bot"
Source="dotnet_bot.png" Grid.Column="0" Grid.Row="0" ClassId="image1"
SemanticProperties.Description="Cute dot net bot waving hi to you!"
HeightRequest="200"
HorizontalOptions="Center" >
<!-- PANジェスチャー -->
<Image.GestureRecognizers>
<PanGestureRecognizer PanUpdated="OnPanImage" />
</Image.GestureRecognizers>
</Image>
<Label Grid.Column="1" Grid.Row="1" x:Name="label1"
Text="Hello, World!"
SemanticProperties.HeadingLevel="Level1"
FontSize="32"
HorizontalOptions="Center" >
<!-- PANジェスチャー -->
<Label.GestureRecognizers x:Uid="3">
<PanGestureRecognizer PanUpdated="OnPanLabel" />
</Label.GestureRecognizers>
</Label>
<Label Grid.Column="2" Grid.Row="2" ClassId="image2"
Text="Welcome to .NET Multi-platform App UI"
SemanticProperties.HeadingLevel="Level2"
SemanticProperties.Description="Welcome to dot net Multi platform App U I"
FontSize="18"
HorizontalOptions="Center" />
<Button Grid.Column="3" Grid.Row="3" ClassId="image3"
x:Name="CounterBtn"
Text="Click me"
SemanticProperties.Hint="Counts the number of times you click"
Clicked="OnCounterClicked"
HorizontalOptions="Center" />
</Grid>
</ContentPage>
C#のソースは↓
- changePosition アニメーション移動をした後にGridを入れ替えて固定
- OnPanImage ImageのPan動作(Android用)
- PanGestureRecognizer_PanUpdated GridのPan動作(Windows用)
ImageとGridのPan動作は似たような動作だけど 移動距離の計算が
Windows用は
bot.TranslationX = e.TotalX;
bot.TranslationY = e.TotalY;
Android用は
bot.TranslationX += e.TotalX;
bot.TranslationY += e.TotalY;
と言うように若干異なってます
そこはMAUIで吸収してほしかった
実装時は、ImageやGridのコードは関数化するかクラス化するけど、要素技術の調査だから汚いソースでいいのだ
using System.Diagnostics;
namespace PanGestureTest;
public partial class MainPage : ContentPage
{
int count = 0;
bool _IsImage = false;
/// <summary>
/// コンストラクタ
/// </summary>
public MainPage()
{
InitializeComponent();
}
/// <summary>
/// グリッド上の位置を入れ替え
/// </summary>
private void changePosition()
{
//イメージコントロールの元々あったGrid上の位置
int botColumn = baseGrid.GetColumn(bot);
int botRow = baseGrid.GetRow(bot);
//ラベルコントロールの元々あったGrid上の位置
int lblColumn = baseGrid.GetColumn(label1);
int lblRow = baseGrid.GetRow(label1);
//Grid上の位置を書換(イメージコントロール)
baseGrid.SetColumn(bot, lblColumn);
baseGrid.SetRow(bot, lblRow);
bot.TranslationX = 0; //移動量は0に戻しておく
bot.TranslationY = 0;
//Grid上の位置を書換(ラベルコントロール)
baseGrid.SetColumn(label1, botColumn);
baseGrid.SetRow(label1, botRow);
label1.TranslationX = 0; //移動量は0に戻しておく
label1.TranslationY = 0;
}
private void OnCounterClicked(object sender, EventArgs e)
{
count++;
if (count == 1)
CounterBtn.Text = $"Clicked {count} time";
else
CounterBtn.Text = $"Clicked {count} times";
SemanticScreenReader.Announce(CounterBtn.Text);
//元の場所に戻す
baseGrid.SetColumn(bot, 0);
baseGrid.SetRow(bot, 0);
bot.TranslationX = 0; //移動量は0に戻しておく
bot.TranslationY = 0;
baseGrid.SetColumn(label1, 1);
baseGrid.SetRow(label1, 1);
label1.TranslationX = 0; //移動量は0に戻しておく
label1.TranslationY = 0;
}
/// <summary>
/// イメージコントロールのPanGestureRecognizer(Android用)
/// </summary>
async private void OnPanImage(object sender, PanUpdatedEventArgs e)
{
Debug.WriteLine(e.StatusType.ToString());
Debug.WriteLine($"image={e.TotalX}");
_IsImage = true;//イメージでPanが発生した事の判定
if (DeviceInfo.Current.Platform == DevicePlatform.WinUI)
{
//Windowsで入ってきたら捨てる
return;
}
if (e.StatusType == GestureStatus.Completed)
{
//移動完了
//ここで、他のコントロールと場所を入れ替えたい
//1.どのコントロールの上にかぶったのか
//2.被さったコントロールがGrid上のcolmとrowのそれぞれ何処の位置にあるのか
//イメージの位置情報
var botPosX = bot.X;
var botPosY = bot.Y;
var botH = bot.Height;
var botW = bot.Width;
//文字ラベルの位置情報
var lblPosX = label1.X;
var lblPosY = label1.Y;
var lblH = label1.Height;
var lblW = label1.Width;
//イメージコントロールの終了処理
var botNewX = botPosX + bot.TranslationX;
var botNewY = botPosY + bot.TranslationY;
if ((botNewX > lblPosX - 30 && botNewX < (lblPosX + lblW))
&& (botNewY > lblPosY - 30 && botNewY < (lblPosY + lblH)))
{
//botがラベルの上にかぶったので、まずアニメ移動
await bot.TranslateTo(lblPosX - botPosX, lblPosY - botPosY, 50);
await label1.TranslateTo(-(lblPosX - botPosX), -(lblPosY - botPosY), 50);
await Task.Delay(50); //アニメ移動が終わるまで待機
changePosition(); //Grid上のポジションを入れ替える
}
else
{
//ラベルの上に居るので無ければ元の位置に戻す
await bot.TranslateTo(0, 0, 50);
}
}
else
{
if (DeviceInfo.Current.Platform == DevicePlatform.Android)
{
bot.TranslationX += e.TotalX;
bot.TranslationY += e.TotalY;
}
else
{
bot.TranslationX = e.TotalX;
bot.TranslationY = e.TotalY;
}
}
}
/// <summary>
/// ラベルコントロールのPanGestureRecognizer
/// </summary>
private void OnPanLabel(object sender, PanUpdatedEventArgs e)
{
_IsImage = false; // ラベルでPanが発生した事の判定
Debug.WriteLine($"label={e.TotalX}");
}
/// <summary>
/// Gridに貼り付けたPanGestureRecognizer(Windows用)
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
async private void PanGestureRecognizer_PanUpdated(object sender, PanUpdatedEventArgs e)
{
if (DeviceInfo.Current.Platform == DevicePlatform.Android)
{
//Androidで入ってきたら捨てる
return;
}
if (e.StatusType == GestureStatus.Completed)
{
//移動完了
//ここで、他のコントロールと場所を入れ替えたい
//1.どのコントロールの上にかぶったのか
//2.被さったコントロールがGrid上のcolmとrowのそれぞれ何処の位置にあるのか
//イメージの位置情報
var botPosX = bot.X;
var botPosY = bot.Y;
var botH = bot.Height;
var botW = bot.Width;
//文字ラベルの位置情報
var lblPosX = label1.X;
var lblPosY = label1.Y;
var lblH = label1.Height;
var lblW = label1.Width;
//イメージコントロールの終了処理
var botNewX = botPosX + bot.TranslationX;
var botNewY = botPosY + bot.TranslationY;
if ((botNewX > lblPosX - 30 && botNewX < (lblPosX + lblW))
&& (botNewY > lblPosY - 30 && botNewY < (lblPosY + lblH)))
{
//botがラベルの上にかぶったので、まずアニメ移動
await bot.TranslateTo(lblPosX - botPosX, lblPosY - botPosY, 50);
await label1.TranslateTo(-(lblPosX - botPosX), -(lblPosY - botPosY), 50);
await Task.Delay(50);
changePosition();
}
else
{
//ラベルの上に居るので無ければ元の位置に戻す
await bot.TranslateTo(0, 0, 50);
}
}
else
{
bot.TranslationX = e.TotalX;
bot.TranslationY = e.TotalY;
}
}
}
英語版のstack overflow検索してたら、やっぱり悩んでいる人もいて解決策が出ていた
まさか、こんな力任せな解決方法だとは・・・
ちょっと補足 、位置判定のところのif文に突如30なんて数字が出てきてるけど、使い勝手の調整用
本番ではどうすっかね
if ((botNewX > lblPosX - 30 && botNewX < (lblPosX + lblW))
&& (botNewY > lblPosY - 30 && botNewY < (lblPosY + lblH)))
ここまで来たら後はBLEが動くかの確認だけだぜ
コメント
コメントを投稿