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