質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.50%
XML

XMLは仕様の1つで、マークアップ言語群を構築するために使われています。

Java

Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

Android

Androidは、Google社が開発したスマートフォンやタブレットなど携帯端末向けのプラットフォームです。 カーネル・ミドルウェア・ユーザーインターフェイス・ウェブブラウザ・電話帳などのアプリケーションやソフトウェアをひとつにまとめて構成。 カーネル・ライブラリ・ランタイムはほとんどがC言語/C++、アプリケーションなどはJavaSEのサブセットとAndroid環境で書かれています。

Android Studio

Android Studioは、 Google社によって開発された、 Androidのネイティブアプリケーション開発に特化した統合開発ツールです。

Q&A

解決済

2回答

1934閲覧

XMLをいじらずに、JavaコードでViewの位置を指定したい

takusuke

総合スコア16

XML

XMLは仕様の1つで、マークアップ言語群を構築するために使われています。

Java

Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

Android

Androidは、Google社が開発したスマートフォンやタブレットなど携帯端末向けのプラットフォームです。 カーネル・ミドルウェア・ユーザーインターフェイス・ウェブブラウザ・電話帳などのアプリケーションやソフトウェアをひとつにまとめて構成。 カーネル・ライブラリ・ランタイムはほとんどがC言語/C++、アプリケーションなどはJavaSEのサブセットとAndroid環境で書かれています。

Android Studio

Android Studioは、 Google社によって開発された、 Androidのネイティブアプリケーション開発に特化した統合開発ツールです。

0グッド

0クリップ

投稿2020/01/24 16:38

<実装したいこと>
現在、Viewをxmlにて以下のように位置指定をしております。
図1

この「温度」とsetTextされているTextViewを長押しすると、任意の位置にドラッグし、位置を保存することができる機能を考えております。
具体的には、ドラッグ後にその座標をSharedPreferencesで保存し、画面が遷移した後、再びこの画面に戻ってきても、その座標を読み込み、その位置にViewを表示させるようにしたいです。

<困っていること>
XMLのデフォルトの位置が原因で、ドラッグ後の座標読み取りにズレが生じてしまいます。
具体的な説明を以下に記載します。
上記に記載のTextViewの変数は「TextView[0]」となっています。
ドラッグ時のコードを以下に記載します。

java

