上拉查看详情和下拉隐藏详情

项目商品详情页的需求,实现上拉显示和下拉隐藏详情的功能,最终效果图如图:

实现思路:上下通过判断两个ScrollView的滑动位置及触摸事件发生的位置,对他们进行隐藏和显示。
上拉部分,由于内部包裹了大量带有点击事件的组件,故需要在上拉条上进行拖动,否则会冲突无法判断。这部分是通过对其包裹内容动态的调用layout方法来实现拖拽效果;
下拉部分,通过对下拉头动态设置marginTop的值,来改变其高度,并达到隐藏和显示的效果。

核心代码


    //上拉组件
    @Bind(R.id.xscrollview)
    XScrollView mXscrollview;
    @Bind(R.id.scrollContainer)
    LinearLayout scrollContainer;

    //下拉组件
    @Bind(R.id.scrollContainer2)
    RelativeLayout scrollContainer2;
    @Bind(R.id.svBottomDetails)
    ScrollView svBottomDetails;
    @Bind({R.id.llDownScroll})
    LinearLayout llDownScroll;

    //上拉部分
    private Rect rect = null;//记录scrollView包裹组件的位置
    private int fullScroll;//scrollView滚动到底部时ScrollView的scrollY值
    private float mDeltaY;//(上拉模块)拖动的距离
    private int downScrollY;//开始拖动的ScrollView的scrollY值
    private float startY;//开始拖动的MotionEvent的y值

    //下拉部分
    private float startY2;
    private float downScrollY2;
    private float mDeltaY2;
    private boolean touched;//是否触摸,在ACTION_MOVE中做标记,记录按下时需要的值
    private RelativeLayout.LayoutParams mLayoutParams;


    /*******************监听详情的隐藏和显示*******************/

    private OnGoodsDetailsListener mOnGoodsDetailsListener;

    public void setOnGoodsDetailsListener(OnGoodsDetailsListener onGoodsDetailsListener) {
        mOnGoodsDetailsListener = onGoodsDetailsListener;
    }

    public interface OnGoodsDetailsListener{
        void onShow(boolean showDetails);
    }

    //下拉隐藏详情
    private void initPullDown() {
        mLayoutParams = new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);

        svBottomDetails.setOnTouchListener(new View.OnTouchListener() {

            @Override
            public boolean onTouch(View v, MotionEvent event) {
                switch (event.getAction()) {

                    case MotionEvent.ACTION_DOWN:
                        //可能的冲突,改为在ACTION_MOVE中获取
                        break;

                    case MotionEvent.ACTION_UP:

                        //向下拖动距离大于100
                        if (mDeltaY2 > 120 && downScrollY2 == 0) {
                            Log.d(TAG, "onTouch: 隐藏详情了");

                            //显示上部
                            mXscrollview.setVisibility(View.VISIBLE);
                            mXscrollview.smoothScrollTo(0, fullScroll);//滚动到底部
                            //隐藏详情
                            svBottomDetails.setVisibility(View.GONE);

                            //还原标题-->商品 详情 评价
                            //修改返回按键和小箭头的事件->点击结束act
                            //将状态传到activity,改变标题
                            mOnGoodsDetailsListener.onShow(false);
                        }

//                      //恢复原有marginTop高度,隐藏头
                        mLayoutParams.setMargins(0, (int) getResources().getDimension(R.dimen.pulldown_head_margin), 0, 0);
                        llDownScroll.setLayoutParams(mLayoutParams);

                        //重置
                        mDeltaY2 = 0;
                        downScrollY2 = 0;
                        startY2 = 0;
                        touched = false;

                        break;
                    case MotionEvent.ACTION_MOVE:
                        //从顶部开始的滑动,且向下滑

                        //在此记录按下位置,取代ACTION_DOWN中
                        if (!touched) {
                            startY2 = event.getY();
                            downScrollY2 = svBottomDetails.getScrollY();
                            Log.d(TAG, "onTouch: startY2 = " + startY2 + " , downScrollY2 = " + downScrollY2);
                        }
                        touched = true;
                        mDeltaY2 = 0.5f * (event.getY() - startY2);
                        Log.d(TAG, "onTouch: downScrollY2 = " + downScrollY2);
                        Log.d(TAG, "onTouch: startY2 = " + startY2);
                        Log.d(TAG, "onTouch: mDeltaY2 = " + mDeltaY2);

                        if (downScrollY2 == 0 && mDeltaY2 > 0) {
                            //计算marginTop高度,动态显示头高度
                            int top = (int) (-120 + mDeltaY2);
                            Log.d(TAG, "onTouch: marginTop = " + top);
                            mLayoutParams.setMargins(0, top, 0, 0);
                            llDownScroll.setLayoutParams(mLayoutParams);
                        }

                        break;
                    default:
                        break;
                }
                return false;
            }
        });
    }


    /**
     * 上拉查看详情
     */
    private void initPullUp() {

        //这一步操作为,获取ScrollView的完全高度,在上拉时,判断是否从最底部开始
        mXscrollview.setOnScrollToBottomLintener(new XScrollView.OnScrollToBottomListener() {
            @Override
            public void onScrollBottomListener(boolean isBottom) {
                if (isBottom) {
                    fullScroll = mXscrollview.getScrollY();
                    Log.d(TAG, "onScrollBottomListener: scrollY = " + fullScroll);
                }
            }
        });

        mXscrollview.setOnTouchListener(new View.OnTouchListener() {

            @Override
            public boolean onTouch(View v, MotionEvent event) {
                switch (event.getAction()) {

                    case MotionEvent.ACTION_DOWN:
                        //记录按下时的Y值
                        startY = event.getY();
                        downScrollY = mXscrollview.getScrollY();
                        Log.d(TAG, "onTouch: startY = " + startY + " , downScrollY = " + downScrollY);
                        if (rect == null) {
                            rect = new Rect(scrollContainer.getLeft(), scrollContainer.getTop(), scrollContainer.getRight(), scrollContainer.getBottom());
                        }

                        break;

                    case MotionEvent.ACTION_UP:

                        //拖动距离大于120
                        if (Math.abs(mDeltaY) > 120) {
                            Log.d(TAG, "onTouch: 显示详情了");
                            //显示详情
                            svBottomDetails.setVisibility(View.VISIBLE);
                            svBottomDetails.smoothScrollTo(0, 0);
                            //隐藏上部
                            mXscrollview.setVisibility(View.GONE);

                            //改变标题-->图文详情
                            //修改返回按键和小箭头的事件->点击还原
                            //将状态传到activity,改变标题
                            mOnGoodsDetailsListener.onShow(true);
                        }

                        // 恢复原有高度
                        if (rect != null) {
                            scrollContainer.layout(rect.left, rect.top, rect.right, rect.bottom);
                            Log.d(TAG, "onTouch: 松手了");
                        }
                        //重置
                        mDeltaY = 0;
                        downScrollY = 0;
                        startY = 0;
                        break;
                    case MotionEvent.ACTION_MOVE:
                        //downScrollY != 0:不是从顶部开始的滑动;fullScroll不为0且不为负值(bug?)
                        if (downScrollY != 0 && fullScroll > 0 && downScrollY >= fullScroll - 20) {
                            //deltaY<0,向上滑动
                            mDeltaY = 0.5f * (event.getY() - startY);
                            Log.d(TAG, "onTouch: downScrollY = " + downScrollY);
                            Log.d(TAG, "onTouch: fullScroll = " + fullScroll);
                            Log.d(TAG, "onTouch: mDeltaY = " + mDeltaY);
                            if (rect != null) {
                                scrollContainer.layout(rect.left, (int) (rect.top + mDeltaY), rect.right, (int) (rect.bottom + mDeltaY));
                            }
                        }

                        break;
                    default:
                        break;
                }
                return false;
            }
        });

    }

