bringToFront not working!!
もともと、以下のような階層で描かれているxmlがあって、
bringToFrontを使って、root直下のFrameLayoutのviewをトップに出していました。(FrameLayoutを一番下に置いてもいいです。)
before.xml
root: RelativeLayout
-FrameLayout
-LinearLayout
- ImageButton
- EditText
- ImageButton
- RecyclerView
それを以下の様にする必要がありましたが、なぜがbringToFrontが効かなくなりました。
after.xml
root: RelativeLayout
-FrameLayout
-LinearLayout
- ImageButton
- EditText
- ImageButton
- CardView
- RecyclerView
詳細
間違いなくCardViewが悪いのは予測がつくわけですが、bringToFrontのメソッドを覗きにいくと、
View.java
public void bringToFront() {
if (mParent != null) {
mParent.bringChildToFront(this);
}
}
親Viewがいれば、親Viewが所持する子Viewを一番前に持ってくるようです。
そこでViewParent(mParentのオブジェクト)の中身を見ると、
ViewParent.java
/**
* this method should be followed by calls to
* {@link#requestLayout()} and {@link View#invalidate()}
* on this parent to force the parent to redraw with the new child ordering.
* /
だそうです。
つまり、bringToFrontを使った際には、親Viewが子Viewの順番を考慮して、再描画する必要があるので、requestLayout() と invalidate()を利用しろということでした。
ところが、これをやってもL以上ではダメでした。
bringToFrontにしてroot直下の階層で一番前面に出してもロリポップ以上では、エレベーションを考慮する必要があります。
今回の場合利用している、root直下のCardViewのエレベーションを2dpつけていたのですが、root直下のFrameLayoutのプロパティでandroid:elevation="2dp"
を追加してあげると直りました。(2dp以上ならOK)
結論
- bringToFront -> requestLayout && invalidate()の順番で呼ぶ。
- ロリポップ以上はエレベーションに気をつけて、必要ならばelevationをつける。(Material Designに沿って)
以上です。