1textView[0].setOnTouchListener(new View.OnTouchListener() { 2 @Override 3 public boolean onTouch(View v, MotionEvent event) { 4 // x,y 位置取得 5 6 int newbuttonX = (int)event.getRawX(); 7 int newbuttonY = (int)event.getRawY(); 8 9 switch (event.getAction()) { 10 // タッチダウンでdragされた 11 case MotionEvent.ACTION_MOVE: 12 // ACTION_MOVEでの位置 13 x = (newbuttonX - buttonX); 14 y = (newbuttonY - buttonY); 15 16 dx = textView[0].getLeft() + x; 17 dy = textView[0].getTop() + y; 18 19 imgW = dx + textView[0].getWidth(); 20 imgH = dy + textView[0].getHeight(); 21 22 // Viewの位置を設定する 23 textView[0].layout(dx, dy, imgW, imgH); 24 25 break; 26 case MotionEvent.ACTION_DOWN: 27 break; 28 case MotionEvent.ACTION_UP: 29               // x座標の保存 30 editor = prefs.edit(); 31 editor.putFloat("oldx1",textView[0].getX()); 32 editor.apply(); 33 read_oldx[0] = prefs.getFloat("oldx1", 0); 34 35               // y座標の保存 36 editor = prefs.edit(); 37 editor.putFloat("oldy1", textView[0].getY()); 38 editor.apply(); 39 40 read_oldy[0] = prefs.getFloat("oldy1", 0); 41 // Logで確認 42               Log.d("onTouch","ACTION_MOVE:dx="+textView[0].getX()+"," +" dy="+textView[0].getY()); 43 break; 44 default: 45 break; 46 } 47 // タッチした位置を古い位置とする 48 buttonX = newbuttonX; 49 buttonY = newbuttonY; 50 51 return true; 52 } 53 });

これでドラッグ後の位置は保存できていると思います(Logで辿って確認済)。

問題はここからです。
これを再表示しているコードを以下に示します。

java

1textView[0].setX(read_oldx[0]); 2textView[0].setY(read_oldy[0]);

このようにコードを書くと、XMLでのデフォルトの位置とドラッグ後の座標の位置が足されて表示されてしまいます。具体的に図で説明します。

一番左上のTextView(TextView[0])をドラッグします。
イメージ説明

この位置にドラッグしました。
イメージ説明

画面遷移後、再びこの画面に戻ってくると以下のように表示されてしまいます。
イメージ説明

これは、XMLで設定したデフォルトの位置を(0,0)と認識し、そこから保存した座標取得を読み込んでいるため、ずれてしまうと私は考えています。。。

インターネットで色々と調べても、所属研究室の教授に相談しても解決しないため、最終手段として質問させて頂きます。
卒業がかかっているため、どうかよろしくお願いいたします、、、。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

dodox86

2020/01/24 17:01 編集

試せていないので危なそうなところの指摘のみですが、全体のスクリーン座標と、TextViewなどの配置位置を示す論理(相対的な)座標の扱いが ごっちゃになっていたりしませんか。例えば以下のgetRawX()は、リファレンスによるとスクリーン座標ぽいです。(Rawと言うくらいだし) int newbuttonX = (int)event.getRawX(); https://developer.android.com/reference/android/view/MotionEvent.html#getRawX() リファレンスを確認して再度見直してみてください。
takusuke

2020/01/25 08:10

ご指摘ありがとうございます。 あまりそのあたりは考えていませんでした汗 しっかり確認して勉強したいと思います。
guest

回答2

0

ベストアンサー

  • Viewの移動について

View#layout(left, top, right, bottom)は親ViewGroupのonLayout内で呼ぶことを想定したメソッドです。これを別の場所で呼び出すとLayoutParamsによる指定(layout_widthやlayout_marginなど)を無視して再レイアウトを行うことになり、好ましくありません。

layoutメソッドでViewを移動するのはやめて、setX/setYメソッドで移動するように変更してください。

java

1x = (newbuttonX - buttonX); 2y = (newbuttonY - buttonY); 3 4// Viewの位置を設定する 5textView[0].setX(x); 6textView[0].setY(y);
  • 位置がずれる原因について

setX/setYメソッドの中身を見ると分かりますが、このメソッドは現在のViewのleft/topをx/yから差し引いた値をtranslationX/translationYに設定します。Viewのレイアウトが完了する前にこのメソッドを呼び出してしまうと、その後Viewのレイアウトが行われる際にleft/topの値が変動するため、位置がずれてしまいます。

これを回避するためには、Viewのレイアウトが完了した後にsetX/setYを呼ぶようにしてください。

java

1// レイアウト完了時に呼ばれるListener 2textView[0].getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() { 3 public void onGlobalLayout() { 4 textView[0].getViewTreeObserver().removeOnGlobalLayoutListener(this); 5 6 textView[0].setX(read_oldx[0]); 7 textView[0].setY(read_oldy[0]); 8 } 9});

余談ですが、サポートライブラリのViewDragHelperを使うことでViewのドラッグ&ドロップはシンプルに実装できます。ご参考までに。

投稿2020/01/25 00:34

kakajika

総合スコア3131

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

takusuke

2020/01/25 08:05

ご回答ありがとうございます。 非常に分かりやすく、勉強になりました。 おかげさまで位置ずれがなくなりました。 本当に感謝です、、、。 ただ、初回起動時のみ「read_oldx[0]」を参照することができないため、デフォルトの'0'が代入されてしまい、Viewが左上に表示されてしまいます。 このデフォルト表示をXMLで設定した位置に設定したいのですが(汗) 大きな問題は解決できたため、解決済と致しましたがその点が少し気になります。。。
kakajika

2020/01/26 00:56

その辺りのコードを見ていないので推測になりますが、SharedPreferencesから読み込んだ値を使って位置設定を行っているのだとしたら、SharedPreferencesに値が保存されていない場合は処理を行わないようにしてみてはどうでしょう?
takusuke

2020/01/26 11:13

ご回答ありがとうございます。 その手がありましたね!完全にできました。 本当に助かりました。感謝してもしきれないです。
guest

0

textView[0].layout(dx, dy, imgW, imgH);

これで位置を指定して描画しているのですから, この dx,dy を一時保存(もしくは ACTION_UP 時も計算)して prefs に保存し, 再表示時の位置指定に layout メソッドを使用しては如何でしょうか.

java

1 int left = textView[0].getLeft() + (newbuttonX - buttonX); 2 int top = textView[0].getTop() + (newbuttonY - buttonY); 3 4 switch (event.getAction()) { 5 case MotionEvent.ACTION_MOVE: 6 //表示 7 int right = left + textView[0].getWidth(); 8 int bottom = top + textView[0].getHeight(); 9 textView[0].layout(left, top, right, bottom); 10 break; 11 case MotionEvent.ACTION_UP: 12 //保存 13 Editor editor = prefs.edit(); 14 editor.putFloat("oldx1", left); //なぜ float? 15 editor.putFloat("oldy1", top); 16 editor.apply(); 17 18 read_oldx[0] = prefs.getFloat("oldx1", 0); 19 read_oldy[0] = prefs.getFloat("oldy1", 0); 20 // Logで確認 21 Log.d("onTouch","ACTION_MOVE: dx="+left+"," +" dy="+top); 22 break; 23 }

java

1 int left = (int)prefs.getFloat("oldx1", 0); 2 int top = (int)prefs.getFloat("oldy1", 0); 3 int right = left + textView[0].getWidth(); 4 int bottom = top + textView[0].getHeight(); 5 textView[0].layout(left, top, right, bottom);

また, どちらも layout の代わりに setLeft / setTop を使っても良いのかもしれません.

投稿2020/01/24 18:30

編集2020/01/24 19:44
jimbe

総合スコア12543

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

kakajika

2020/01/25 00:13

layoutメソッドの挙動について調べてから回答された方が良いと思います。
jimbe

2020/01/25 03:14

失礼しました.
takusuke

2020/01/25 08:09

またもご回答ありがとうございます。 丁寧に教えて頂き感謝いたします。 おかげさまで色々と勉強になりました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.50%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問