• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2015 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.percent;
18 
19 import android.content.Context;
20 import android.content.res.TypedArray;
21 import android.support.annotation.RequiresApi;
22 import android.util.AttributeSet;
23 import android.view.ViewGroup;
24 import android.widget.FrameLayout;
25 
26 /**
27  * Subclass of {@link android.widget.FrameLayout} that supports percentage based dimensions and
28  * margins.
29  *
30  * You can specify dimension or a margin of child by using attributes with "Percent" suffix. Follow
31  * this example:
32  *
33  * <pre class="prettyprint">
34  * &lt;android.support.percent.PercentFrameLayout
35  *         xmlns:android="http://schemas.android.com/apk/res/android"
36  *         xmlns:app="http://schemas.android.com/apk/res-auto"
37  *         android:layout_width="match_parent"
38  *         android:layout_height="match_parent"&gt
39  *     &lt;ImageView
40  *         app:layout_widthPercent="50%"
41  *         app:layout_heightPercent="50%"
42  *         app:layout_marginTopPercent="25%"
43  *         app:layout_marginLeftPercent="25%"/&gt
44  * &lt;/android.support.percent.PercentFrameLayout&gt
45  * </pre>
46  *
47  * The attributes that you can use are:
48  * <ul>
49  *     <li>{@code layout_widthPercent}
50  *     <li>{@code layout_heightPercent}
51  *     <li>{@code layout_marginPercent}
52  *     <li>{@code layout_marginLeftPercent}
53  *     <li>{@code layout_marginTopPercent}
54  *     <li>{@code layout_marginRightPercent}
55  *     <li>{@code layout_marginBottomPercent}
56  *     <li>{@code layout_marginStartPercent}
57  *     <li>{@code layout_marginEndPercent}
58  *     <li>{@code layout_aspectRatio}
59  * </ul>
60  *
61  * It is not necessary to specify {@code layout_width/height} if you specify {@code
62  * layout_widthPercent.} However, if you want the view to be able to take up more space than what
63  * percentage value permits, you can add {@code layout_width/height="wrap_content"}. In that case
64  * if the percentage size is too small for the View's content, it will be resized using
65  * {@code wrap_content} rule.
66  *
67  * <p>
68  * You can also make one dimension be a fraction of the other by setting only width or height and
69  * using {@code layout_aspectRatio} for the second one to be calculated automatically. For
70  * example, if you would like to achieve 16:9 aspect ratio, you can write:
71  * <pre class="prettyprint">
72  *     android:layout_width="300dp"
73  *     app:layout_aspectRatio="178%"
74  * </pre>
75  * This will make the aspect ratio 16:9 (1.78:1) with the width fixed at 300dp and height adjusted
76  * accordingly.
77  *
78  * @deprecated consider using ConstraintLayout and associated layouts instead. The following shows
79  * how to replicate the functionality of percentage layouts with a ConstraintLayout. The Guidelines
80  * are used to define each percentage break point, and then a Button view is stretched to fill
81  * the gap:
82  *
83  * <pre class="prettyprint">
84  * &lt;android.support.constraint.ConstraintLayout
85  *         xmlns:android="http://schemas.android.com/apk/res/android"
86  *         xmlns:app="http://schemas.android.com/apk/res-auto"
87  *         android:layout_width="match_parent"
88  *         android:layout_height="match_parent"&gt
89  *
90  *     &lt;android.support.constraint.Guideline
91  *         android:layout_width="wrap_content"
92  *         android:layout_height="wrap_content"
93  *         android:id="@+id/left_guideline"
94  *         app:layout_constraintGuide_percent=".15"
95  *         android:orientation="vertical"/&gt
96  *
97  *     &lt;android.support.constraint.Guideline
98  *         android:layout_width="wrap_content"
99  *         android:layout_height="wrap_content"
100  *         android:id="@+id/right_guideline"
101  *         app:layout_constraintGuide_percent=".85"
102  *         android:orientation="vertical"/&gt
103  *
104  *     &lt;android.support.constraint.Guideline
105  *         android:layout_width="wrap_content"
106  *         android:layout_height="wrap_content"
107  *         android:id="@+id/top_guideline"
108  *         app:layout_constraintGuide_percent=".15"
109  *         android:orientation="horizontal"/&gt
110  *
111  *     &lt;android.support.constraint.Guideline
112  *         android:layout_width="wrap_content"
113  *         android:layout_height="wrap_content"
114  *         android:id="@+id/bottom_guideline"
115  *         app:layout_constraintGuide_percent=".85"
116  *         android:orientation="horizontal"/&gt
117  *
118  *     &lt;Button
119  *         android:text="Button"
120  *         android:layout_width="0dp"
121  *         android:layout_height="0dp"
122  *         android:id="@+id/button"
123  *         app:layout_constraintLeft_toLeftOf="@+id/left_guideline"
124  *         app:layout_constraintRight_toRightOf="@+id/right_guideline"
125  *         app:layout_constraintTop_toTopOf="@+id/top_guideline"
126  *         app:layout_constraintBottom_toBottomOf="@+id/bottom_guideline" /&gt
127  *
128  * &lt;/android.support.constraint.ConstraintLayout&gt
129  */
130 @Deprecated
131 public class PercentFrameLayout extends FrameLayout {
132     private final PercentLayoutHelper mHelper = new PercentLayoutHelper(this);
133 
PercentFrameLayout(Context context)134     public PercentFrameLayout(Context context) {
135         super(context);
136     }
137 
PercentFrameLayout(Context context, AttributeSet attrs)138     public PercentFrameLayout(Context context, AttributeSet attrs) {
139         super(context, attrs);
140     }
141 
PercentFrameLayout(Context context, AttributeSet attrs, int defStyleAttr)142     public PercentFrameLayout(Context context, AttributeSet attrs, int defStyleAttr) {
143         super(context, attrs, defStyleAttr);
144     }
145 
146     @Override
generateDefaultLayoutParams()147     protected LayoutParams generateDefaultLayoutParams() {
148         return new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
149     }
150 
151     @Override
generateLayoutParams(AttributeSet attrs)152     public LayoutParams generateLayoutParams(AttributeSet attrs) {
153         return new LayoutParams(getContext(), attrs);
154     }
155 
156     @Override
onMeasure(int widthMeasureSpec, int heightMeasureSpec)157     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
158         mHelper.adjustChildren(widthMeasureSpec, heightMeasureSpec);
159         super.onMeasure(widthMeasureSpec, heightMeasureSpec);
160         if (mHelper.handleMeasuredStateTooSmall()) {
161             super.onMeasure(widthMeasureSpec, heightMeasureSpec);
162         }
163     }
164 
165     @Override
onLayout(boolean changed, int left, int top, int right, int bottom)166     protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
167         super.onLayout(changed, left, top, right, bottom);
168         mHelper.restoreOriginalParams();
169     }
170 
171     /**
172      * @deprecated this class is deprecated along with its parent class.
173      */
174     @Deprecated
175     public static class LayoutParams extends FrameLayout.LayoutParams
176             implements PercentLayoutHelper.PercentLayoutParams {
177         private PercentLayoutHelper.PercentLayoutInfo mPercentLayoutInfo;
178 
LayoutParams(Context c, AttributeSet attrs)179         public LayoutParams(Context c, AttributeSet attrs) {
180             super(c, attrs);
181             mPercentLayoutInfo = PercentLayoutHelper.getPercentLayoutInfo(c, attrs);
182         }
183 
LayoutParams(int width, int height)184         public LayoutParams(int width, int height) {
185             super(width, height);
186         }
187 
LayoutParams(int width, int height, int gravity)188         public LayoutParams(int width, int height, int gravity) {
189             super(width, height, gravity);
190         }
191 
LayoutParams(ViewGroup.LayoutParams source)192         public LayoutParams(ViewGroup.LayoutParams source) {
193             super(source);
194         }
195 
LayoutParams(MarginLayoutParams source)196         public LayoutParams(MarginLayoutParams source) {
197             super(source);
198         }
199 
LayoutParams(FrameLayout.LayoutParams source)200         public LayoutParams(FrameLayout.LayoutParams source) {
201             super((MarginLayoutParams) source);
202             gravity = source.gravity;
203         }
204 
205         @RequiresApi(19)
LayoutParams(LayoutParams source)206         public LayoutParams(LayoutParams source) {
207             // The copy constructor used here is only supported on API 19+.
208             this((FrameLayout.LayoutParams) source);
209             mPercentLayoutInfo = source.mPercentLayoutInfo;
210         }
211 
212         @Override
getPercentLayoutInfo()213         public PercentLayoutHelper.PercentLayoutInfo getPercentLayoutInfo() {
214             if (mPercentLayoutInfo == null) {
215                 mPercentLayoutInfo = new PercentLayoutHelper.PercentLayoutInfo();
216             }
217 
218             return mPercentLayoutInfo;
219         }
220 
221         @Override
setBaseAttributes(TypedArray a, int widthAttr, int heightAttr)222         protected void setBaseAttributes(TypedArray a, int widthAttr, int heightAttr) {
223             PercentLayoutHelper.fetchWidthAndHeight(this, a, widthAttr, heightAttr);
224         }
225     }
226 }
227