/** * Set the activity content from a layout resource. The resource will be * inflated, adding all top-level views to the activity. * * @param layoutResID Resource ID to be inflated. * * @see #setContentView(android.view.View) * @see #setContentView(android.view.View, android.view.ViewGroup.LayoutParams) */ publicvoidsetContentView(@LayoutResint layoutResID){ getWindow().setContentView(layoutResID); initWindowDecorActionBar(); }
/** * Retrieve the current {@link android.view.Window} for the activity. * This can be used to directly access parts of the Window API that * are not available through Activity/Screen. * * @return Window The current window, or null if the activity is not * visual. */ public Window getWindow(){ return mWindow; }
@Override publicvoidsetContentView(int layoutResID){ // Note: FEATURE_CONTENT_TRANSITIONS may be set in the process of installing the window // decor, when theme attributes and the like are crystalized. Do not check the feature // before this happens. //注释1 if (mContentParent == null) { installDecor(); } elseif (!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()) { cb.onContentChanged(); } mContentParentExplicitlySet = true; }
protected DecorView generateDecor(int featureId){ // System process doesn't have application context and in that case we need to directly use // the context we have. Otherwise we want the application context, so we don't cling to the // activity. Context context; if (mUseDecorContext) { Context applicationContext = getContext().getApplicationContext(); if (applicationContext == null) { context = getContext(); } else { context = new DecorContext(applicationContext, getContext()); if (mTheme != -1) { context.setTheme(mTheme); } } } else { context = getContext(); } returnnew DecorView(context, featureId, this, getAttributes()); }
/** * Finds a view that was identified by the {@code android:id} XML attribute * that was processed in {@link android.app.Activity#onCreate}. * <p> * This will implicitly call {@link #getDecorView} with all of the associated side-effects. * <p> * <strong>Note:</strong> In most cases -- depending on compiler support -- * the resulting view is automatically cast to the target class type. If * the target class type is unconstrained, an explicit cast may be * necessary. * * @param id the ID to search for * @return a view with given ID if found, or {@code null} otherwise * @see View#findViewById(int) * @see Window#requireViewById(int) */ @Nullable public <T extends View> T findViewById(@IdResint id){ return getDecorView().findViewById(id); }
voidonResourcesLoaded(LayoutInflater inflater, int layoutResource){ if (mBackdropFrameRenderer != null) { loadBackgroundDrawablesIfNeeded(); mBackdropFrameRenderer.onResourcesLoaded( this, mResizingBackgroundDrawable, mCaptionBackgroundDrawable, mUserCaptionBackgroundDrawable, getCurrentColor(mStatusColorViewState), getCurrentColor(mNavigationColorViewState)); }
mDecorCaptionView = createDecorCaptionView(inflater); final View root = inflater.inflate(layoutResource, null); if (mDecorCaptionView != null) { if (mDecorCaptionView.getParent() == null) { addView(mDecorCaptionView, new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT)); } mDecorCaptionView.addView(root, new ViewGroup.MarginLayoutParams(MATCH_PARENT, MATCH_PARENT)); } else {
// Put it below the color views. addView(root, 0, new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT)); } mContentRoot = (ViewGroup) root; initializeElevation(); }
@Override publicvoidsetContentView(int layoutResID){ // Note: FEATURE_CONTENT_TRANSITIONS may be set in the process of installing the window // decor, when theme attributes and the like are crystalized. Do not check the feature // before this happens. if (mContentParent == null) { installDecor(); } elseif (!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()) { cb.onContentChanged(); } mContentParentExplicitlySet = true; }
/** * Inflate a new view hierarchy from the specified xml resource. Throws * {@link InflateException} if there is an error. * * @param resource ID for an XML layout resource to load (e.g., * <code>R.layout.main_page</code>) * @param root Optional view to be the parent of the generated hierarchy (if * <em>attachToRoot</em> is true), or else simply an object that * provides a set of LayoutParams values for root of the returned * hierarchy (if <em>attachToRoot</em> is false.) * @param attachToRoot Whether the inflated hierarchy should be attached to * the root parameter? If false, root is only used to create the * correct subclass of LayoutParams for the root view in the XML. * @return The root View of the inflated hierarchy. If root was supplied and * attachToRoot is true, this is root; otherwise it is the root of * the inflated XML file. */ public View inflate(@LayoutResint resource, @Nullable ViewGroup root, boolean attachToRoot){ final Resources res = getContext().getResources(); if (DEBUG) { Log.d(TAG, "INFLATING from resource: \"" + res.getResourceName(resource) + "\" (" + Integer.toHexString(resource) + ")"); }
/** * Inflate a new view hierarchy from the specified XML node. Throws * {@link InflateException} if there is an error. * <p> * <em><strong>Important</strong></em> For performance * reasons, view inflation relies heavily on pre-processing of XML files * that is done at build time. Therefore, it is not currently possible to * use LayoutInflater with an XmlPullParser over a plain XML file at runtime. * * @param parser XML dom node containing the description of the view * hierarchy. * @param root Optional view to be the parent of the generated hierarchy (if * <em>attachToRoot</em> is true), or else simply an object that * provides a set of LayoutParams values for root of the returned * hierarchy (if <em>attachToRoot</em> is false.) * @param attachToRoot Whether the inflated hierarchy should be attached to * the root parameter? If false, root is only used to create the * correct subclass of LayoutParams for the root view in the XML. * @return The root View of the inflated hierarchy. If root was supplied and * attachToRoot is true, this is root; otherwise it is the root of * the inflated XML file. */ public View inflate(XmlPullParser parser, @Nullable ViewGroup root, boolean attachToRoot){ synchronized (mConstructorArgs) { Trace.traceBegin(Trace.TRACE_TAG_VIEW, "inflate");
final Context inflaterContext = mContext; final AttributeSet attrs = Xml.asAttributeSet(parser); Context lastContext = (Context) mConstructorArgs[0]; mConstructorArgs[0] = inflaterContext; View result = root;
try { advanceToRootNode(parser); final String name = parser.getName();
if (TAG_MERGE.equals(name)) { if (root == null || !attachToRoot) { thrownew InflateException("<merge /> can be used only with a valid " + "ViewGroup root and attachToRoot=true"); }
rInflate(parser, root, inflaterContext, attrs, false); } else { // Temp is the root view that was found in the xml final View temp = createViewFromTag(root, name, inflaterContext, attrs);
ViewGroup.LayoutParams params = null;
if (root != null) { if (DEBUG) { System.out.println("Creating params from root: " + root); } // Create layout params that match root, if supplied params = root.generateLayoutParams(attrs); if (!attachToRoot) { // Set the layout params for temp if we are not // attaching. (If we are, we use addView, below) temp.setLayoutParams(params); } }
if (DEBUG) { System.out.println("-----> start inflating children"); }
// Inflate all children under temp against its context. rInflateChildren(parser, temp, attrs, true);
if (DEBUG) { System.out.println("-----> done inflating children"); }
// We are supposed to attach all the views we found (int temp) // to root. Do that now. if (root != null && attachToRoot) { root.addView(temp, params); }
// Decide whether to return the root that was passed in or the // top view found in xml. if (root == null || !attachToRoot) { result = temp; } }
/** * Recursive method used to inflate internal (non-root) children. This * method calls through to {@link #rInflate} using the parent context as * the inflation context. * <strong>Note:</strong> Default visibility so the BridgeInflater can * call it. */ finalvoidrInflateChildren(XmlPullParser parser, View parent, AttributeSet attrs, boolean finishInflate)throws XmlPullParserException, IOException { rInflate(parser, parent, parent.getContext(), attrs, finishInflate); }
/** * Recursive method used to descend down the xml hierarchy and instantiate * views, instantiate their children, and then call onFinishInflate(). * <p> * <strong>Note:</strong> Default visibility so the BridgeInflater can * override it. */ voidrInflate(XmlPullParser parser, View parent, Context context, AttributeSet attrs, boolean finishInflate)throws XmlPullParserException, IOException {
finalint depth = parser.getDepth(); int type; boolean pendingRequestFocus = false;
while (((type = parser.next()) != XmlPullParser.END_TAG || parser.getDepth() > depth) && type != XmlPullParser.END_DOCUMENT) {
if (type != XmlPullParser.START_TAG) { continue; }
final String name = parser.getName();
if (TAG_REQUEST_FOCUS.equals(name)) { pendingRequestFocus = true; consumeChildElements(parser); } elseif (TAG_TAG.equals(name)) { parseViewTag(parser, parent, attrs); } elseif (TAG_INCLUDE.equals(name)) { if (parser.getDepth() == 0) { thrownew InflateException("<include /> cannot be the root element"); } parseInclude(parser, context, parent, attrs); } elseif (TAG_MERGE.equals(name)) { thrownew InflateException("<merge /> must be the root element"); } else { final View view = createViewFromTag(parent, name, context, attrs); final ViewGroup viewGroup = (ViewGroup) parent; final ViewGroup.LayoutParams params = viewGroup.generateLayoutParams(attrs); rInflateChildren(parser, view, attrs, true); viewGroup.addView(view, params); } }
if (pendingRequestFocus) { parent.restoreDefaultFocus(); }
if (finishInflate) { parent.onFinishInflate(); } }
/** * Convenience method for calling through to the five-arg createViewFromTag * method. This method passes {@code false} for the {@code ignoreThemeAttr} * argument and should be used for everything except {@code >include>} * tag parsing. */ @UnsupportedAppUsage private View createViewFromTag(View parent, String name, Context context, AttributeSet attrs){ return createViewFromTag(parent, name, context, attrs, false); }
/** * Creates a view from a tag name using the supplied attribute set. * <p> * <strong>Note:</strong> Default visibility so the BridgeInflater can * override it. * * @param parent the parent view, used to inflate layout params * @param name the name of the XML tag used to define the view * @param context the inflation context for the view, typically the * {@code parent} or base layout inflater context * @param attrs the attribute set for the XML tag used to define the view * @param ignoreThemeAttr {@code true} to ignore the {@code android:theme} * attribute (if set) for the view being inflated, * {@code false} otherwise */ @UnsupportedAppUsage View createViewFromTag(View parent, String name, Context context, AttributeSet attrs, boolean ignoreThemeAttr){ if (name.equals("view")) { name = attrs.getAttributeValue(null, "class"); }
// Apply a theme wrapper, if allowed and one is specified. if (!ignoreThemeAttr) { final TypedArray ta = context.obtainStyledAttributes(attrs, ATTRS_THEME); finalint themeResId = ta.getResourceId(0, 0); if (themeResId != 0) { context = new ContextThemeWrapper(context, themeResId); } ta.recycle(); }
/** * Tries to create a view from a tag name using the supplied attribute set. * * This method gives the factory provided by {@link LayoutInflater#setFactory} and * {@link LayoutInflater#setFactory2} a chance to create a view. However, it does not apply all * of the general view creation logic, and thus may return {@code null} for some tags. This * method is used by {@link LayoutInflater#inflate} in creating {@code View} objects. * * @hide for use by precompiled layouts. * * @param parent the parent view, used to inflate layout params * @param name the name of the XML tag used to define the view * @param context the inflation context for the view, typically the * {@code parent} or base layout inflater context * @param attrs the attribute set for the XML tag used to define the view */ @UnsupportedAppUsage(trackingBug = 122360734) @Nullable publicfinal View tryCreateView(@Nullable View parent, @NonNull String name, @NonNull Context context, @NonNull AttributeSet attrs){ if (name.equals(TAG_1995)) { // Let's party like it's 1995! returnnew BlinkLayout(context, attrs); }
/** * Attach a custom Factory interface for creating views while using * this LayoutInflater. This must not be null, and can only be set once; * after setting, you can not change the factory. This is * called on each element name as the xml is parsed. If the factory returns * a View, that is added to the hierarchy. If it returns null, the next * factory default {@link #onCreateView} method is called. * * <p>If you have an existing * LayoutInflater and want to add your own factory to it, use * {@link #cloneInContext} to clone the existing instance and then you * can use this function (once) on the returned new instance. This will * merge your own factory with whatever factory the original instance is * using. */ publicvoidsetFactory(Factory factory){ if (mFactorySet) { thrownew IllegalStateException("A factory has already been set on this LayoutInflater"); } if (factory == null) { thrownew NullPointerException("Given factory can not be null"); } mFactorySet = true; if (mFactory == null) { mFactory = factory; } else { mFactory = new FactoryMerger(factory, null, mFactory, mFactory2); } }
/** * Like {@link #setFactory}, but allows you to set a {@link Factory2} * interface. */ publicvoidsetFactory2(Factory2 factory){ if (mFactorySet) { thrownew IllegalStateException("A factory has already been set on this LayoutInflater"); } if (factory == null) { thrownew NullPointerException("Given factory can not be null"); } mFactorySet = true; if (mFactory == null) { mFactory = mFactory2 = factory; } else { mFactory = mFactory2 = new FactoryMerger(factory, factory, mFactory, mFactory2); } }
/** * Low-level function for instantiating a view by name. This attempts to * instantiate a view class of the given <var>name</var> found in this * LayoutInflater's ClassLoader. * * <p> * There are two things that can happen in an error case: either the * exception describing the error will be thrown, or a null will be * returned. You must deal with both possibilities -- the former will happen * the first time createView() is called for a class of a particular name, * the latter every time there-after for that class name. * * @param viewContext The context used as the context parameter of the View constructor * @param name The full name of the class to be instantiated. * @param attrs The XML attributes supplied for this instance. * * @return View The newly instantiated view, or null. */ @Nullable publicfinal View createView(@NonNull Context viewContext, @NonNull String name, @Nullable String prefix, @Nullable AttributeSet attrs) throws ClassNotFoundException, InflateException { Objects.requireNonNull(viewContext); Objects.requireNonNull(name); Constructor<? extends View> constructor = sConstructorMap.get(name); if (constructor != null && !verifyClassLoader(constructor)) { constructor = null; sConstructorMap.remove(name); } Class<? extends View> clazz = null;
if (constructor == null) { // Class not found in the cache, see if it's real, and try to add it clazz = Class.forName(prefix != null ? (prefix + name) : name, false, mContext.getClassLoader()).asSubclass(View.class);
if (mFilter != null && clazz != null) { boolean allowed = mFilter.onLoadClass(clazz); if (!allowed) { failNotAllowed(name, prefix, viewContext, attrs); } } constructor = clazz.getConstructor(mConstructorSignature); constructor.setAccessible(true); sConstructorMap.put(name, constructor); } else { // If we have a filter, apply it to cached constructor if (mFilter != null) { // Have we seen this name before? Boolean allowedState = mFilterMap.get(name); if (allowedState == null) { // New class -- remember whether it is allowed clazz = Class.forName(prefix != null ? (prefix + name) : name, false, mContext.getClassLoader()).asSubclass(View.class);
/** * Version of {@link #onCreateView(View, String, AttributeSet)} that also * takes the inflation context. The default * implementation simply calls {@link #onCreateView(View, String, AttributeSet)}. * * @param viewContext The Context to be used as a constructor parameter for the View * @param parent The future parent of the returned view. <em>Note that * this may be null.</em> * @param name The fully qualified class name of the View to be create. * @param attrs An AttributeSet of attributes to apply to the View. * * @return View The View created. */ @Nullable public View onCreateView(@NonNull Context viewContext, @Nullable View parent, @NonNull String name, @Nullable AttributeSet attrs) throws ClassNotFoundException { return onCreateView(parent, name, attrs); }
/** * Version of {@link #onCreateView(String, AttributeSet)} that also * takes the future parent of the view being constructed. The default * implementation simply calls {@link #onCreateView(String, AttributeSet)}. * * @param parent The future parent of the returned view. <em>Note that * this may be null.</em> * @param name The fully qualified class name of the View to be create. * @param attrs An AttributeSet of attributes to apply to the View. * * @return View The View created. */ protected View onCreateView(View parent, String name, AttributeSet attrs) throws ClassNotFoundException { return onCreateView(name, attrs); }
/** * This routine is responsible for creating the correct subclass of View * given the xml element name. Override it to handle custom view objects. If * you override this in your subclass be sure to call through to * super.onCreateView(name) for names you do not recognize. * * @param name The fully qualified class name of the View to be create. * @param attrs An AttributeSet of attributes to apply to the View. * * @return View The View created. */ protected View onCreateView(String name, AttributeSet attrs) throws ClassNotFoundException { return createView(name, "android.view.", attrs); }