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