android 自定义Scrollview实现淘宝二层楼效果新版微信小程序下拉效果

android 自定义Scrollview实现淘宝二层楼效果新版微信小程序下拉效果

由于最近一段时间真的是太忙了,没有顾上即使更新博客,还请粉丝们见谅,最近要实现这样一个效果,这个效果跟淘宝二层楼和新版微信7.0的下拉小程序效果差不多,百般查找真心没有找到自己合适的,没办法只能自撸了,来看效果。

来,二话不说了,直接上代码吧。

import android.content.Context;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ScrollView;
import android.widget.Scroller;

/**
 * Created by zhaoshaohe on 2019.4.1
 */
public class StickyScrollView extends ScrollView {
    public static final String TAG = StickyScrollView.class.getSimpleName();
    public static final int PAGE_TOP = 0;
    public static final int PAGE_BOTTOM = 1;
    public static final double PERCENT = 0.4;
    public static final int ANIMATION_DURATION = 180;
    public static final int TOUCH_DURATION = 150;

    private ViewGroup mChildLayout;
    private View mTopChildView;

    private Context mContext;
    private OnPageChangeListener onPageChangeListener;

    private boolean isScrollAuto;           //判断是否自由滚动
    private Scroller mScroller;             //滑动类
    private int screenHeight;               //屏幕高度
    private int offsetDistance;             //topview的高度与屏幕的高度差
    private int topChildHeight;             //topview的高度
    private boolean isTouch;                //用户是否在触控屏幕
    private int currentPage;                //值为0时屏幕显示topview,值为1时屏幕显示bottomview
    private long downTime;                  //用户按下屏幕的时间戳
    private long upTime;                    //用户抬起时的时间戳
    private int downY;                      //用户按下屏幕的y坐标
    private int upY;                        //用户抬起的y坐标
    private boolean isPageChange;           //页面是否切换

    public StickyScrollView(Context context) {
        super(context);
        this.mContext = context;
    }

    public StickyScrollView(Context context, AttributeSet attrs) {
        super(context, attrs);
        this.mContext = context;
    }

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

    public void setOnPageChangeListener(OnPageChangeListener onPageChangeListener) {
        this.onPageChangeListener = onPageChangeListener;
    }

    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        super.onLayout(changed, l, t, r, b);

        mChildLayout = (ViewGroup) getChildAt(0);
        mTopChildView = mChildLayout.getChildAt(0);
        topChildHeight = mTopChildView.getMeasuredHeight();
        screenHeight = getMeasuredHeight();
        offsetDistance = topChildHeight - screenHeight;
    }

    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        switch (ev.getAction()) {
            case MotionEvent.ACTION_DOWN:
                isTouch = true;
                downY = (int) ev.getY();
                downTime = System.currentTimeMillis();
                if (mScroller != null) {
                    mScroller.forceFinished(true);
                    mScroller = null;
                }
                break;
            case MotionEvent.ACTION_MOVE:
                break;
            case MotionEvent.ACTION_UP:
                isTouch = false;
                upY = (int) ev.getY();
                upTime = System.currentTimeMillis();
                //用户手指在屏幕上的时间
                long duration = upTime - downTime;

                //这里要确保点击事件不失效
                if (Math.abs(upY - downY) > 50) {
                    Log.e(TAG, ">>>ISN_T CLICK:" + Math.abs(upY - downY));
                    if (currentPage == PAGE_TOP) {
                        //下面的判断已经能确定用户是否往上滑
                        if (getScrollY() > offsetDistance) {
                            mScroller = new Scroller(mContext);
                            if (getScrollY() < (screenHeight * PERCENT + offsetDistance) && duration > TOUCH_DURATION) {
                                isPageChange = false;
                                scrollToTarget(PAGE_TOP);
                            } else {
                                //切换到下界面
                                isPageChange = true;
                                isScrollAuto = duration < TOUCH_DURATION ? true : false;
                                scrollToTarget(PAGE_BOTTOM);
                                currentPage = PAGE_BOTTOM;
                            }
                            return false;
                        }
                    } else {
                        if (getScrollY() < topChildHeight) {
                            mScroller = new Scroller(mContext);
                            if (getScrollY() < (topChildHeight - screenHeight * PERCENT) || duration < TOUCH_DURATION) {
                                //切换到上界面
                                isPageChange = true;
                                isScrollAuto = duration < TOUCH_DURATION ? true : false;
                                scrollToTarget(PAGE_TOP);
                                currentPage = PAGE_TOP;
                            } else {
                                isPageChange = false;
                                scrollToTarget(PAGE_BOTTOM);
                            }
                            return false;
                        }
                    }
                }
                break;
        }
        return super.dispatchTouchEvent(ev);
    }

    /**
     * 滚动到指定位置
     */
    private void scrollToTarget(int currentPage) {
        int delta;
        if (currentPage == PAGE_TOP) {
            delta = getScrollY() - offsetDistance;
            mScroller.startScroll(0, getScrollY(), 0, -delta, isScrollAuto == true ? ANIMATION_DURATION : (int) (Math.abs(delta) * 0.4));
        } else if (currentPage == PAGE_BOTTOM) {
            delta = getScrollY() - topChildHeight;
            mScroller.startScroll(0, getScrollY(), 0, -delta, isScrollAuto == true ? ANIMATION_DURATION : (int) (Math.abs(delta) * 0.4));
        }
        postInvalidate();
    }

    @Override
    public void computeScroll() {
        // 调用startScroll的时候scroller.computeScrollOffset()返回true
        super.computeScroll();
        if (mScroller == null) {
            return;
        }
        if (mScroller.computeScrollOffset()) {
            this.scrollTo(mScroller.getCurrX(), mScroller.getCurrY());
            postInvalidate();
            if (mScroller.isFinished()) {
                mScroller = null;
                if (onPageChangeListener != null && isPageChange) onPageChangeListener.OnPageChange(currentPage);
            }
        }
    }


    @Override
    protected void onScrollChanged(int l, int t, int oldl, int oldt) {
        super.onScrollChanged(l, t, oldl, oldt);
        //滚动时的监听,当用户触屏滑动时不监听,t == getScrollY
        if (currentPage == PAGE_TOP) {
            if (getScrollY() > offsetDistance && !isTouch) {
                if (mScroller == null) {
                    //用于控制当滑动到分界线时停止滚动
                    scrollTo(0, offsetDistance);
                } else {
                    scrollToTarget(PAGE_TOP);
                }
            }
        } else if (currentPage == PAGE_BOTTOM) {
            if (getScrollY() < topChildHeight && !isTouch) {
                if (mScroller == null) {
                    scrollTo(0, topChildHeight);
                } else {
                    scrollToTarget(PAGE_BOTTOM);
                }
            }
        }
    }

    /**
     * 切换页面完成后的回调
     */
    public interface OnPageChangeListener {
        void OnPageChange(int currentPage);
    }

}

