Android 各种 滚动View 监听 和各种判断

总结下各种View 的滑动监听

滑动阈值:int touchSlop = ViewConfiguration.get(this).getScaledTouchSlop();

getMeasuredHeight()是实际View的大小,与屏幕无关,而getHeight的大小此时则是屏幕的大小。

当超出屏幕后, getMeasuredHeight() 等于 getHeight()加上屏幕之外没有显示的大小

滚动到顶部判断:
getScrollY() == 0


滚动到底部判断:
View childView = getChildAt(0);

childView.getMeasuredHeight() <= getScrollY() + getHeight();

其中getChildAt表示得到ScrollView的child View
childView.getMeasuredHeight()表示得到子View的高度,

 getScrollY()表示得到y轴的滚动距离,

getHeight()为scrollView可见的高度即屏幕的高度
getScrollY()达到最大时加上scrollView的高度就的就等于它内容的高度了.

ScroolView:

回到顶部:

一、ScrollView.scrollTo(0,0)  直接置顶,瞬间回到顶部,没有滚动过程,其中Y值可以设置为大于0的值,使Scrollview停在指定位置;

二、ScrollView.fullScroll(View.FOCUS_UP)  类似于手动拖回顶部,有滚动过程;   需要post 新开线程

三、ScrollView.smoothScrollTo(0, 0) 类似于手动拖回顶部,有滚动过程,其中Y值可以设置为大于0的值,使Scrollview停在指定位置。
判断滑动位置的地方,可以有两种方式:

1、实现OnTouchListener来监听

OnTouchListener onTouchListener=new OnTouchListener(){  
            @Override  
            public boolean onTouch(View v, MotionEvent event) { 
                switch (event.getAction()) {
                    case MotionEvent.ACTION_UP:
                        if (childView  != null && childView .getMeasuredHeight() <= getScrollY() + getHeight()) {
                        // 滑动到底部
                        } else if (getScrollY() == 0) {
                        // 滑动到顶部  貌似不好用
                        //看下面listview 判断 第一个子view 的getTop
                        }
                    break;
                }
                return false;
            }
 } 

2、重写ScrollView的onScrollChanged的方法,在onScrollChanged函数中判断


public class myScrollView extends ScrollView
{
    public myScrollView(Context context)
    {
        super(context);
    }
    public myScrollView(Context context, AttributeSet attributeSet)
    {
        super(context,attributeSet);
    }
 
    @Override
    protected void onScrollChanged(int l, int t, int oldl, int oldt)
    {
        View view = (View)getChildAt(getChildCount()-1);
        int d = view.getBottom();
        d -= (getHeight()+getScrollY());
        if(d==0)
        {
            //you are at the end of the list in scrollview 
            //do what you wanna do here
        }
        else
            super.onScrollChanged(l,t,oldl,oldt);
    }
}

判断是否在顶部  在滚动停止后:

 private int lastY = 0;
        private int touchEventId = -9983761;

        @SuppressLint("HandlerLeak")
        Handler handler = new Handler(){
            @Override
            public void handleMessage(Message msg) {
                super.handleMessage(msg);
                View scroller = (View) msg.obj;

                if (msg.what == touchEventId) {
                    if (lastY == scroller.getScrollY()) {
                        //停止了,此处你的操作业务
                        if (scroller.getScrollY() == 0) {
                            hidePopup();
                        }
                    } else {
                        handler.sendMessageDelayed(handler.obtainMessage(touchEventId, scroller), 1);
                        lastY = scroller.getScrollY();
                    }
                }
            }
        };
  case MotionEvent.ACTION_CANCEL:
                    if (type == SCROLLVIEW) {
//                        hidePopup(); 从整个Messge池中返回一个新的Message实例 降低内存的开销 避免分配新的对象
                        handler.sendMessageDelayed(handler.obtainMessage(touchEventId, v), 300);
                    }
                    break;

 

判断滑动方向:

1. onTouch 监听

