• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2014 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.support.v7.widget;
18 
19 import android.content.Context;
20 import android.content.res.TypedArray;
21 import android.graphics.Canvas;
22 import android.support.v7.appcompat.R;
23 import android.util.AttributeSet;
24 import android.view.LayoutInflater;
25 import android.view.View;
26 import android.view.ViewGroup;
27 import android.view.ViewParent;
28 
29 import java.lang.ref.WeakReference;
30 
31 /**
32  * Backport of {@link android.view.ViewStub} so that we can set the
33  * {@link android.view.LayoutInflater} on devices before Jelly Bean.
34  *
35  * @hide
36  */
37 public final class ViewStubCompat extends View {
38     private int mLayoutResource = 0;
39     private int mInflatedId;
40 
41     private WeakReference<View> mInflatedViewRef;
42 
43     private LayoutInflater mInflater;
44     private OnInflateListener mInflateListener;
45 
ViewStubCompat(Context context, AttributeSet attrs)46     public ViewStubCompat(Context context, AttributeSet attrs) {
47         this(context, attrs, 0);
48     }
49 
ViewStubCompat(Context context, AttributeSet attrs, int defStyle)50     public ViewStubCompat(Context context, AttributeSet attrs, int defStyle) {
51         super(context, attrs, defStyle);
52 
53         TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.ViewStubCompat,
54                 defStyle, 0);
55 
56         mInflatedId = a.getResourceId(R.styleable.ViewStubCompat_android_inflatedId, NO_ID);
57         mLayoutResource = a.getResourceId(R.styleable.ViewStubCompat_android_layout, 0);
58 
59         setId(a.getResourceId(R.styleable.ViewStubCompat_android_id, NO_ID));
60         a.recycle();
61 
62         setVisibility(GONE);
63         setWillNotDraw(true);
64     }
65 
66     /**
67      * Returns the id taken by the inflated view. If the inflated id is
68      * {@link View#NO_ID}, the inflated view keeps its original id.
69      *
70      * @return A positive integer used to identify the inflated view or
71      *         {@link #NO_ID} if the inflated view should keep its id.
72      *
73      * @see #setInflatedId(int)
74      * @attr name android:inflatedId
75      */
getInflatedId()76     public int getInflatedId() {
77         return mInflatedId;
78     }
79 
80     /**
81      * Defines the id taken by the inflated view. If the inflated id is
82      * {@link View#NO_ID}, the inflated view keeps its original id.
83      *
84      * @param inflatedId A positive integer used to identify the inflated view or
85      *                   {@link #NO_ID} if the inflated view should keep its id.
86      *
87      * @see #getInflatedId()
88      * @attr name android:inflatedId
89      */
setInflatedId(int inflatedId)90     public void setInflatedId(int inflatedId) {
91         mInflatedId = inflatedId;
92     }
93 
94     /**
95      * Returns the layout resource that will be used by {@link #setVisibility(int)} or
96      * {@link #inflate()} to replace this StubbedView
97      * in its parent by another view.
98      *
99      * @return The layout resource identifier used to inflate the new View.
100      *
101      * @see #setLayoutResource(int)
102      * @see #setVisibility(int)
103      * @see #inflate()
104      * @attr name android:layout
105      */
getLayoutResource()106     public int getLayoutResource() {
107         return mLayoutResource;
108     }
109 
110     /**
111      * Specifies the layout resource to inflate when this StubbedView becomes visible or invisible
112      * or when {@link #inflate()} is invoked. The View created by inflating the layout resource is
113      * used to replace this StubbedView in its parent.
114      *
115      * @param layoutResource A valid layout resource identifier (different from 0.)
116      *
117      * @see #getLayoutResource()
118      * @see #setVisibility(int)
119      * @see #inflate()
120      * @attr name android:layout
121      */
setLayoutResource(int layoutResource)122     public void setLayoutResource(int layoutResource) {
123         mLayoutResource = layoutResource;
124     }
125 
126     /**
127      * Set {@link LayoutInflater} to use in {@link #inflate()}, or {@code null}
128      * to use the default.
129      */
setLayoutInflater(LayoutInflater inflater)130     public void setLayoutInflater(LayoutInflater inflater) {
131         mInflater = inflater;
132     }
133 
134     /**
135      * Get current {@link LayoutInflater} used in {@link #inflate()}.
136      */
getLayoutInflater()137     public LayoutInflater getLayoutInflater() {
138         return mInflater;
139     }
140 
141     @Override
onMeasure(int widthMeasureSpec, int heightMeasureSpec)142     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
143         setMeasuredDimension(0, 0);
144     }
145 
146     @Override
draw(Canvas canvas)147     public void draw(Canvas canvas) {
148     }
149 
150     @Override
dispatchDraw(Canvas canvas)151     protected void dispatchDraw(Canvas canvas) {
152     }
153 
154     /**
155      * When visibility is set to {@link #VISIBLE} or {@link #INVISIBLE},
156      * {@link #inflate()} is invoked and this StubbedView is replaced in its parent
157      * by the inflated layout resource. After that calls to this function are passed
158      * through to the inflated view.
159      *
160      * @param visibility One of {@link #VISIBLE}, {@link #INVISIBLE}, or {@link #GONE}.
161      *
162      * @see #inflate()
163      */
164     @Override
setVisibility(int visibility)165     public void setVisibility(int visibility) {
166         if (mInflatedViewRef != null) {
167             View view = mInflatedViewRef.get();
168             if (view != null) {
169                 view.setVisibility(visibility);
170             } else {
171                 throw new IllegalStateException("setVisibility called on un-referenced view");
172             }
173         } else {
174             super.setVisibility(visibility);
175             if (visibility == VISIBLE || visibility == INVISIBLE) {
176                 inflate();
177             }
178         }
179     }
180 
181     /**
182      * Inflates the layout resource identified by {@link #getLayoutResource()}
183      * and replaces this StubbedView in its parent by the inflated layout resource.
184      *
185      * @return The inflated layout resource.
186      *
187      */
inflate()188     public View inflate() {
189         final ViewParent viewParent = getParent();
190 
191         if (viewParent != null && viewParent instanceof ViewGroup) {
192             if (mLayoutResource != 0) {
193                 final ViewGroup parent = (ViewGroup) viewParent;
194                 final LayoutInflater factory;
195                 if (mInflater != null) {
196                     factory = mInflater;
197                 } else {
198                     factory = LayoutInflater.from(getContext());
199                 }
200                 final View view = factory.inflate(mLayoutResource, parent,
201                         false);
202 
203                 if (mInflatedId != NO_ID) {
204                     view.setId(mInflatedId);
205                 }
206 
207                 final int index = parent.indexOfChild(this);
208                 parent.removeViewInLayout(this);
209 
210                 final ViewGroup.LayoutParams layoutParams = getLayoutParams();
211                 if (layoutParams != null) {
212                     parent.addView(view, index, layoutParams);
213                 } else {
214                     parent.addView(view, index);
215                 }
216 
217                 mInflatedViewRef = new WeakReference<View>(view);
218 
219                 if (mInflateListener != null) {
220                     mInflateListener.onInflate(this, view);
221                 }
222 
223                 return view;
224             } else {
225                 throw new IllegalArgumentException("ViewStub must have a valid layoutResource");
226             }
227         } else {
228             throw new IllegalStateException("ViewStub must have a non-null ViewGroup viewParent");
229         }
230     }
231 
232     /**
233      * Specifies the inflate listener to be notified after this ViewStub successfully
234      * inflated its layout resource.
235      *
236      * @param inflateListener The OnInflateListener to notify of successful inflation.
237      *
238      * @see android.view.ViewStub.OnInflateListener
239      */
setOnInflateListener(OnInflateListener inflateListener)240     public void setOnInflateListener(OnInflateListener inflateListener) {
241         mInflateListener = inflateListener;
242     }
243 
244     /**
245      * Listener used to receive a notification after a ViewStub has successfully
246      * inflated its layout resource.
247      *
248      * @see android.view.ViewStub#setOnInflateListener(android.view.ViewStub.OnInflateListener)
249      */
250     public static interface OnInflateListener {
251         /**
252          * Invoked after a ViewStub successfully inflated its layout resource.
253          * This method is invoked after the inflated view was added to the
254          * hierarchy but before the layout pass.
255          *
256          * @param stub The ViewStub that initiated the inflation.
257          * @param inflated The inflated View.
258          */
onInflate(ViewStubCompat stub, View inflated)259         void onInflate(ViewStubCompat stub, View inflated);
260     }
261 }