package com.example.test;
import android.content.Context;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.ViewConfiguration;
import android.widget.GridView;
import android.widget.LinearLayout;
public class HeadGridView extends LinearLayout{
    private static final String TAG = HeadGridView.class.getSimpleName();
    private LinearLayout mHeadLayout;
    private GridView mGridView;
    private int mHeadHeight;
    private boolean mIsBeingDragged;
    private float mLastMotionY;
    private float mTouchSlop;
    private boolean mGridViewFocused = true;
    private State mState = State.getDefaultMode();
    public HeadGridView(Context context) {
        this(context, null);
    }
    public HeadGridView(Context context, AttributeSet attrs) {
        super(context, attrs);
        initContentView(context);
    }
    
    private void initContentView(Context context) {
        ViewConfiguration config = ViewConfiguration.get(context);
        mTouchSlop = config.getScaledTouchSlop();
        setOrientation(VERTICAL);
        GridView gridView = new GridView(context);
        LayoutParams gridParams = new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT);
        gridView.setNumColumns(2);
        gridView.setLayoutParams(gridParams);
        mGridView = gridView;
        initGridView(gridView);
        addView(gridView);
        
        LinearLayout headLayout = new LinearLayout(context);
        LayoutParams headParams = new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT);
        headLayout.setLayoutParams(headParams);
        mHeadLayout = headLayout;
        initHead(headLayout);
        addView(headLayout,0);
    }
    
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        int parentWidth = MeasureSpec.getSize(widthMeasureSpec);
        int parentHeight = MeasureSpec.getSize(heightMeasureSpec);
        int gridWidthSpec = MeasureSpec.makeMeasureSpec(parentWidth, MeasureSpec.EXACTLY);
        int gridHeightSpec = MeasureSpec.makeMeasureSpec(parentHeight, MeasureSpec.EXACTLY);
        mGridView.measure(gridWidthSpec, gridHeightSpec);
        setMeasuredDimension(parentWidth, parentHeight);
    }
    
    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        super.onLayout(changed, l, t, r, b);
        mHeadHeight = getChildAt(0).getMeasuredHeight();
    }
    
    protected void initGridView(GridView gridView) {
        
    }
    protected void initHead(LinearLayout headLayout) {
    }
    
    @Override
    public final boolean onInterceptTouchEvent(MotionEvent event) {
        Log.d(TAG, "currentState = "+mState+" event = "+event.getAction()+" mIsBeingDragged = "+mIsBeingDragged);
        final int action = event.getAction();
        
        if (action == MotionEvent.ACTION_CANCEL || action == MotionEvent.ACTION_UP) {
            mIsBeingDragged = false;
            return false;
        }
        if (mIsBeingDragged) {
            return true;
        }
        switch (action) {
            case MotionEvent.ACTION_MOVE:
                final float y = event.getY();
                final float absDiff = Math.abs(y - mLastMotionY);;
                if (absDiff > mTouchSlop) {
                    mLastMotionY = y;
                    mIsBeingDragged = true;
                    if (mState != State.Head_Visible) {
                        mGridViewFocused = false;
                    }
                }
                break;
            case MotionEvent.ACTION_DOWN:
                mLastMotionY = event.getY();
                mIsBeingDragged = false;
                break;
            default:
                break;
        }
        return mIsBeingDragged;
    }
    
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        
        if (event.getAction() == MotionEvent.ACTION_DOWN && event.getEdgeFlags() != 0) {
            return false;
        }
        
        switch (event.getAction()) {
            case MotionEvent.ACTION_MOVE: {
                if (mIsBeingDragged) {
                    pullEvent(event);
                    return true;
                }
                break;
            }
            case MotionEvent.ACTION_DOWN: 
                mLastMotionY = event.getY();
                return true;
            case MotionEvent.ACTION_CANCEL:
            case MotionEvent.ACTION_UP: 
                if (mIsBeingDragged) {
                    mIsBeingDragged = false;
                }
                return true;
        }
        return false;
    }
    
    private void dispatchDownToGridView(MotionEvent e, float downY) {
        int action = e.getAction();
        MotionEvent de = MotionEvent.obtain(e);
        de.setLocation(de.getX(), downY);
        de.setAction(MotionEvent.ACTION_DOWN);
        mGridView.dispatchTouchEvent(de);
        e.setAction(action);
    }
    
    private void pullEvent(MotionEvent e) {
        if (!mGridViewFocused) {
            dispatchDownToGridView(e, mLastMotionY);
            mGridViewFocused = true;
        }
        
        float y = e.getY();
        int scrollValue = Math.round(mLastMotionY - y);
        if (mState == State.Bottom_Top) {
            if (scrollValue > 0){
                if (mState == State.Bottom_Top) {
                    dispatchDownToGridView(e, mLastMotionY);
                }
                mGridView.dispatchTouchEvent(e);
                mState = State.Bottom_Medium;
            } else {
                mState = State.Head_Visible;
            }
        }
        
        if (mState.canHeadViewScroll()) {
            int currentScrollY = getScrollY();
            int maxScroolY = mHeadHeight - currentScrollY;
            if (scrollValue > 0) { //向上滑动
                if (maxScroolY < scrollValue) {
                    scrollValue = maxScroolY;
                    mState = State.Bottom_Top;
                }
                scrollBy(0, scrollValue);
            } else { //向下滑动
                if (currentScrollY > 0) {
                    if (currentScrollY < - scrollValue) {
                        scrollValue = - currentScrollY;
                    }
                    scrollBy(0, scrollValue);
                }
            }
        } else {
            mGridView.dispatchTouchEvent(e);
            if (scrollValue < 0) {
                int top = mGridView.getChildAt(0).getTop();
                if (top == 0) {
                    mState = State.Bottom_Top;
                }
            }
        }
        mLastMotionY = y;
    }
    
    public static enum State{
        Head_Visible(0x01),
        Bottom_Top(0x02),
        Bottom_Bottom(0x03),
        Bottom_Medium(0x04);
        
        private int id;
        
        private State(int id) {
            this.id = id;
        }
        
        public int getId(){
            return id;
        }
        
        public static State getDefaultMode(){
            return State.Head_Visible;
        }
        
        static State mapState(final int id) {
            for (State value : State.values()) {
                if (id == value.getId()) {
                    return value;
                }
            }
            return getDefaultMode();
        }
        
        boolean canHeadViewScroll() {
            return this == Head_Visible || this == Bottom_Top;
        }
    }
}
简单实现,目前还有些许问题,后续可参考:https://android.googlesource.com/platform/packages/apps/Gallery2/+/idea133/src/com/android/photos/views/HeaderGridView.java
 
  
  
  
 
 
  
 
 
 