/*
 * Copyright (C) 2008 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package android.view;

import android.annotation.IdRes;
import android.annotation.LayoutRes;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.util.AttributeSet;
import android.widget.RemoteViews.RemoteView;

import com.android.internal.R;

import java.lang.ref.WeakReference;

A ViewStub is an invisible, zero-sized View that can be used to lazily inflate layout resources at runtime. When a ViewStub is made visible, or when inflate() is invoked, the layout resource is inflated. The ViewStub then replaces itself in its parent with the inflated View or Views. Therefore, the ViewStub exists in the view hierarchy until setVisibility(int) or inflate() is invoked. The inflated View is added to the ViewStub's parent with the ViewStub's layout parameters. Similarly, you can define/override the inflate View's id by using the ViewStub's inflatedId property. For instance:
    <ViewStub android:id="@+id/stub"
              android:inflatedId="@+id/subTree"
              android:layout="@layout/mySubTree"
              android:layout_width="120dip"
              android:layout_height="40dip" />
The ViewStub thus defined can be found using the id "stub." After inflation of the layout resource "mySubTree," the ViewStub is removed from its parent. The View created by inflating the layout resource "mySubTree" can be found using the id "subTree," specified by the inflatedId property. The inflated View is finally assigned a width of 120dip and a height of 40dip. The preferred way to perform the inflation of the layout resource is the following:
    ViewStub stub = findViewById(R.id.stub);
    View inflated = stub.inflate();
When inflate() is invoked, the ViewStub is replaced by the inflated View and the inflated View is returned. This lets applications get a reference to the inflated View without executing an extra findViewById().
@attrref android.R.styleable#ViewStub_inflatedId
@attrref android.R.styleable#ViewStub_layout
/** * A ViewStub is an invisible, zero-sized View that can be used to lazily inflate * layout resources at runtime. * * When a ViewStub is made visible, or when {@link #inflate()} is invoked, the layout resource * is inflated. The ViewStub then replaces itself in its parent with the inflated View or Views. * Therefore, the ViewStub exists in the view hierarchy until {@link #setVisibility(int)} or * {@link #inflate()} is invoked. * * The inflated View is added to the ViewStub's parent with the ViewStub's layout * parameters. Similarly, you can define/override the inflate View's id by using the * ViewStub's inflatedId property. For instance: * * <pre> * &lt;ViewStub android:id="@+id/stub" * android:inflatedId="@+id/subTree" * android:layout="@layout/mySubTree" * android:layout_width="120dip" * android:layout_height="40dip" /&gt; * </pre> * * The ViewStub thus defined can be found using the id "stub." After inflation of * the layout resource "mySubTree," the ViewStub is removed from its parent. The * View created by inflating the layout resource "mySubTree" can be found using the * id "subTree," specified by the inflatedId property. The inflated View is finally * assigned a width of 120dip and a height of 40dip. * * The preferred way to perform the inflation of the layout resource is the following: * * <pre> * ViewStub stub = findViewById(R.id.stub); * View inflated = stub.inflate(); * </pre> * * When {@link #inflate()} is invoked, the ViewStub is replaced by the inflated View * and the inflated View is returned. This lets applications get a reference to the * inflated View without executing an extra findViewById(). * * @attr ref android.R.styleable#ViewStub_inflatedId * @attr ref android.R.styleable#ViewStub_layout */
@RemoteView public final class ViewStub extends View { private int mInflatedId; private int mLayoutResource; private WeakReference<View> mInflatedViewRef; private LayoutInflater mInflater; private OnInflateListener mInflateListener; public ViewStub(Context context) { this(context, 0); }
Creates a new ViewStub with the specified layout resource.
Params:
  • context – The application's environment.
  • layoutResource – The reference to a layout resource that will be inflated.
/** * Creates a new ViewStub with the specified layout resource. * * @param context The application's environment. * @param layoutResource The reference to a layout resource that will be inflated. */
public ViewStub(Context context, @LayoutRes int layoutResource) { this(context, null); mLayoutResource = layoutResource; } public ViewStub(Context context, AttributeSet attrs) { this(context, attrs, 0); } public ViewStub(Context context, AttributeSet attrs, int defStyleAttr) { this(context, attrs, defStyleAttr, 0); } public ViewStub(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { super(context); final TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.ViewStub, defStyleAttr, defStyleRes); mInflatedId = a.getResourceId(R.styleable.ViewStub_inflatedId, NO_ID); mLayoutResource = a.getResourceId(R.styleable.ViewStub_layout, 0); mID = a.getResourceId(R.styleable.ViewStub_id, NO_ID); a.recycle(); setVisibility(GONE); setWillNotDraw(true); }
Returns the id taken by the inflated view. If the inflated id is View.NO_ID, the inflated view keeps its original id.
See Also:
Returns:A positive integer used to identify the inflated view or View.NO_ID if the inflated view should keep its id.
@attrref android.R.styleable#ViewStub_inflatedId
/** * Returns the id taken by the inflated view. If the inflated id is * {@link View#NO_ID}, the inflated view keeps its original id. * * @return A positive integer used to identify the inflated view or * {@link #NO_ID} if the inflated view should keep its id. * * @see #setInflatedId(int) * @attr ref android.R.styleable#ViewStub_inflatedId */
@IdRes public int getInflatedId() { return mInflatedId; }
Defines the id taken by the inflated view. If the inflated id is View.NO_ID, the inflated view keeps its original id.
Params:
  • inflatedId – A positive integer used to identify the inflated view or View.NO_ID if the inflated view should keep its id.
See Also:
@attrref android.R.styleable#ViewStub_inflatedId
/** * Defines the id taken by the inflated view. If the inflated id is * {@link View#NO_ID}, the inflated view keeps its original id. * * @param inflatedId A positive integer used to identify the inflated view or * {@link #NO_ID} if the inflated view should keep its id. * * @see #getInflatedId() * @attr ref android.R.styleable#ViewStub_inflatedId */
@android.view.RemotableViewMethod(asyncImpl = "setInflatedIdAsync") public void setInflatedId(@IdRes int inflatedId) { mInflatedId = inflatedId; }
@hide
/** @hide **/
public Runnable setInflatedIdAsync(@IdRes int inflatedId) { mInflatedId = inflatedId; return null; }
Returns the layout resource that will be used by setVisibility(int) or inflate() to replace this StubbedView in its parent by another view.
See Also:
Returns:The layout resource identifier used to inflate the new View.
@attrref android.R.styleable#ViewStub_layout
/** * Returns the layout resource that will be used by {@link #setVisibility(int)} or * {@link #inflate()} to replace this StubbedView * in its parent by another view. * * @return The layout resource identifier used to inflate the new View. * * @see #setLayoutResource(int) * @see #setVisibility(int) * @see #inflate() * @attr ref android.R.styleable#ViewStub_layout */
@LayoutRes public int getLayoutResource() { return mLayoutResource; }
Specifies the layout resource to inflate when this StubbedView becomes visible or invisible or when inflate() is invoked. The View created by inflating the layout resource is used to replace this StubbedView in its parent.
Params:
  • layoutResource – A valid layout resource identifier (different from 0.)
See Also:
@attrref android.R.styleable#ViewStub_layout
/** * Specifies the layout resource to inflate when this StubbedView becomes visible or invisible * or when {@link #inflate()} is invoked. The View created by inflating the layout resource is * used to replace this StubbedView in its parent. * * @param layoutResource A valid layout resource identifier (different from 0.) * * @see #getLayoutResource() * @see #setVisibility(int) * @see #inflate() * @attr ref android.R.styleable#ViewStub_layout */
@android.view.RemotableViewMethod(asyncImpl = "setLayoutResourceAsync") public void setLayoutResource(@LayoutRes int layoutResource) { mLayoutResource = layoutResource; }
@hide
/** @hide **/
public Runnable setLayoutResourceAsync(@LayoutRes int layoutResource) { mLayoutResource = layoutResource; return null; }
Set LayoutInflater to use in inflate(), or null to use the default.
/** * Set {@link LayoutInflater} to use in {@link #inflate()}, or {@code null} * to use the default. */
public void setLayoutInflater(LayoutInflater inflater) { mInflater = inflater; }
Get current LayoutInflater used in inflate().
/** * Get current {@link LayoutInflater} used in {@link #inflate()}. */
public LayoutInflater getLayoutInflater() { return mInflater; } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { setMeasuredDimension(0, 0); } @Override public void draw(Canvas canvas) { } @Override protected void dispatchDraw(Canvas canvas) { }
When visibility is set to View.VISIBLE or View.INVISIBLE, inflate() is invoked and this StubbedView is replaced in its parent by the inflated layout resource. After that calls to this function are passed through to the inflated view.
Params:
See Also:
/** * When visibility is set to {@link #VISIBLE} or {@link #INVISIBLE}, * {@link #inflate()} is invoked and this StubbedView is replaced in its parent * by the inflated layout resource. After that calls to this function are passed * through to the inflated view. * * @param visibility One of {@link #VISIBLE}, {@link #INVISIBLE}, or {@link #GONE}. * * @see #inflate() */
@Override @android.view.RemotableViewMethod(asyncImpl = "setVisibilityAsync") public void setVisibility(int visibility) { if (mInflatedViewRef != null) { View view = mInflatedViewRef.get(); if (view != null) { view.setVisibility(visibility); } else { throw new IllegalStateException("setVisibility called on un-referenced view"); } } else { super.setVisibility(visibility); if (visibility == VISIBLE || visibility == INVISIBLE) { inflate(); } } }
@hide
/** @hide **/
public Runnable setVisibilityAsync(int visibility) { if (visibility == VISIBLE || visibility == INVISIBLE) { ViewGroup parent = (ViewGroup) getParent(); return new ViewReplaceRunnable(inflateViewNoAdd(parent)); } else { return null; } } private View inflateViewNoAdd(ViewGroup parent) { final LayoutInflater factory; if (mInflater != null) { factory = mInflater; } else { factory = LayoutInflater.from(mContext); } final View view = factory.inflate(mLayoutResource, parent, false); if (mInflatedId != NO_ID) { view.setId(mInflatedId); } return view; } private void replaceSelfWithView(View view, ViewGroup parent) { final int index = parent.indexOfChild(this); parent.removeViewInLayout(this); final ViewGroup.LayoutParams layoutParams = getLayoutParams(); if (layoutParams != null) { parent.addView(view, index, layoutParams); } else { parent.addView(view, index); } }
Inflates the layout resource identified by getLayoutResource() and replaces this StubbedView in its parent by the inflated layout resource.
Returns:The inflated layout resource.
/** * Inflates the layout resource identified by {@link #getLayoutResource()} * and replaces this StubbedView in its parent by the inflated layout resource. * * @return The inflated layout resource. * */
public View inflate() { final ViewParent viewParent = getParent(); if (viewParent != null && viewParent instanceof ViewGroup) { if (mLayoutResource != 0) { final ViewGroup parent = (ViewGroup) viewParent; final View view = inflateViewNoAdd(parent); replaceSelfWithView(view, parent); mInflatedViewRef = new WeakReference<>(view); if (mInflateListener != null) { mInflateListener.onInflate(this, view); } return view; } else { throw new IllegalArgumentException("ViewStub must have a valid layoutResource"); } } else { throw new IllegalStateException("ViewStub must have a non-null ViewGroup viewParent"); } }
Specifies the inflate listener to be notified after this ViewStub successfully inflated its layout resource.
Params:
  • inflateListener – The OnInflateListener to notify of successful inflation.
See Also:
/** * Specifies the inflate listener to be notified after this ViewStub successfully * inflated its layout resource. * * @param inflateListener The OnInflateListener to notify of successful inflation. * * @see android.view.ViewStub.OnInflateListener */
public void setOnInflateListener(OnInflateListener inflateListener) { mInflateListener = inflateListener; }
Listener used to receive a notification after a ViewStub has successfully inflated its layout resource.
See Also:
  • setOnInflateListener.setOnInflateListener(OnInflateListener)
/** * Listener used to receive a notification after a ViewStub has successfully * inflated its layout resource. * * @see android.view.ViewStub#setOnInflateListener(android.view.ViewStub.OnInflateListener) */
public static interface OnInflateListener {
Invoked after a ViewStub successfully inflated its layout resource. This method is invoked after the inflated view was added to the hierarchy but before the layout pass.
Params:
  • stub – The ViewStub that initiated the inflation.
  • inflated – The inflated View.
/** * Invoked after a ViewStub successfully inflated its layout resource. * This method is invoked after the inflated view was added to the * hierarchy but before the layout pass. * * @param stub The ViewStub that initiated the inflation. * @param inflated The inflated View. */
void onInflate(ViewStub stub, View inflated); }
@hide
/** @hide **/
public class ViewReplaceRunnable implements Runnable { public final View view; ViewReplaceRunnable(View view) { this.view = view; } @Override public void run() { replaceSelfWithView(view, (ViewGroup) getParent()); } } }