Android实际开发问题07------模仿京东列表页控件

京东列表页控件:主要分为两部分,头部和内容部分

     1.当向上滑动时,头部跟着滑动,头部消失的时候,内容部分开始滑动,

     2.当向下滑动时,如果内容页正处于最顶部,则头部也跟着滑动

     3.当内容部分处于中间部分时,向下滑显示头部,向上滑关闭头部

下面部分虽然完成了该部分功能,但是顶部消失过于卡顿,导致情况使用不能像想像的那样,主要是viewGroup如果一旦拦截事件,那么viewGroup里面的view将无法在获取事件,所以只能在dispatchTouchEvent里面进行分发,由于事件触发慢,导致卡顿


public class PullToView extends LinearLayout {

    //顶部视图控件拉动状态
    //隐藏状态
    private static final int HIDE = 1;
    //拖动
    private static final int PULL = 2;
    //展示状态
    private static final int SHOW = 3;


    private Context mContext;

    //头部所处状态
    private int mHeaderState;

    //内容部分状态
    private AdapterView<?> mAdapterView;

    private View mHeaderView;

    private int mHeaderViewHeight;
    private View mContentView;

    //ListView
    private ListView mListView;

    //GridView
    private GridView mGridView;

    private int mLastMotionY;
    private int mIndexMotionY;

    public PullToView(Context context) {
        super(context);
        mContext = context;
    }

    public PullToView(Context context, AttributeSet attrs) {
        super(context, attrs);
        mContext = context;
    }

    public PullToView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        mContext = context;
    }

    @Override
    protected void onFinishInflate() {
        super.onFinishInflate();
        init();
    }

    private void init() {
        int count = getChildCount();
        if (count != 2) {
            throw new IllegalArgumentException("The Layout must contains two views");
        }
        //获取第一个控件
        mHeaderView = getChildAt(0);
        measureView(mHeaderView);
        //获取第一个控件高度
        mHeaderViewHeight = mHeaderView.getMeasuredHeight();

        mContentView = getChildAt(1);
        if (mContentView instanceof ViewGroup) {
            initAdapterView(((ViewGroup) mContentView));
        }
        setmAdapterView(true);
        mHeaderState = SHOW;
    }

    /**
     * 计算控件的高宽
     *
     * @param view
     */
    private void measureView(View view) {
        ViewGroup.LayoutParams params = view.getLayoutParams();
        if (params == null) {
            params = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT
                    , ViewGroup.LayoutParams.WRAP_CONTENT);
        }

        // 获取宽度(外间距,内间距,view的宽度)
        int childWidthSpec = ViewGroup.getChildMeasureSpec(0, 0 + 0, params.width);
        int pHeight = params.height;
        int childHeightSpec;

        //  MeasureSpec 它有三种模式:
        //  UNSPECIFIED(未指定),父元素部队自元素施加任何束缚,子元素可以得到任意想要的大小
        //  EXACTLY(完全),父元素决定自元素的确切大小,子元素将被限定在给定的边界里而忽略它本身大小
        //  AT_MOST(至多),子元素至多达到指定大小的值
        if (pHeight > 0) {
            childHeightSpec = MeasureSpec.makeMeasureSpec(pHeight, MeasureSpec.EXACTLY);
        } else {
            childHeightSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
        }
        view.measure(childWidthSpec, childHeightSpec);
    }

    private void initAdapterView(ViewGroup viewGroup) {
        if (viewGroup == null) {
            return;
        }
        for (int i = 0; i < viewGroup.getChildCount(); i++) {
            View view = viewGroup.getChildAt(i);
            if (view instanceof ListView) {
                mListView = ((ListView) view);
            } else if (view instanceof GridView) {
                mGridView = ((GridView) view);
            } else if (view instanceof ViewGroup) {
                initAdapterView(((ViewGroup) view));
            }
        }
    }


    @Override
    public boolean dispatchTouchEvent(MotionEvent e) {
        int y = (int) e.getRawY();
        switch (e.getAction()) {
            case MotionEvent.ACTION_DOWN:
                mLastMotionY = y;
                mIndexMotionY = y;
                break;
            case MotionEvent.ACTION_MOVE:
                int deltaY = y - mLastMotionY;
                int distance = y - mIndexMotionY;
                changingHeaderViewTopMargin(deltaY, distance);
                mLastMotionY = y;
                break;
            case MotionEvent.ACTION_UP:
            case MotionEvent.ACTION_CANCEL:
                int indexY = y - mIndexMotionY;
                if (indexY <= 0) {
                    changingHeaderViewTopMargin(0, indexY);
                }
                break;

        }
        return super.dispatchTouchEvent(e);
    }

    /**
     * 改变头部距离
     *
     * @param delta
     * @return
     */
    private void changingHeaderViewTopMargin(int delta, int distance) {
        //获取第一个控件高度
        mHeaderViewHeight = mHeaderView.getMeasuredHeight();
        //获取头部的布局属性
        LayoutParams params = (LayoutParams) mHeaderView.getLayoutParams();
        int topMargin = params.topMargin;

        if (delta <= 0) {//上划
            mHeaderViewHeight = mHeaderView.getMeasuredHeight();
            // 如果AdapterView当前第一个可见的位置是数据的第一个,且处于AdapterView顶部
            if (mAdapterView.getFirstVisiblePosition() == 0&& mHeaderState != HIDE) {
                mAdapterView.getChildAt(0).setTop(0);
                mHeaderState = PULL;
                params.topMargin = params.topMargin + delta;
            } else if (distance < -200 && mHeaderState == SHOW) {//当
                mHeaderState = HIDE;
                params.topMargin = -mHeaderViewHeight;
            } else if (mHeaderState == PULL) {
                mHeaderState = HIDE;
                params.topMargin = -mHeaderViewHeight;
            }

            if (mHeaderViewHeight < Math.abs(params.topMargin)) {
                mHeaderState = HIDE;
                params.topMargin = -mHeaderViewHeight;
            }
        } else if (delta > 0) {
            //如果第一个控件展示出了
            int top = mAdapterView.getChildAt(0).getTop();
            if (mAdapterView.getFirstVisiblePosition()==0&&top!=0){
            }else if (mAdapterView.getFirstVisiblePosition() == 0 && mHeaderState != SHOW) {
                params.topMargin = params.topMargin + delta;
                if (mHeaderState == PULL) {
                    mAdapterView.getChildAt(0).setTop(0);
                }
                if (params.topMargin >= 0) {
                    params.topMargin = 0;
                    mHeaderState = SHOW;
                } else if (params.topMargin < 0 && Math.abs(params.topMargin) < mHeaderViewHeight) {
                    mHeaderState = PULL;
                } else {
                    params.topMargin = -mHeaderViewHeight;
                    mHeaderState = HIDE;
                }
            } else if (distance > 200 && mHeaderState == HIDE) {
                if (getAdapterScrollY() > 1000) {
                    params.topMargin = 0;
                    mHeaderState = SHOW;
                }
            }
        }
        if (topMargin != params.topMargin) {
            mHeaderView.setLayoutParams(params);
            invalidate();
        }
    }

    private void setmAdapterView(boolean isListView) {
        if (isListView) {
            mAdapterView = mListView;
        } else {
            mAdapterView = mGridView;
        }
    }

    public int getAdapterScrollY() {
        View c = mAdapterView.getChildAt(0);
        if (c == null) {
            return 0;
        }
        int firstVisiblePosition = mListView.getFirstVisiblePosition();
        int top = c.getTop();
        return -top + firstVisiblePosition * c.getHeight();
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值