この属性は Window に関するもので、Window では以下のフィールドとメソッドが関連します。
Window
public abstract class Window {
...
private boolean mCloseOnTouchOutside = false;
private boolean mSetCloseOnTouchOutside = false;
...
/** @hide */
public void setCloseOnTouchOutside(boolean close) {
mCloseOnTouchOutside = close;
mSetCloseOnTouchOutside = true;
}
/** @hide */
public void setCloseOnTouchOutsideIfNotSet(boolean close) {
if (!mSetCloseOnTouchOutside) {
mCloseOnTouchOutside = close;
mSetCloseOnTouchOutside = true;
}
}
...
/** @hide */
public boolean shouldCloseOnTouch(Context context, MotionEvent event) {
final boolean isOutside =
event.getAction() == MotionEvent.ACTION_DOWN && isOutOfBounds(context, event)
|| event.getAction() == MotionEvent.ACTION_OUTSIDE;
if (mCloseOnTouchOutside && peekDecorView() != null && isOutside) {
return true;
}
return false;
}
private boolean isOutOfBounds(Context context, MotionEvent event) {
final int x = (int) event.getX();
final int y = (int) event.getY();
final int slop = ViewConfiguration.get(context).getScaledWindowTouchSlop();
final View decorView = getDecorView();
return (x < -slop) || (y < -slop)
|| (x > (decorView.getWidth()+slop))
|| (y > (decorView.getHeight()+slop));
}
}
Window の shouldCloseOnTouch() では、mCloseOnTouchOutside が true、かつ peekDecorView が null ではない、かつ MotionEvent の action が MotionEvent.ACTION_OUTSIDE、もしくは MotionEvent.ACTION_DOWN でタップ位置が DecorView の外側の場合、true が返ります。
Window の setCloseOnTouchOutside() は hide になっていて通常のアプリからは呼べません。 ではコードでは指定できないのかというと、Activity の setFinishOnTouchOutside() から指定できます。
Activity
public void setFinishOnTouchOutside(boolean finish) {
mWindow.setCloseOnTouchOutside(finish);
}
Activity の onTouchEvent() で Window の shouldCloseOnTouch() を呼んでおり、これにより DecorView の外側をタップすると Activity が finish() します。
Activity
public boolean onTouchEvent(MotionEvent event) {
if (mWindow.shouldCloseOnTouch(this, event)) {
finish();
return true;
}
return false;
}
ちなみに android:windowCloseOnTouchOutside 属性の設定値は、PhoneWindow から Window.setCloseOnTouchOutsideIfNotSet() を呼ぶことで適用されています。
0 件のコメント:
コメントを投稿