package com.example.testtt;
import android.app.Activity;
import android.os.Bundle;
import android.view.MotionEvent;
import android.widget.Toast;
public class MainActivity extends Activity {
  //手指按下的点为(x1, y1)手指离开屏幕的点为(x2, y2)
  float x1 = 0;
  float x2 = 0;
  float y1 = 0;
  float y2 = 0;
 
  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
  }
 
  @Override
  public boolean onTouchEvent(MotionEvent event) {
    //继承了Activity的onTouchEvent方法,直接监听点击事件
    if(event.getAction() == MotionEvent.ACTION_DOWN) {
      //当手指按下的时候
      x1 = event.getX();
      y1 = event.getY();
    }
    if(event.getAction() == MotionEvent.ACTION_UP) {
      //当手指离开的时候
      x2 = event.getX();
      y2 = event.getY();
      if(y1 - y2 > 50) {
        Toast.makeText(MainActivity.this, "向上滑", Toast.LENGTH_SHORT).show();
      } else if(y2 - y1 > 50) {
        Toast.makeText(MainActivity.this, "向下滑", Toast.LENGTH_SHORT).show();
      } else if(x1 - x2 > 50) {
        Toast.makeText(MainActivity.this, "向左滑", Toast.LENGTH_SHORT).show();
      } else if(x2 - x1 > 50) {
        Toast.makeText(MainActivity.this, "向右滑", Toast.LENGTH_SHORT).show();
      }
    }
    return super.onTouchEvent(event);
  }
 
 
}

2. 继承SrcoolView 

/使用自定义view继承自ScrollView
public class MyScrollView extends ScrollView {

    private OnScrollListener listener;

    public void setOnScrollListener(OnScrollListener listener) {
        this.listener = listener;
    }

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

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

    public MyScrollView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    //设置接口
    public interface OnScrollListener{
        void onScroll(int scrollY);
    }

    //重写原生onScrollChanged方法,将参数传递给接口,由接口传递出去
    @Override
    protected void onScrollChanged(int l, int t, int oldl, int oldt) {
        super.onScrollChanged(l, t, oldl, oldt);
        if(listener != null){

            //这里我只传了垂直滑动的距离
            listener.onScroll(t);
        }
    }
}

 //1. 第一个参数是目前水平滑动后的距离    
 //2. 第二个参数是目前垂直滑动后的距离    
 //3. 第三个参数是之前水平滑动前的距离
 //4. 第四个参数是之前水平滑动前的距离

ListView 和GridView 监听

移动到顶部底部:

listview.setSelection(position);   

gridview.smoothScrollToPosition(position);  带动画   post新开线程

需要在新线程使用

滚动监听:

 private AbsListView.OnScrollListener LIST_GRID_LISTENER = new AbsListView.OnScrollListener() {
        @Override
        public void onScrollStateChanged(AbsListView view, int scrollState) {
            switch (scrollState) {
                case SCROLL_STATE_FLING:
                    break;
                case SCROLL_STATE_IDLE:
                    // 判断滚动到顶部
                    if (mListView.getFirstVisiblePosition() == 0) {
                        View firstVisibleItemView = view.getChildAt(0);
                        if (firstVisibleItemView != null && firstVisibleItemView.getTop() == 0) {
                            
                        }
                    }
                    break;
                case SCROLL_STATE_TOUCH_SCROLL:
                    
                    break;
            }
        }

        @Override
        public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
            if (firstVisibleItem == 0) {
                
              //顶部  不够准确
            }
        }
    };

ScroolState 三种状态

  • OnScrollListener.SCROLL_STATE_IDLE:滚动停止时的状态
  • OnScrollListener.SCROLL_STATE_STOUCH_SCROLL:触摸正在滚动,手指还没离开界面时的状态
  • OnScrollListener.SCROLL_STATE_FLING:用户在用力滑动后,ListView由于惯性将继续滑动时的状态
     

