Activity构成
在自定义 View 的时候,需要去了解 View 体系的一个非常重要的知识点—— View 的事件分发机制。在讲 View 的事件分发机制之前,需要先了解一下 Activity 的构成,因为当你点击一个 View 时,会产生点击事件,点击事件最先传递到 Activity。
先来看 Activity 是怎么加载布局的:
public void setContentView(@LayoutRes int layoutResID) {
getWindow().setContentView(layoutResID);
initWindowDecorActionBar();
}
当你加载一个布局的时候,Activity 会先调用 getWindow().setContentView(layoutResID),再往下看什么是 getWindow():
public Window getWindow() {
return mWindow;
}
getWindow() 返回了 mWindow,继续往下找,会在 Activity 的 attach() 方法中发现使用了 mWindow:
final void attach(Context context, ActivityThread aThread,
Instrumentation instr, IBinder token, int ident,
Application application, Intent intent, ActivityInfo info,
CharSequence title, Activity parent, String id,
NonConfigurationInstances lastNonConfigurationInstances,
Configuration config, String referrer, IVoiceInteractor voiceInteractor,
Window window, ActivityConfigCallback activityConfigCallback, IBinder assistToken) {
attachBaseContext(context);
mFragments.attachHost(null /*parent*/);
mWindow = new PhoneWindow(this, window, activityConfigCallback);
mWindow.setWindowControllerCallback(this);
mWindow.setCallback(this);
mWindow.setOnWindowDismissedCallback(this);
mWindow.getLayoutInflater().setPrivateFactory(this);
···
}
getWindow() 返回了 mWindow,而 mWindow 又是由 PhoneWindow 实例化而来的。所以 getWindow().setContentView() 实际上就是指的是 PhonewWindow.setContentView(),接下来看看 PhonewWindow.setContentView() 的内容:
@Override
public void setContentView(int layoutResID) {
if (mContentParent == null) {
installDecor();
} else if (!hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
mContentParent.removeAllViews();
}
if (hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
final Scene newScene = Scene.getSceneForLayout(mContentParent, layoutResID,
getContext());
transitionTo(newScene);
} else {
mLayoutInflater.inflate(layoutResID, mContentParent);
}
mContentParent.requestApplyInsets();
final Callback cb = getCallback();
if (cb != null && !isDestroyed()