Home | History | Annotate | Download | only in widget
      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.v7.widget;
     18 
     19 import android.content.Context;
     20 import android.support.annotation.NonNull;
     21 import android.support.annotation.Nullable;
     22 import android.support.v4.view.NestedScrollingParent2;
     23 import android.support.v4.view.ViewCompat;
     24 import android.util.AttributeSet;
     25 import android.view.View;
     26 import android.view.ViewGroup;
     27 import android.widget.FrameLayout;
     28 
     29 public class TestedFrameLayout extends FrameLayout implements NestedScrollingParent2 {
     30 
     31     private NestedScrollingParent2 mNestedScrollingDelegate;
     32 
     33     public TestedFrameLayout(Context context) {
     34         super(context);
     35     }
     36 
     37     @Override
     38     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
     39         RecyclerView recyclerView = getRvChild();
     40         if (recyclerView == null) {
     41             super.onMeasure(widthMeasureSpec, heightMeasureSpec);
     42             return;
     43         }
     44         FullControlLayoutParams lp = (FullControlLayoutParams) recyclerView.getLayoutParams();
     45         if (lp.wSpec == null && lp.hSpec == null) {
     46             super.onMeasure(widthMeasureSpec, heightMeasureSpec);
     47             return;
     48         }
     49         final int childWidthMeasureSpec;
     50         if (lp.wSpec != null) {
     51             childWidthMeasureSpec = lp.wSpec;
     52         } else if (lp.width == LayoutParams.MATCH_PARENT) {
     53             final int width = Math.max(0, getMeasuredWidth()
     54                     - lp.leftMargin - lp.rightMargin);
     55             childWidthMeasureSpec = MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY);
     56         } else {
     57             childWidthMeasureSpec = getChildMeasureSpec(widthMeasureSpec,
     58                     lp.leftMargin + lp.rightMargin, lp.width);
     59         }
     60 
     61         final int childHeightMeasureSpec;
     62         if (lp.hSpec != null) {
     63             childHeightMeasureSpec = lp.hSpec;
     64         } else if (lp.height == LayoutParams.MATCH_PARENT) {
     65             final int height = Math.max(0, getMeasuredHeight()
     66                     - lp.topMargin - lp.bottomMargin);
     67             childHeightMeasureSpec = MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY);
     68         } else {
     69             childHeightMeasureSpec = getChildMeasureSpec(heightMeasureSpec,
     70                     lp.topMargin + lp.bottomMargin, lp.height);
     71         }
     72         recyclerView.measure(childWidthMeasureSpec, childHeightMeasureSpec);
     73         if (MeasureSpec.getMode(widthMeasureSpec) == MeasureSpec.EXACTLY &&
     74                 MeasureSpec.getMode(heightMeasureSpec) == MeasureSpec.EXACTLY) {
     75             setMeasuredDimension(
     76                     MeasureSpec.getSize(widthMeasureSpec),
     77                     MeasureSpec.getSize(heightMeasureSpec)
     78             );
     79         } else {
     80             setMeasuredDimension(
     81                     chooseSize(widthMeasureSpec,
     82                             recyclerView.getWidth() + getPaddingLeft() + getPaddingRight(),
     83                             getMinimumWidth()),
     84                     chooseSize(heightMeasureSpec,
     85                             recyclerView.getHeight() + getPaddingTop() + getPaddingBottom(),
     86                             getMinimumHeight()));
     87         }
     88     }
     89 
     90     public static int chooseSize(int spec, int desired, int min) {
     91         final int mode = View.MeasureSpec.getMode(spec);
     92         final int size = View.MeasureSpec.getSize(spec);
     93         switch (mode) {
     94             case View.MeasureSpec.EXACTLY:
     95                 return size;
     96             case View.MeasureSpec.AT_MOST:
     97                 return Math.min(size, desired);
     98             case View.MeasureSpec.UNSPECIFIED:
     99             default:
    100                 return Math.max(desired, min);
    101         }
    102     }
    103 
    104     private RecyclerView getRvChild() {
    105         for (int i = 0; i < getChildCount(); i++) {
    106             if (getChildAt(i) instanceof RecyclerView) {
    107                 return (RecyclerView) getChildAt(i);
    108             }
    109         }
    110         return null;
    111     }
    112 
    113     @Override
    114     protected boolean checkLayoutParams(ViewGroup.LayoutParams p) {
    115         return p instanceof FullControlLayoutParams;
    116     }
    117 
    118     @Override
    119     protected ViewGroup.LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) {
    120         return new FullControlLayoutParams(p);
    121     }
    122 
    123     @Override
    124     public LayoutParams generateLayoutParams(AttributeSet attrs) {
    125         return new FullControlLayoutParams(getContext(), attrs);
    126     }
    127 
    128     @Override
    129     protected LayoutParams generateDefaultLayoutParams() {
    130         return new FullControlLayoutParams(getWidth(), getHeight());
    131     }
    132 
    133     @Override
    134     public boolean onStartNestedScroll(View child, View target, int nestedScrollAxes) {
    135         return onStartNestedScroll(child, target, nestedScrollAxes, ViewCompat.TYPE_TOUCH);
    136     }
    137 
    138     @Override
    139     public void onNestedScrollAccepted(View child, View target, int axes) {
    140         onNestedScrollAccepted(child, target, axes, ViewCompat.TYPE_TOUCH);
    141     }
    142 
    143     @Override
    144     public void onNestedPreScroll(View target, int dx, int dy, int[] consumed) {
    145         onNestedPreScroll(target, dx, dy, consumed, ViewCompat.TYPE_TOUCH);
    146     }
    147 
    148     @Override
    149     public void onNestedScroll(View target, int dxConsumed, int dyConsumed, int dxUnconsumed,
    150             int dyUnconsumed) {
    151         onNestedScroll(target, dxConsumed, dyConsumed, dxUnconsumed, dyUnconsumed,
    152                 ViewCompat.TYPE_TOUCH);
    153     }
    154 
    155     @Override
    156     public void onStopNestedScroll(View target) {
    157         onStopNestedScroll(target, ViewCompat.TYPE_TOUCH);
    158     }
    159 
    160     @Override
    161     public int getNestedScrollAxes() {
    162         return mNestedScrollingDelegate != null
    163                 ? mNestedScrollingDelegate.getNestedScrollAxes()
    164                 : 0;
    165     }
    166 
    167     @Override
    168     public boolean onStartNestedScroll(@NonNull View child, @NonNull View target,
    169             @ViewCompat.ScrollAxis int axes, @ViewCompat.NestedScrollType int type) {
    170         return mNestedScrollingDelegate != null
    171                 && mNestedScrollingDelegate.onStartNestedScroll(child, target, axes, type);
    172     }
    173 
    174     @Override
    175     public void onNestedScrollAccepted(@NonNull View child, @NonNull View target,
    176             @ViewCompat.ScrollAxis int axes, @ViewCompat.NestedScrollType int type) {
    177         if (mNestedScrollingDelegate != null) {
    178             mNestedScrollingDelegate.onNestedScrollAccepted(child, target, axes, type);
    179         }
    180     }
    181 
    182     @Override
    183     public boolean onNestedPreFling(View target, float velocityX, float velocityY) {
    184         return mNestedScrollingDelegate != null
    185                 && mNestedScrollingDelegate.onNestedPreFling(target, velocityX, velocityY);
    186     }
    187 
    188     @Override
    189     public boolean onNestedFling(View target, float velocityX, float velocityY, boolean consumed) {
    190         return mNestedScrollingDelegate != null
    191                 && mNestedScrollingDelegate.onNestedFling(target, velocityX, velocityY, consumed);
    192     }
    193 
    194     @Override
    195     public void onNestedScroll(@NonNull View target, int dxConsumed, int dyConsumed,
    196             int dxUnconsumed, int dyUnconsumed, @ViewCompat.NestedScrollType int type) {
    197         if (mNestedScrollingDelegate != null) {
    198             mNestedScrollingDelegate.onNestedScroll(target, dxConsumed, dyConsumed,
    199                     dxUnconsumed, dyUnconsumed, type);
    200         }
    201     }
    202 
    203     @Override
    204     public void onNestedPreScroll(@NonNull View target, int dx, int dy, @Nullable int[] consumed,
    205             @ViewCompat.NestedScrollType int type) {
    206         if (mNestedScrollingDelegate != null) {
    207             mNestedScrollingDelegate.onNestedPreScroll(target, dx, dy, consumed, type);
    208         }
    209     }
    210 
    211     @Override
    212     public void onStopNestedScroll(@NonNull View target, @ViewCompat.NestedScrollType int type) {
    213         if (mNestedScrollingDelegate != null) {
    214             mNestedScrollingDelegate.onStopNestedScroll(target, type);
    215         }
    216     }
    217 
    218     public void setNestedScrollingDelegate(NestedScrollingParent2 delegate) {
    219         mNestedScrollingDelegate = delegate;
    220     }
    221 
    222     public static class FullControlLayoutParams extends FrameLayout.LayoutParams {
    223 
    224         Integer wSpec;
    225         Integer hSpec;
    226 
    227         public FullControlLayoutParams(Context c, AttributeSet attrs) {
    228             super(c, attrs);
    229         }
    230 
    231         public FullControlLayoutParams(int width, int height) {
    232             super(width, height);
    233         }
    234 
    235         public FullControlLayoutParams(ViewGroup.LayoutParams source) {
    236             super(source);
    237         }
    238 
    239         public FullControlLayoutParams(FrameLayout.LayoutParams source) {
    240             super(source);
    241         }
    242 
    243         public FullControlLayoutParams(MarginLayoutParams source) {
    244             super(source);
    245         }
    246     }
    247 }
    248