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