这是自定义的粘性StickyScrollview,主要逻辑都在这儿了。

来看如何使用:

<com.example.zsh.scrollview_demo.StickyScrollView xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/sticky_scroll"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:scrollbars="none">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical">

        <!-- child_0 -->
        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:gravity="center"
            android:orientation="vertical">

            <ImageView
                android:id="@+id/item_1"
                android:clickable="true"
                android:layout_width="match_parent"
                android:layout_height="200dp"
                android:layout_marginTop="2dp"
                android:scaleType="centerCrop"
                android:src="@mipmap/ic_launcher" />


            <ImageView
                android:id="@+id/item_2"
                android:clickable="true"
                android:layout_width="match_parent"
                android:layout_height="200dp"
                android:layout_marginTop="2dp"
                android:scaleType="centerCrop"
                android:background="@mipmap/ic_launcher" />


            <ImageView
                android:id="@+id/item_3"
                android:clickable="true"
                android:layout_width="match_parent"
                android:layout_height="200dp"
                android:layout_marginTop="2dp"
                android:scaleType="centerCrop"
                android:background="@mipmap/ic_launcher" />

            <ImageView
                android:id="@+id/item_4"
                android:clickable="true"
                android:layout_width="match_parent"
                android:layout_height="200dp"
                android:layout_marginTop="2dp"
                android:scaleType="centerCrop"
                android:background="@mipmap/ic_launcher" />

            <ImageView
                android:id="@+id/item_5"
                android:clickable="true"
                android:layout_width="match_parent"
                android:layout_height="200dp"
                android:layout_marginTop="2dp"
                android:layout_marginBottom="2dp"
                android:scaleType="centerCrop"
                android:background="@mipmap/ic_launcher"  />


        </LinearLayout>


        <!-- child_1 -->
        <ScrollView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:scrollbars="vertical">

            <LinearLayout
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:gravity="center"
                android:orientation="vertical">

                <!-- divider -->
                <TextView
                    android:layout_width="match_parent"
                    android:layout_height="30dp"
                    android:gravity="center"
                    android:textColor="@android:color/white"
                    android:textSize="16sp"
                    android:text="Divider"
                    android:background="#00AA50"/>

                <ImageView
                    android:id="@+id/item_6"
                    android:clickable="true"
                    android:layout_width="match_parent"
                    android:layout_height="200dp"
                    android:layout_marginTop="2dp"
                    android:scaleType="centerCrop"
                    android:background="@color/colorAccent" />


                <ImageView
                    android:id="@+id/item_7"
                    android:clickable="true"
                    android:layout_width="match_parent"
                    android:layout_height="200dp"
                    android:layout_marginTop="2dp"
                    android:scaleType="centerCrop"
                    android:background="@color/colorAccent"/>


                <ImageView
                    android:id="@+id/item_8"
                    android:clickable="true"
                    android:layout_width="match_parent"
                    android:layout_height="200dp"
                    android:layout_marginTop="2dp"
                    android:scaleType="centerCrop"
                   android:background="@color/colorAccent" />

                <ImageView
                    android:id="@+id/item_9"
                    android:clickable="true"
                    android:layout_width="match_parent"
                    android:layout_height="200dp"
                    android:layout_marginTop="2dp"
                    android:scaleType="centerCrop"
                    android:background="@color/colorAccent" />


                <ImageView
                    android:id="@+id/item_10"
                    android:clickable="true"
                    android:layout_width="match_parent"
                    android:layout_height="200dp"
                    android:layout_marginTop="2dp"
                    android:scaleType="centerCrop"
                    android:background="@color/colorAccent" />

            </LinearLayout>

        </ScrollView>

    </LinearLayout>


