ViewStub.java revision b6af533114cfa5a4547990e79e96bd0402c47e72
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 17package android.view; 18 19import android.content.Context; 20import android.content.res.TypedArray; 21import android.graphics.Canvas; 22import android.util.AttributeSet; 23 24import com.android.internal.R; 25 26import 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 * <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" /> 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 */ 69public 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 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 */ 87 public ViewStub(Context context, int layoutResource) { 88 mLayoutResource = layoutResource; 89 initialize(context); 90 } 91 92 public ViewStub(Context context, AttributeSet attrs) { 93 this(context, attrs, 0); 94 } 95 96 @SuppressWarnings({"UnusedDeclaration"}) 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 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 */ 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 */ 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 */ 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 */ 175 public void setLayoutResource(int layoutResource) { 176 mLayoutResource = layoutResource; 177 } 178 179 @Override 180 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 181 setMeasuredDimension(0, 0); 182 } 183 184 @Override 185 public void draw(Canvas canvas) { 186 } 187 188 @Override 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 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 if (visibility == VISIBLE || visibility == INVISIBLE) { 211 super.setVisibility(visibility); 212 inflate(); 213 } 214 } 215 216 /** 217 * Inflates the layout resource identified by {@link #getLayoutResource()} 218 * and replaces this StubbedView in its parent by the inflated layout resource. 219 * 220 * @return The inflated layout resource. 221 * 222 */ 223 public View inflate() { 224 final ViewParent viewParent = getParent(); 225 226 if (viewParent != null && viewParent instanceof ViewGroup) { 227 if (mLayoutResource != 0) { 228 final ViewGroup parent = (ViewGroup) viewParent; 229 final LayoutInflater factory = LayoutInflater.from(mContext); 230 final View view = factory.inflate(mLayoutResource, parent, 231 false); 232 233 if (mInflatedId != NO_ID) { 234 view.setId(mInflatedId); 235 } 236 237 final int index = parent.indexOfChild(this); 238 parent.removeViewInLayout(this); 239 240 final ViewGroup.LayoutParams layoutParams = getLayoutParams(); 241 if (layoutParams != null) { 242 parent.addView(view, index, layoutParams); 243 } else { 244 parent.addView(view, index); 245 } 246 247 mInflatedViewRef = new WeakReference(view); 248 249 if (mInflateListener != null) { 250 mInflateListener.onInflate(this, view); 251 } 252 253 return view; 254 } else { 255 throw new IllegalArgumentException("ViewStub must have a valid layoutResource"); 256 } 257 } else { 258 throw new IllegalStateException("ViewStub must have a non-null ViewGroup viewParent"); 259 } 260 } 261 262 /** 263 * Specifies the inflate listener to be notified after this ViewStub successfully 264 * inflated its layout resource. 265 * 266 * @param inflateListener The OnInflateListener to notify of successful inflation. 267 * 268 * @see android.view.ViewStub.OnInflateListener 269 */ 270 public void setOnInflateListener(OnInflateListener inflateListener) { 271 mInflateListener = inflateListener; 272 } 273 274 /** 275 * Listener used to receive a notification after a ViewStub has successfully 276 * inflated its layout resource. 277 * 278 * @see android.view.ViewStub#setOnInflateListener(android.view.ViewStub.OnInflateListener) 279 */ 280 public static interface OnInflateListener { 281 /** 282 * Invoked after a ViewStub successfully inflated its layout resource. 283 * This method is invoked after the inflated view was added to the 284 * hierarchy but before the layout pass. 285 * 286 * @param stub The ViewStub that initiated the inflation. 287 * @param inflated The inflated View. 288 */ 289 void onInflate(ViewStub stub, View inflated); 290 } 291} 292