• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2008 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package android.view;
18 
19 import android.content.Context;
20 import android.content.res.TypedArray;
21 import android.graphics.Canvas;
22 import android.util.AttributeSet;
23 import android.widget.RemoteViews.RemoteView;
24 
25 import com.android.internal.R;
26 
27 import java.lang.ref.WeakReference;
28 
29 /**
30  * A ViewStub is an invisible, zero-sized View that can be used to lazily inflate
31  * layout resources at runtime.
32  *
33  * When a ViewStub is made visible, or when {@link #inflate()}  is invoked, the layout resource
34  * is inflated. The ViewStub then replaces itself in its parent with the inflated View or Views.
35  * Therefore, the ViewStub exists in the view hierarchy until {@link #setVisibility(int)} or
36  * {@link #inflate()} is invoked.
37  *
38  * The inflated View is added to the ViewStub's parent with the ViewStub's layout
39  * parameters. Similarly, you can define/override the inflate View's id by using the
40  * ViewStub's inflatedId property. For instance:
41  *
42  * <pre>
43  *     &lt;ViewStub android:id="@+id/stub"
44  *               android:inflatedId="@+id/subTree"
45  *               android:layout="@layout/mySubTree"
46  *               android:layout_width="120dip"
47  *               android:layout_height="40dip" /&gt;
48  * </pre>
49  *
50  * The ViewStub thus defined can be found using the id "stub." After inflation of
51  * the layout resource "mySubTree," the ViewStub is removed from its parent. The
52  * View created by inflating the layout resource "mySubTree" can be found using the
53  * id "subTree," specified by the inflatedId property. The inflated View is finally
54  * assigned a width of 120dip and a height of 40dip.
55  *
56  * The preferred way to perform the inflation of the layout resource is the following:
57  *
58  * <pre>
59  *     ViewStub stub = (ViewStub) findViewById(R.id.stub);
60  *     View inflated = stub.inflate();
61  * </pre>
62  *
63  * When {@link #inflate()} is invoked, the ViewStub is replaced by the inflated View
64  * and the inflated View is returned. This lets applications get a reference to the
65  * inflated View without executing an extra findViewById().
66  *
67  * @attr ref android.R.styleable#ViewStub_inflatedId
68  * @attr ref android.R.styleable#ViewStub_layout
69  */
70 @RemoteView
71 public final class ViewStub extends View {
72     private int mLayoutResource = 0;
73     private int mInflatedId;
74 
75     private WeakReference<View> mInflatedViewRef;
76 
77     private LayoutInflater mInflater;
78     private OnInflateListener mInflateListener;
79 
ViewStub(Context context)80     public ViewStub(Context context) {
81         initialize(context);
82     }
83 
84     /**
85      * Creates a new ViewStub with the specified layout resource.
86      *
87      * @param context The application's environment.
88      * @param layoutResource The reference to a layout resource that will be inflated.
89      */
ViewStub(Context context, int layoutResource)90     public ViewStub(Context context, int layoutResource) {
91         mLayoutResource = layoutResource;
92         initialize(context);
93     }
94 
ViewStub(Context context, AttributeSet attrs)95     public ViewStub(Context context, AttributeSet attrs) {
96         this(context, attrs, 0);
97     }
98 
99     @SuppressWarnings({"UnusedDeclaration"})
ViewStub(Context context, AttributeSet attrs, int defStyle)100     public ViewStub(Context context, AttributeSet attrs, int defStyle) {
101         TypedArray a = context.obtainStyledAttributes(attrs, com.android.internal.R.styleable.ViewStub,
102                 defStyle, 0);
103 
104         mInflatedId = a.getResourceId(R.styleable.ViewStub_inflatedId, NO_ID);
105         mLayoutResource = a.getResourceId(R.styleable.ViewStub_layout, 0);
106 
107         a.recycle();
108 
109         a = context.obtainStyledAttributes(attrs, com.android.internal.R.styleable.View, defStyle, 0);
110         mID = a.getResourceId(R.styleable.View_id, NO_ID);
111         a.recycle();
112 
113         initialize(context);
114     }
115 
initialize(Context context)116     private void initialize(Context context) {
117         mContext = context;
118         setVisibility(GONE);
119         setWillNotDraw(true);
120     }
121 
122     /**
123      * Returns the id taken by the inflated view. If the inflated id is
124      * {@link View#NO_ID}, the inflated view keeps its original id.
125      *
126      * @return A positive integer used to identify the inflated view or
127      *         {@link #NO_ID} if the inflated view should keep its id.
128      *
129      * @see #setInflatedId(int)
130      * @attr ref android.R.styleable#ViewStub_inflatedId
131      */
getInflatedId()132     public int getInflatedId() {
133         return mInflatedId;
134     }
135 
136     /**
137      * Defines the id taken by the inflated view. If the inflated id is
138      * {@link View#NO_ID}, the inflated view keeps its original id.
139      *
140      * @param inflatedId A positive integer used to identify the inflated view or
141      *                   {@link #NO_ID} if the inflated view should keep its id.
142      *
143      * @see #getInflatedId()
144      * @attr ref android.R.styleable#ViewStub_inflatedId
145      */
146     @android.view.RemotableViewMethod
setInflatedId(int inflatedId)147     public void setInflatedId(int inflatedId) {
148         mInflatedId = inflatedId;
149     }
150 
151     /**
152      * Returns the layout resource that will be used by {@link #setVisibility(int)} or
153      * {@link #inflate()} to replace this StubbedView
154      * in its parent by another view.
155      *
156      * @return The layout resource identifier used to inflate the new View.
157      *
158      * @see #setLayoutResource(int)
159      * @see #setVisibility(int)
160      * @see #inflate()
161      * @attr ref android.R.styleable#ViewStub_layout
162      */
getLayoutResource()163     public int getLayoutResource() {
164         return mLayoutResource;
165     }
166 
167     /**
168      * Specifies the layout resource to inflate when this StubbedView becomes visible or invisible
169      * or when {@link #inflate()} is invoked. The View created by inflating the layout resource is
170      * used to replace this StubbedView in its parent.
171      *
172      * @param layoutResource A valid layout resource identifier (different from 0.)
173      *
174      * @see #getLayoutResource()
175      * @see #setVisibility(int)
176      * @see #inflate()
177      * @attr ref android.R.styleable#ViewStub_layout
178      */
179     @android.view.RemotableViewMethod
setLayoutResource(int layoutResource)180     public void setLayoutResource(int layoutResource) {
181         mLayoutResource = layoutResource;
182     }
183 
184     /**
185      * Set {@link LayoutInflater} to use in {@link #inflate()}, or {@code null}
186      * to use the default.
187      */
setLayoutInflater(LayoutInflater inflater)188     public void setLayoutInflater(LayoutInflater inflater) {
189         mInflater = inflater;
190     }
191 
192     /**
193      * Get current {@link LayoutInflater} used in {@link #inflate()}.
194      */
getLayoutInflater()195     public LayoutInflater getLayoutInflater() {
196         return mInflater;
197     }
198 
199     @Override
onMeasure(int widthMeasureSpec, int heightMeasureSpec)200     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
201         setMeasuredDimension(0, 0);
202     }
203 
204     @Override
draw(Canvas canvas)205     public void draw(Canvas canvas) {
206     }
207 
208     @Override
dispatchDraw(Canvas canvas)209     protected void dispatchDraw(Canvas canvas) {
210     }
211 
212     /**
213      * When visibility is set to {@link #VISIBLE} or {@link #INVISIBLE},
214      * {@link #inflate()} is invoked and this StubbedView is replaced in its parent
215      * by the inflated layout resource.
216      *
217      * @param visibility One of {@link #VISIBLE}, {@link #INVISIBLE}, or {@link #GONE}.
218      *
219      * @see #inflate()
220      */
221     @Override
222     @android.view.RemotableViewMethod
setVisibility(int visibility)223     public void setVisibility(int visibility) {
224         if (mInflatedViewRef != null) {
225             View view = mInflatedViewRef.get();
226             if (view != null) {
227                 view.setVisibility(visibility);
228             } else {
229                 throw new IllegalStateException("setVisibility called on un-referenced view");
230             }
231         } else {
232             super.setVisibility(visibility);
233             if (visibility == VISIBLE || visibility == INVISIBLE) {
234                 inflate();
235             }
236         }
237     }
238 
239     /**
240      * Inflates the layout resource identified by {@link #getLayoutResource()}
241      * and replaces this StubbedView in its parent by the inflated layout resource.
242      *
243      * @return The inflated layout resource.
244      *
245      */
inflate()246     public View inflate() {
247         final ViewParent viewParent = getParent();
248 
249         if (viewParent != null && viewParent instanceof ViewGroup) {
250             if (mLayoutResource != 0) {
251                 final ViewGroup parent = (ViewGroup) viewParent;
252                 final LayoutInflater factory;
253                 if (mInflater != null) {
254                     factory = mInflater;
255                 } else {
256                     factory = LayoutInflater.from(mContext);
257                 }
258                 final View view = factory.inflate(mLayoutResource, parent,
259                         false);
260 
261                 if (mInflatedId != NO_ID) {
262                     view.setId(mInflatedId);
263                 }
264 
265                 final int index = parent.indexOfChild(this);
266                 parent.removeViewInLayout(this);
267 
268                 final ViewGroup.LayoutParams layoutParams = getLayoutParams();
269                 if (layoutParams != null) {
270                     parent.addView(view, index, layoutParams);
271                 } else {
272                     parent.addView(view, index);
273                 }
274 
275                 mInflatedViewRef = new WeakReference<View>(view);
276 
277                 if (mInflateListener != null) {
278                     mInflateListener.onInflate(this, view);
279                 }
280 
281                 return view;
282             } else {
283                 throw new IllegalArgumentException("ViewStub must have a valid layoutResource");
284             }
285         } else {
286             throw new IllegalStateException("ViewStub must have a non-null ViewGroup viewParent");
287         }
288     }
289 
290     /**
291      * Specifies the inflate listener to be notified after this ViewStub successfully
292      * inflated its layout resource.
293      *
294      * @param inflateListener The OnInflateListener to notify of successful inflation.
295      *
296      * @see android.view.ViewStub.OnInflateListener
297      */
setOnInflateListener(OnInflateListener inflateListener)298     public void setOnInflateListener(OnInflateListener inflateListener) {
299         mInflateListener = inflateListener;
300     }
301 
302     /**
303      * Listener used to receive a notification after a ViewStub has successfully
304      * inflated its layout resource.
305      *
306      * @see android.view.ViewStub#setOnInflateListener(android.view.ViewStub.OnInflateListener)
307      */
308     public static interface OnInflateListener {
309         /**
310          * Invoked after a ViewStub successfully inflated its layout resource.
311          * This method is invoked after the inflated view was added to the
312          * hierarchy but before the layout pass.
313          *
314          * @param stub The ViewStub that initiated the inflation.
315          * @param inflated The inflated View.
316          */
onInflate(ViewStub stub, View inflated)317         void onInflate(ViewStub stub, View inflated);
318     }
319 }
320