布局文件


<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
                xmlns:app="http://schemas.android.com/apk/res-auto"
                android:id="@+id/rlContainer"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:background="@color/nc_good_bg">

    

    <ScrollView
        android:id="@+id/xscrollview"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_alignParentStart="true"
        android:layout_below="@+id/tvLoading"
        android:visibility="visible">

        <LinearLayout
            android:id="@+id/scrollContainer"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:orientation="vertical">


                

                <LinearLayout
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:layout_marginTop="10dp"
                    android:background="@color/app_white"
                    android:drawableLeft="@drawable/arrow_top"
                    android:gravity="center"
                    android:orientation="horizontal">

                    <ImageView
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:background="@drawable/arrow_top"/>

                    <TextView
                        android:id="@+id/tvUpScroll"
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:background="@color/app_white"
                        android:gravity="center"
                        android:paddingBottom="20dp"
                        android:paddingLeft="4dp"
                        android:paddingTop="20dp"
                        android:text="上拉查看图文详情"/>
                LinearLayout>


        LinearLayout>


    ScrollView>


    <ScrollView
        android:id="@+id/svBottomDetails"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:visibility="gone">

        <RelativeLayout
            android:id="@+id/scrollContainer2"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:visibility="visible">

            
            <LinearLayout
                android:id="@+id/llDownScroll"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_marginTop="@dimen/pulldown_head_margin"
                android:background="@color/app_white"
                android:gravity="center"
                android:orientation="horizontal"
                android:visibility="visible">

                <ImageView
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:background="@drawable/arrow_down"/>

                <TextView
                    android:id="@+id/tvDownScroll"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:background="@color/app_white"
                    android:gravity="center"
                    android:paddingBottom="20dp"
                    android:paddingLeft="4dp"
                    android:paddingTop="20dp"
                    android:text="下拉收起图文详情"/>
            LinearLayout>

            <LinearLayout
                android:id="@+id/llTabs"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_below="@+id/llDownScroll"
                android:background="@color/app_white"
                android:orientation="horizontal"
                android:padding="@dimen/dp8"
                android:visibility="visible">

                

            LinearLayout>

            <WebView
                android:id="@+id/wvImg"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:layout_below="@+id/llTabs"/>


        RelativeLayout>

    ScrollView>

