一、什么是WindowInsets?
WindowInsets源码解释为Window Content的一系列插值集合,可以理解为可以将其理解为不同的窗口装饰区域类型,比如一个Activity相对于手机屏幕需要空出的地方以腾给StatusBar、Ime、NavigationBar等系统窗口,具体表现为该区域需要的上下左右的宽高。
WindowInsets包括三类:SystemWindowInsets、StableInsets、WIndowDecorInsets
- SystemWindowInsets:全窗口下,被navigationbar、statusbar、ime或其他系统窗口覆盖的区域
- StableInsets:全窗口下,被系统UI覆盖的区域
- WIndowDecorInsets:系统预留属性
二、InsetsState
2.1 InsetsState简单介绍
1、保存系统中所有的Insets的状态,他是状态描述者,持有系统中可以产生Window Insets的window状态,它主要持有以下几种类型的Insets:
frameworks/base/core/java/android/view/InsetsState.java
public class InsetsState implements Parcelable {
public static final int ITYPE_INVALID = -1;
static final int FIRST_TYPE = 0;
public static final int ITYPE_STATUS_BAR = FIRST_TYPE;//状态栏
public static final int ITYPE_NAVIGATION_BAR = 1;//导航栏
public static final int ITYPE_CAPTION_BAR = 2;
public static final int ITYPE_TOP_GESTURES = 3;
public static final int ITYPE_BOTTOM_GESTURES = 4;
public static final int ITYPE_LEFT_GESTURES = 5;
public static final int ITYPE_RIGHT_GESTURES = 6;
public static final int ITYPE_TOP_MANDATORY_GESTURES = 7;
public static final int ITYPE_BOTTOM_MANDATORY_GESTURES = 8;
public static final int ITYPE_LEFT_MANDATORY_GESTURES = 9;
public static final int ITYPE_RIGHT_MANDATORY_GESTURES = 10;
public static final int ITYPE_LEFT_DISPLAY_CUTOUT = 11;
public static final int ITYPE_TOP_DISPLAY_CUTOUT = 12;
public static final int ITYPE_RIGHT_DISPLAY_CUTOUT = 13;
public static final int ITYPE_BOTTOM_DISPLAY_CUTOUT = 14;
public static final int ITYPE_LEFT_TAPPABLE_ELEMENT = 15;
public static final int ITYPE_TOP_TAPPABLE_ELEMENT = 16;
public static final int ITYPE_RIGHT_TAPPABLE_ELEMENT = 17;
public static final int ITYPE_BOTTOM_TAPPABLE_ELEMENT = 18;
public static final int ITYPE_IME = 19;//输入法
public static final int ITYPE_CLIMATE_BAR = 20;
public static final int ITYPE_EXTRA_NAVIGATION_BAR = 21;
static final int LAST_TYPE = ITYPE_EXTRA_NAVIGATION_BAR;
public static final int SIZE = LAST_TYPE + 1;
//mSources变量维护所有产生Insets的window(也就是InsetsSource)的状态。
private final InsetsSource[] mSources = new InsetsSource[SIZE];
}
2.2 InsetsState发生变化
1、InsetsState发生变化的时候,会回调ViewRootImpl的内部类W的insetsChanged方法,相关代码如下所示。
frameworks/base/core/java/android/view/ViewRootImpl.java
public final class ViewRootImpl implements ViewParent,
View.AttachInfo.Callbacks, ThreadedRenderer.DrawCallbacks,
AttachedSurfaceControl {
static class W extends IWindow.Stub {
private final WeakReference<ViewRootImpl> mViewAncestor;
private final IWindowSession mWindowSession;
W(ViewRootImpl viewAncestor) {
mViewAncestor = new WeakReference<ViewRootImpl>(viewAncestor);
mWindowSession = viewAncestor.mWindowSession;
}
//Insets发生了变化
@Override
public void insetsChanged(InsetsState insetsState, boolean willMove, boolean willResize) {
final ViewRootImpl viewAncestor = mViewAncestor.get();
if (viewAncestor != null) {
//触发ViewRootImpl的dispatchInsetsChanged方法
viewAncestor.dispatchInsetsChanged(insetsState, willMove, willResize);
}
}
}
//ViewRootImpl的内部Handler
final ViewRootHandler mHandler = new ViewRootHandler();
private void dispatchInsetsChanged(InsetsState insetsState, boolean willMove,
boolean willResize) {
if (Binder.getCallingPid() == android.os.Process.myPid()) {
insetsState = new InsetsState(insetsState, true /* copySource */);
}
if (mTranslator != null) {
mTranslator.translateInsetsStateInScreenToAppWindow(insetsState);
}
if (insetsState != null && insetsState.getSourceOrDefaultVisibility(ITYPE_IME)) {
ImeTracing.getInstance().triggerClientDump("ViewRootImpl#dispatchInsetsChanged",
getInsetsController().getHost().getInputMethodManager(), null /* icProto */);
}
SomeArgs args = SomeArgs.obtain();
args.arg1 = insetsState;
args.argi1 = willMove ? 1 : 0;
args.argi2 = willResize ? 1 : 0;
//发送MSG_INSETS_CHANGED消息事件,触发ViewRootHandler的handleMessage方法。
mHandler.obtainMessage(MSG_INSETS_CHANGED, args).sendToTarget();
}
//系统Insets的控制器
private final InsetsController mInsetsController;
final class ViewRootHandler extends Handler {
@Override
public void handleMessage(Message msg) {
try {
handleMessageImpl(msg);
} finally {
Trace.traceEnd(Trace.TRACE_TAG_VIEW);
}
}
private void handleMessageImpl(Message msg) {
switch (msg.what) {
...代码省略...
case MSG_INSETS_CHANGED: {
SomeArgs args = (SomeArgs) msg.obj;
mWillMove = args.argi1 == 1;
mWillResize = args.argi2 == 1;
//触发InsetsController的onStateChanged方法
mInsetsController.onStateChanged((InsetsState) args.arg1);
args.recycle();
break;
}
...代码省略...
}
}
}
ViewRootImpl经过层层调用,最终会调用InsetsController的onStateChanged方法。
2、InsetsController的onStateChanged方法如下所示。
frameworks/base/core/java/android/view/InsetsController.java
public class InsetsController implements WindowInsetsController, InsetsAnimationControlCallbacks {
public boolean onStateChanged(InsetsState state) {
boolean stateChanged = !mState.equals(state, true /* excludingCaptionInsets */,
false /* excludeInvisibleIme */)
|| !captionInsetsUnchanged();
if (!stateChanged && mLastDispatchedState.equals(state)) {
return false;
}
if (DEBUG) Log.d(TAG, "onStateChanged: " + state);
mLastDispatchedState.set(state, true /* copySources */);
final InsetsState lastState = new InsetsState(mState, true /* copySources */);
updateState(state);
applyLocalVisibilityOverride();
if (!mState.equals(lastState, false /* excludingCaptionInsets */,
true /* excludeInvisibleIme */)) {
if (DEBUG) Log.d(TAG, "onStateChanged, notifyInsetsChanged");
mHost.notifyInsetsChanged();
startResizingAnimationIfNeeded(lastState);
}
return true;
}
}