忍者ブログ
  • 2024.10
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 2024.12
[PR]
×

[PR]上記の広告は3ヶ月以上新規記事投稿のないブログに表示されています。新しい記事を書く事で広告が消えます。

【2024/11/23 01:52 】 |
Androidで、コード上でビューを座標指定して表示させる方法
Androidで、ビューをpx指定で表示したいことがある。

当たり前のやり方のような気がするが、意外と方法が用意されていない。
iOSなら、view.frameやview.boundsで矩形を指定することができるのだが、Androidはそれがない。


Androidは、ビューに加えて、レイアウト(FrameLayout,LinearLayout,RelativeLayoutなど)という概念がある。
(正確にはレイアウトもビューなのだが。)
ビューはレイアウトの中に配置される。

そのビューを、レイアウトから上下左右のマージンいくつ離すか、という指定をすることになる。

本来これでいいはずなのだが、
実際にビューを配置してみると、狙った位置と大きさも位置もずれていることがある。


なぜか。

マージンを指定することによって、矩形の大きさが決まる。
例えば、幅640,高さ240のLayoutの中に、左右マージン各20,上下マージン各10を取ると、
ビューのRect(x,y,w,h)=(20,10,600,220)になる。

しかし、ビューが実際に正確にその大きさで配置されるとは限らない。

たとえば、ビューの幅、高さの指定がWRAP_CONTENTだと、矩形のサイズはあまり関係なくビューの「見た目の大きさ」は決まってしまう。

また、MATCH_PARENTだとしても、
たとえばImageViewなら、元画像の縦横比を崩さない範囲で最大サイズ表示、のようなことになるからだ。
また、広告SDKで表示するアイコンなど、実際の表示サイズが不定になるものの場合もある。

そのようなとき、ビューは大抵左上寄せの位置に表示される。

これは嫌だ。指定座標を中心とする位置に収まってほしい。


じゃあ、gravityをCENTERに指定すれば…?
としたいが、gravity指定はビューにはできず、Layoutに指定する。
gravityは、そのレイアウト全体の重力場を指定するためのものだからだ。

ビューを中央寄せにする指定をビュー自体に対してできないか…となる。
もちろんその指定はあって、xmlでいうと
centerHorizontal
などの指定がそれにあたる。これは、
「自分の親のレイアウトの左右方向中心に配置」
ということだ。

……ということは、自分の親のレイアウトが必要になる。
何も考えずそのままcenterHorizontal,centerVerticalを指定したら、大本のレイアウト(おそらく画面全体を覆うRelativeLayoutになっているだろう)の中心に行ってしまう。それはスクリーンの中心だ。
そうじゃない。

さっき指定した矩形の中心にいてほしいのだ!


…………ということは、さっきの指定の矩形のレイアウトを作成すればいいんだ。


大本のRelativeLayout
+-- 矩形Layout
+-- ビュー(中央寄せで配置)




という二重構造にすればよい。




private void addChildView(View parent, View view, Rect rect) {
int x = rect.left;
int y = rect.top;
int width = rect.right - rect.left;
int height = rect.bottom - rect.top;

// 中間レイアウトを作成。正確にrectの範囲を覆うRelativeLayout。
RelativeLayout positioner = new RelativeLayout(getApplicationContext());

// 中間レイアウトのレイアウトパラメータ
RelativeLayout.LayoutParams lp1 = new RelativeLayout.LayoutParams(width, height);
lp1.leftMargin = x;
lp1.topMargin = y;

// 中間レイアウトを親ビューの子にする
parent.addView(positioner, lp1);

// 目的のビューのレイアウトパラメータを作成。今作った中間ビューの中心に配置
RelativeLayout.LayoutParams lp2 = new RelativeLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
lp2.addRule(RelativeLayout.CENTER_VERTICAL);
lp2.addRule(RelativeLayout.CENTER_HORIZONTAL);

// 目的のビューを中間レイアウトの子にする
positioner.addView(view, lp2);
}






こういう感じになる。

中間レイアウトはRelativeLayoutでなければダメで、他のレイアウトだとマージン指定が効かない。
FrameLayoutやLinearLayoutにすると表示位置が左上固定になってしまう。

RelativeLayoutなので、レイアウトパラメータもRelativeLayout.LayoutParamsにする。



ビューのレイアウトパラメータもRelativeLayout.LayoutParamsにする。
でないとaddRule()メソッドが使えない。(だからCENTER_HORIZONTAL/VERTICAL指定ができない)

FrameLayoutには
lp2.gravity = Gravity.CENTER;
のような指定もできるが、これは自分の子孫に対して効かせるパラメータなので、ビュー自身を中央寄せしたい場合は意味が無い。




というわけで、
=================================
中間レイアウトはRelativeLayout
中間レイアウトのパラメータはRelativeLayout.LayoutParams
ビューのパラメータもRelativeLayout.LayoutParams
=================================
となる。



ちなみにレイアウトパラメータ類の子孫関係は以下

ViewGroup.LayoutParams
+-- ViewGroup.MarginLayoutParams
+-- FrameLayout.LayoutParams
+-- RelativeLayout.LayoutParams
+-- LinearLayout.LayoutParams



どのレイアウトパラメータも、コンストラクタの基本はwidthとheightの指定(int)である。
lp1のように、幅と高さを直に設定することもできるが、
多くの場合はlp2のように MATCH_PARENT(-1) か WRAP_CONTENT(-2) という特殊な値を入れて使うことになる。

PR
【2015/05/25 20:25 】 | Android | 有り難いご意見(0)
<<リジェクト理由:ゲーム内容と異なるアイコン | ホーム | Androidでローカル通知>>
有り難いご意見
貴重なご意見の投稿














<<前ページ | ホーム | 次ページ>>