RelativeLayout>

重写的ScrollView,可获取最大滚动高度

//滚动到底部时,clampedY变为true,其余情况为false,通过回调将状态传出去即可。
    @Override
    protected void onOverScrolled(int scrollX, int scrollY, boolean clampedX, boolean clampedY) {
        super.onOverScrolled(scrollX, scrollY, clampedX, clampedY);
        if (scrollY != 0 && null != mOnScrollToBottomListener) {
            mOnScrollToBottomListener.onScrollBottomListener(clampedY);
        }
    }

重写后的ViewPager,可禁止水平滑动

public class MyViewPager extends ViewPager {

    public MyViewPager(Context context) {
        super(context);
    }

    public MyViewPager(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    //默认为true
    private boolean isCanScroll = true;

    //通过设置为false,禁止ViewPager的水平滑动
    public void setCanScroll(boolean isCanScroll) {
        this.isCanScroll = isCanScroll;
    }

    @Override
    public void scrollTo(int x, int y) {
        if (isCanScroll) {
            super.scrollTo(x, y);
        }
    }
}

Activity中控制标题显示

/*******************控制标题显示*********************/
    @Override
    public void onShow(boolean showDetails) {
        this.showDetails = showDetails;
        if (showDetails){
            setCommonHeader("图文详情");
            tabGoods.setVisibility(View.GONE);
            //禁止ViewPager水平滑动
            vpFragment.setCanScroll(false);
        }else {
            setCommonHeader("");
            //显示TabLayout
            tabGoods.setVisibility(View.VISIBLE);
            //恢复ViewPager水平滑动
            vpFragment.setCanScroll(true);
        }
    }

你可能感兴趣的:(安卓组件)