onScroll 介绍

  • firstVisibleItem:当前能看见的第一个item的ID(从0开始
  • visibleItemCount:当前可见的item总数
  • totalItemCount:列表中适配器总数量,也就是整个ListView中item总数

滑动方向:

  • firstVisibleItem > oldVisibleItem   // 向上滑动
  • firstVisibleItem < oldVisibleItem  // 向下滑动

判断顶部底部

  • firstVisibleItem + visibleItemCount == totalItemCount    //底部
  • firstVisibleItem=0  顶部     
  • 在onScrollStateChanged中判断
  • mListView.getLastVisiblePosition() == (mListView.getCount() - 1)  //底部
  • mListView.getFirstVisiblePosition() == 0   //顶部

ListView也为我们提供了一些封装好了的方法,来获取item的位置信息 

// 获取当前可见区域内第一个item            mListView.getFirstVisiblePosition();

 // 获取当前可见区域内最后一个item       mListView.getLastVisiblePosition();

 

RecyclerView :

移动:

RecyclerView提供了几种移动的方法

scrollToPosition       这个方法的作用是定位到指定项,就是把你想显示的项显示出来,但是在屏幕的什么位置是不管的,只要那一项现在看得到了,那它就罢工了!

scrollTo

scrollBy   这个方法是自己去控制移动的距离,单位是像素,所以在使用scrollBy(x, y)需要自己去计算移动的高度或宽度。

smoothScrollBy    

smoothScrollToPosition      惯性滑动至某一位置

scrollToPositionWithOffset   用法:((LinearLayoutManager)recyclerView.getLayoutManager()).scrollToPositionWithOffset(position,0);

该置顶就置顶

判断 顶部 底部
方法一:

垂直判断:

mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {

            @Override
            public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
                super.onScrolled(recyclerView, dx, dy);
                Log.i(TAG, "--------------------------------------");
                if(mRecyclerView.canScrollVertically(1)){
                    Log.i(TAG, "direction 1: true");
                }else {
                    Log.i(TAG, "direction 1: false");//滑动到底部
                }
                if(mRecyclerView.canScrollVertically(-1)){
                    Log.i(TAG, "direction -1: true");
                }else {
                    Log.i(TAG, "direction -1: false");//滑动到顶部
                }
            }
        });

横向:

/**
     * Check if this view can be scrolled horizontally in a certain direction.
     *
     * @param direction Negative to check scrolling left, positive to check scrolling right.
     * @return true if this view can be scrolled in the specified direction, false otherwise.
     */
    public boolean canScrollHorizontally(int direction) {
        final int offset = computeHorizontalScrollOffset();
        final int range = computeHorizontalScrollRange() - computeHorizontalScrollExtent();
        if (range == 0) return false;
        if (direction < 0) {
            return offset > 0;
        } else {
            return offset < range - 1;
        }
    }

判断是否滑动到底部, recyclerView.canScrollVertically(1);返回false表示不能往上滑动,即代表到底部了;

判断是否滑动到顶部, recyclerView.canScrollVertically(-1);返回false表示不能往下滑动,即代表到顶部了;

方法二:
 

mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {

            @Override
            public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
                super.onScrolled(recyclerView, dx, dy);
                Log.i(TAG, "--------------------------------------");
                LinearLayoutManager layoutManager = (LinearLayoutManager) recyclerView.getLayoutManager();
                int firstCompletelyVisibleItemPosition = layoutManager.findFirstCompletelyVisibleItemPosition();
                Log.i(TAG, "firstCompletelyVisibleItemPosition: "+firstCompletelyVisibleItemPosition);
                if(firstCompletelyVisibleItemPosition==0)
                    Log.i(TAG, "滑动到顶部");

                int lastCompletelyVisibleItemPosition = layoutManager.findLastCompletelyVisibleItemPosition();
                Log.i(TAG, "lastCompletelyVisibleItemPosition: "+lastCompletelyVisibleItemPosition);
                if(lastCompletelyVisibleItemPosition==layoutManager.getItemCount()-1)
                    Log.i(TAG, "滑动到底部");
            }
        });

滑动方向:

//dy <0 表示 上滑, dy>0 表示下滑

三种状态:

/**
 * The RecyclerView is not currently scrolling.
 * 当前的recycleView不滑动(滑动已经停止时)
 */
public static final int SCROLL_STATE_IDLE = 0;

/**
 * The RecyclerView is currently being dragged by outside input such as user touch input.
 * 当前的recycleView被拖动滑动
 */
public static final int SCROLL_STATE_DRAGGING = 1;

/**
 * The RecyclerView is currently animating to a final position while not under
 * outside control.
 * 当前的recycleView在滚动到某个位置的动画过程,但没有被触摸滚动.调用 scrollToPosition(int) 应该会触发这个状态
 */
public static final int SCROLL_STATE_SETTLING = 2;

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值