实现标题固定,上滑覆盖标题的效果

前两天实验了一个效果,demo是速卖通app AliExpress 商品详情页面,上滑覆盖顶部ViewPager。

不过在实现的效果略有不同,我设定的是ViewPager是固定页面顶部的,没有不同步滑动的效果。

如果想实现不同步滑动的效果,可以设置viewpager的滑动速度是原来速度的1/3或者其他。


第一步,重写ScrollView,实现三个构造方法,重写onScrollChanged()这个方法。


第二步,创建接口OnScrolledListener:

public interface OnScrolledListener {

    /**
     * ScrollView的滑动事件的回调监听
     * @param y ScrollView的滑动纵坐标
     */
    void scroll(int y);
}

第三步,在重写的ScrollView中初始化OnScrolledListener接口:

private OnScrolledListener listener = new OnScrolledListener() {
        @Override
        public void scroll(int y) {

        }
    };


第四步,在onScrollChanged()这个方法中对接口回调监听:

@Override
protected void onScrollChanged(int l, int t, int oldl, int oldt) {
    listener.scroll(getScrollY());
    super.onScrollChanged(l, t, oldl, oldt);
}


第五步, 重写的ScrollView中添加方法,设置回调监听对象:

public void setListener(OnScrolledListener listener){
    this.listener = listener;
}

第六步,当布局文件xml中使用被重写的ScrollView:

<com.ximoon.corveredtitlescrollview.MyScrollView
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/msv"
    xmlns:android="http://schemas.android.com/apk/res/android">

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content">
    
        <android.support.v4.view.ViewPager
            android:id="@+id/vp"
            android:layout_width="match_parent"
            android:layout_height="200dp"></android.support.v4.view.ViewPager>

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="我是标题"
            android:textSize="20sp"
            android:layout_alignParentLeft="true"
            android:layout_marginLeft="20dp"
            android:layout_alignBottom="@id/vp"/>

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="700dp"
            android:layout_below="@id/vp"
            android:background="@android:color/holo_red_dark"></LinearLayout>

    </RelativeLayout>
    
</com.ximoon.corveredtitlescrollview.MyScrollView>

MyScrollView是刚刚重写的ScrollView,里面包含一个子控件RelativeLayout

(ScrollView的特性,最多含有一个子控件)。

RelativeLayout里面包含三部分,一个就是顶部的ViewPager。

还有一个是TextView,随着滑动,在ViewPager上显示,最后是LinearLayout,是整个滑动区域。


第七步,在Activity内找到控件,并设置回调监听对象,重写滑动事件:

private MyScrollView myScrollView = null;
private ViewPager mViewPager = null;
/** 屏幕宽度*/
public static int DISPLAYW = 0;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    // 测量屏幕的宽度
    DISPLAYW = getResources().getDisplayMetrics().widthPixels;

    setContentView(R.layout.activity_main);

    myScrollView = (MyScrollView) findViewById(R.id.msv);
    mViewPager = (ViewPager) findViewById(R.id.vp);

    // 设置viewpager的宽高一致,为屏幕的宽度(因为嵌套在scrollview中,所以必须重新设置高度)
    mViewPager.setLayoutParams(new RelativeLayout.LayoutParams(DISPLAYW,DISPLAYW));

    myScrollView.setListener(new OnScrolledListener() {
        @Override
        public void scroll(int y) {
            // 若滑动坐标的绝对值即滑动距离不超过viewpager的高度的时候,设置viewpager回滚位置(相当于viewpager滑动的距离是ScrollView滑动距离的相反值,以保持viewpager固定)
            // if ((y < 0 && -y <= DISPLAYW) || (y > 0 && y <= DISPLAYW)) {
                // 因为viewpager是可横向滚动的控件,所以需要按屏计算它的目前滚动宽度,滚动纵坐标即ScrollView的滚动纵坐标的相反值
                mViewPager.scrollTo(mViewPager.getCurrentItem() * DISPLAYW, -y);   // 此处存在一个问题  滑屏到中间位置的时候再滑动viewpager,会导致图片位置出错,可重写viewpager的滑动纠错
            // }
            
        }
    });
    mViewPager.setAdapter(new ImageAdapter());
    mViewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
        @Override
        public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
            // 当viewpager滑动的时候解决viewpager恢复相对于scrollview的坐标造成的显示失误
            myScrollView.scrollTo(0,0);
        }

        @Override
        public void onPageSelected(int position) {

        }

        @Override
        public void onPageScrollStateChanged(int state) {

        }
    });
}
而这句代码:
mViewPager.scrollTo(mViewPager.getCurrentItem() * DISPLAYW, -y);

正常情况下,myScrollView滑动多少距离,myScrollView 内部的控件也应该随之滑动多少距离。

但是由于在ScrollView内,所以获得的相对滑动坐标即getScrollY()为0。

这个时候,我们需要手动设置mViewPager相对myScrollView的相对滑动纵坐标。

意思表示,当myScrollView向上或者向下滑动到y坐标的时候,mViewPager则向相反方向滑动相同的距离。

所以滑动纵坐标为-y。参数y是通过myScrollView.getScrollY()获得的mScrollY返回过来,

所以通过scrollTo()方法就可以滑动到坐标指示位置。

横坐标就更简单了,因为mViewPager相当于一个横向的ScrollView,

所以它也有一个滑动坐标,但是是横向的,每一屏都对应着不同的横坐标。

myScrollView滑动的时候,如果设置滑动横坐标为0。

mViewPager.scrollTo(0,-y),那么造成的后果就是当mViewPager不在position=0的位置的时候,

myScrollView的滑动会促使mViewPager回到position为0的位置。

添加mViewPager滑动的监听事件,并在onPageScrolled()方法中设置myScrollView的滑动事件。

此方法可另类解决当myScrollView滑动到mViewPager的中间位置时再滑动myScrollView,

造成mViewPager的相对滑动纵坐标出现问题,

导致mViewPager的底部出现在可滑动区域的上方,而mViewPager只显示下半部分的错误。



github地址:点击打开链接

发布了23 篇原创文章 · 获赞 10 · 访问量 5万+

猜你喜欢

转载自blog.csdn.net/byxyrq/article/details/49532273