</com.example.zsh.scrollview_demo.StickyScrollView>

再来看MainActivity,

package com.example.zsh.scrollview_demo;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.ImageView;
import android.widget.Toast;

public class MainActivity extends AppCompatActivity implements View.OnClickListener, StickyScrollView.OnPageChangeListener {
    public static final String TAG = MainActivity.class.getSimpleName();

    private ImageView ImageItem1;
    private ImageView ImageItem2;
    private ImageView ImageItem3;
    private ImageView ImageItem4;
    private ImageView ImageItem5;
    private ImageView ImageItem6;
    private ImageView ImageItem7;
    private ImageView ImageItem8;
    private ImageView ImageItem9;
    private ImageView ImageItem10;

    private StickyScrollView stickyScrollView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        stickyScrollView = (StickyScrollView) findViewById(R.id.sticky_scroll);
        stickyScrollView.setOnPageChangeListener(this);

        ImageItem1 = (ImageView) findViewById(R.id.item_1);
        ImageItem2 = (ImageView) findViewById(R.id.item_2);
        ImageItem3 = (ImageView) findViewById(R.id.item_3);
        ImageItem4 = (ImageView) findViewById(R.id.item_4);
        ImageItem5 = (ImageView) findViewById(R.id.item_5);
        ImageItem6 = (ImageView) findViewById(R.id.item_6);
        ImageItem7 = (ImageView) findViewById(R.id.item_7);
        ImageItem8 = (ImageView) findViewById(R.id.item_8);
        ImageItem9 = (ImageView) findViewById(R.id.item_9);
        ImageItem10 = (ImageView) findViewById(R.id.item_10);

        ImageItem1.setOnClickListener(this);
        ImageItem2.setOnClickListener(this);
        ImageItem3.setOnClickListener(this);
        ImageItem4.setOnClickListener(this);
        ImageItem5.setOnClickListener(this);
        ImageItem6.setOnClickListener(this);
        ImageItem7.setOnClickListener(this);
        ImageItem8.setOnClickListener(this);
        ImageItem9.setOnClickListener(this);
        ImageItem10.setOnClickListener(this);

    }

    @Override
    public void onClick(View v) {
        Log.e(TAG, ">>>onClick");
        switch (v.getId()) {
            case R.id.item_1:
                Log.e(TAG, ">>>item_1");
                Toast.makeText(this, "IMAGE_1", Toast.LENGTH_SHORT).show();
                break;
            case R.id.item_2:
                Log.e(TAG, ">>>item_2");
                Toast.makeText(this, "IMAGE_2", Toast.LENGTH_SHORT).show();
                break;
            case R.id.item_3:
                Log.e(TAG, ">>>item_3");
                Toast.makeText(this, "IMAGE_3", Toast.LENGTH_SHORT).show();
                break;
            case R.id.item_4:
                Log.e(TAG, ">>>item_4");
                Toast.makeText(this, "IMAGE_4", Toast.LENGTH_SHORT).show();
                break;
            case R.id.item_5:
                Log.e(TAG, ">>>item_5");
                Toast.makeText(this, "IMAGE_5", Toast.LENGTH_SHORT).show();
                break;
            case R.id.item_6:
                Log.e(TAG, ">>>item_6");
                Toast.makeText(this, "IMAGE_6", Toast.LENGTH_SHORT).show();
                break;
            case R.id.item_7:
                Log.e(TAG, ">>>item_7");
                Toast.makeText(this, "IMAGE_7", Toast.LENGTH_SHORT).show();
                break;
            case R.id.item_8:
                Log.e(TAG, ">>>item_8");
                Toast.makeText(this, "IMAGE_8", Toast.LENGTH_SHORT).show();
                break;
            case R.id.item_9:
                Log.e(TAG, ">>>item_9");
                Toast.makeText(this, "IMAGE_9", Toast.LENGTH_SHORT).show();
                break;
            case R.id.item_10:
                Log.e(TAG, ">>>item_10");
                Toast.makeText(this, "IMAGE_10", Toast.LENGTH_SHORT).show();
                break;
        }
    }

    @Override
    public void OnPageChange(int currentPage) {
        Log.e(TAG, ">>>OnPageChange");
        switch (currentPage) {
            case StickyScrollView.PAGE_TOP:
                Toast.makeText(this, "CHANGE_TO_TOP", Toast.LENGTH_SHORT).show();
                break;
            case StickyScrollView.PAGE_BOTTOM:
                Toast.makeText(this, "CHANGE_TO_BOTTOM", Toast.LENGTH_SHORT).show();
                break;
        }
    }
}

好了,这样一个效果就做出来了。可能还会有小瑕疵,后续再慢慢调。欢迎大家使用,哈哈,我要去忙了。。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值