解決出来ないってグダグダ書いてしまったけど、解決方法がわかった
解決方法はこちら
本当はPANで実現しようと思ったのだけど、リリースした場所を自分で計算しないといけないようなので面倒なのでドラッグ&ドロップでごまかそうという話
実は俺がわかってないだけかもしれないけど
この人の動画にはずいぶん助けられた
もはや、アプリのコーディングは英語圏のページや動画を頼らないと無理なんだな
ほら、よくあるじゃ無い、スマホである項目を別の項目に移動して入れ替えるというやつ
あれをやりたいのよ。
本当はD&DじゃなくてPANで実現するのが正しそうなのだけどね・・・
↑こんな感じのでお試しプログラムを作ってみた
要は、上の画像のイメージ画像をHello,World!のところに移動して、
上に乗っかられてしまったHello,World!をイメージ画像のところに追い出すというのを繰り返す
Visual Studioで.NET MAUIのプロジェクトをいつものように作ったら
まずはxamlの書換
- Borderを削除
- StackLayoutをグリッドに変更
- Gridの設定をする(ColumnDefinitions,RowDefinition,x:Name)
- 各コントロールにGridの位置を設定
- イメージコントロールとラベルに名称(x:Name)
- イメージコントロールにジェスチャー登録(Image.GestureRecognizers)
- イメージコントロールのジェスチャーにドラック開始イベント(DragGestureRecognizer)
- ドロップを受け入れるラベルにジェスチャー登録(Label.GestureRecognizers)
- ラベルにドロップイベント(DropGestureRecognizer)
- 後は・・・まあ適当に
<!-- StackLayoutをグリッドに変更 -->
<Grid x:Name="maingrid" >
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="*" />
<RowDefinition Height="*" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<!-- imageにNameとClassIdを追加 grid位置も適当に決める -->
<Image Grid.Column="3" Grid.Row="0" x:Name="bot" ClassId="bot"
Source="dotnet_bot.png"
SemanticProperties.Description="Cute dot net bot waving hi to you!"
HeightRequest="200"
HorizontalOptions="Center" >
<Image.GestureRecognizers>
<DragGestureRecognizer DragStarting="DragGestureRecognizer_DragStarting"/>
</Image.GestureRecognizers>
</Image>
<!-- LebelにNameとClassIdを追加 grid位置も適当に決める -->
<Label Grid.Column="2" Grid.Row="1" x:Name="lbl1" ClassId="lbl1"
Text="Hello, World!"
SemanticProperties.HeadingLevel="Level1"
FontSize="32"
HorizontalOptions="Center" >
<Label.GestureRecognizers>
<DropGestureRecognizer Drop="DropGestureRecognizer_Drop" />
</Label.GestureRecognizers>
</Label>
<Label Grid.Column="1" Grid.Row="2"
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" >
</Label>
<Button Grid.Column="0" Grid.Row="3"
x:Name="CounterBtn"
Text="Click me"
SemanticProperties.Hint="Counts the number of times you click"
Clicked="OnCounterClicked"
HorizontalOptions="Center" >
</Button>
</Grid>
CSのソースがこちら
元のテンプレートに色々追加
- ラベルの書き戻し用変数(string _strOrg)
- ラベルを書き戻すためのタイマー(Timer _tim using Timer = System.Timers.Timer;も必要 )
- コンストラクタの中にタイマーの各種設定
- changeTextメソッド(強制的に書き換えられたテキストを書き戻す)
- タイマー発動イベント(_tim_Elapsed)
- DragGestureRecognizer_DragStartingにコピー元データ(今回は捨てる)
- DropGestureRecognizer_Dropに、移動などのコードを記述
メインはDropGestureRecognizer_Dropなのだけど、アニメの移動やなんかを実行してます
・・・・が、困っちゃうのがLabelのTextを何が何でも書き換えようとするのよね
なので、しょうがないので今回は一時的に待避してタイマーで書き戻すなんとことをやってるのよね
本当はPanGestureRecognizerを使うべき何だろうけど、リリースした場所のコントロールの判定を位置情報を自分で計算せねばならないのだよな
もしかしたら、俺が知らないだけで、PanGestureRecognizerを使った方法があるのかもしれないけど
スマートじゃ無いなぁ・・・・
誰か本当の方法を教えてください
まあデータのコピーしたいだけなら、D&Dでさらっとコピーできるので悩まないでいいのだけどコントロールの移動の本当の方法はどうやるのでしょう
まあ、そんなわけでMAUI盤のえるいーだーはこんなトリッキーな方法でこの操作を実現するかも
public partial class MainPage : ContentPage
{
/// <summary>サンプルに最初からあるカウンタ</summary>
int count = 0;
/// <summary>元のラベルの文字を一時保存する</summary>
string _strOrg;
/// <summary>タイマー</summary>
Timer _tim;
/// <summary>
/// コンストラクタ
/// </summary>
public MainPage()
{
//タイマーの設定をする
_tim = new Timer();
_tim.Interval = 10;
_tim.Elapsed += _tim_Elapsed;
_tim.AutoReset = false; //タイマーはstart後に1回だけ発動
InitializeComponent();
}
/// <summary>
/// ラベルを書き戻すためにタイマーから呼ばれる
/// </summary>
private void changeText()
{
lbl1.Text = _strOrg; //ラベルの書き戻し
lbl1.IsEnabled = true;
}
/// <summary>
/// タイマー発動
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void _tim_Elapsed(object sender, ElapsedEventArgs e)
{
//WPF上のスレッドに changeTextメソッドの操作を委任
MainThread.BeginInvokeOnMainThread(changeText);
}
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);
}
/// <summary>
/// イメージコントロールのドラッグスタート
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void DragGestureRecognizer_DragStarting(object sender, DragStartingEventArgs e)
{
e.Data.Text = "開始"; //本来はコピー先に送りたいデータを書く
Debug.WriteLine("ドラッグスタート");
}
/// <summary>
/// イメージコントロールのドロップ
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private async void DropGestureRecognizer_Drop(object sender, DropEventArgs e)
{
_strOrg = lbl1.Text; //ラベルの文字を一旦保存
double x = bot.X - lbl1.X; //イメージコントロールの移動量
double y = bot.Y - lbl1.Y;
await lbl1.TranslateTo(x, y, 100); //ラベルをイメージのあった位置にゆっくり移動
await bot.TranslateTo(-x, -y, 100); //イメージコントロールをラベルの会った位置にゆっくりいどう
string text = await e.Data.GetTextAsync(); //ドラッグ元から持ってきたデータ、いらないのだけどドロップすると無理やりラベルにコピーされる
//今回はあっても無くても一緒
//イメージコントロールの元々あったGrid上の位置
int botx = maingrid.GetColumn(bot);
int boty = maingrid.GetRow(bot);
//ラベルコントロールの元々あったGrid上の位置
int lblx = maingrid.GetColumn(lbl1);
int lbly = maingrid.GetRow(lbl1);
//Grid上の位置を書換(イメージコントロール)
maingrid.SetColumn(bot, lblx);
maingrid.SetRow(bot, lbly);
bot.TranslationX = 0; //移動量は0に戻しておく
bot.TranslationY=0;
//Grid上の位置を書換(ラベルコントロール)
maingrid.SetColumn(lbl1, botx);
maingrid.SetRow(lbl1, boty);
lbl1.TranslationX= 0; //移動量は0に戻しておく
lbl1.TranslationY= 0;
//lbl1.Text = "移動中";
lbl1.IsEnabled= false;
Debug.WriteLine("イメージのドロップ");
//タイマー開始(ラベル上に勝手に書き戻された文字列をタイマーから書き戻す)
_tim.Start();
}
}
コメント
コメントを投稿