参考:
RecyclerView的滚动事件分析
判断view能否上滑
listview的分页
android - 标题栏随ScrollView滚动变色(仿知乎)
ViewPager的setOnPageChangeListener方法详解
一、ListView的滚动监听
布局:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.example.lenovo.myscrolltest.MainActivity">
<ListView
android:id="@+id/lv"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:entries="@array/sports" />
</LinearLayout>
res/values/arrays:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string-array name="sports">
<item>1</item>
<item>2</item>
<item>3</item>
<item>4</item>
<item>5</item>
<item>6</item>
<item>7</item>
<item>8</item>
<item>9</item>
<item>10</item>
<item>11</item>
<item>12</item>
<item>13</item>
<item>14</item>
<item>15</item>
<item>16</item>
<item>17</item>
<item>18</item>
<item>19</item>
<item>20</item>
<item>21</item>
<item>22</item>
<item>23</item>
<item>24</item>
<item>25</item>
<item>26</item>
<item>27</item>
<item>28</item>
<item>29</item>
<item>30</item>
</string-array>
</resources>
测试MainActivity
public class MainActivity extends AppCompatActivity {
private ListView mLv;
@SuppressLint("NewApi")
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mLv = ((ListView) this.findViewById(R.id.lv));
//滚动位移的监听
mLv.setOnScrollChangeListener(new View.OnScrollChangeListener() {
@Override
public void onScrollChange(View v, int scrollX, int scrollY, int oldScrollX, int oldScrollY) {
//ListView无水平滑动,scrollX和oldScrollX均为零
// Log.e("333333", "scrollX==" + scrollX);
// Log.e("333333", "oldScrollX====" + oldScrollX);
Log.e("333333", "scrollY==" + scrollY);
Log.e("333333", "oldScrollY===" + oldScrollY);
Log.e("333333", "v instanceof ListView===" + (v instanceof ListView));
Log.e("333333", "============================================");
}
});
//滚动状态和位置监听
mLv.setOnScrollListener(new AbsListView.OnScrollListener() {
/**
* 监听着ListView的滑动状态改变
* @param view
* @param scrollState
*/
@Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
switch (scrollState) {
//页面正被用户拖拽(手指未离开)
case SCROLL_STATE_TOUCH_SCROLL:
Log.e("222222", "111===SCROLL_STATE_TOUCH_SCROLL===");
break;
//页面自行滑动,有动画效果(手指已离开):
//如果手指拖动离开后页面也停止,则不会调用,除非离开后页面还有惯性滑动
case SCROLL_STATE_FLING:
Log.e("222222", "222===SCROLL_STATE_FLING===");
break;
//页面停滞,无动画效果
case SCROLL_STATE_IDLE:
Log.e("222222", "333===SCROLL_STATE_IDLE===");
break;
}
}
/**
* 监听滑动位置
* @param view
* @param firstVisibleItem
* @param visibleItemCount
* @param totalItemCount
*/
@Override
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
//firstVisibleItem和view.getFirstVisiblePosition()的值相同,表示第一个看到的item位置,半个也算
Log.e("111111", "===firstVisibleItem==" + firstVisibleItem);//0
Log.e("111111", "===getFirstVisiblePosition==" + view.getFirstVisiblePosition());//0
//visibleItemCount==ListView可见的item总数,半个也算
Log.e("111111", "===visibleItemCount==" + visibleItemCount);//11
//totalItemCount==ListView的全部item总数(包括可见+不可见)
Log.e("111111", "===totalItemCount==" + totalItemCount);//30
//表示最后看到的item位置,半个也算
Log.e("111111", "===getLastVisiblePosition==" + view.getLastVisiblePosition());//10
//判断是否到了底部
boolean isBottom = (firstVisibleItem + visibleItemCount) == totalItemCount;//19 + 11 == 30
Log.e("111111", "===isBottom=====" + isBottom);
Log.e("111111", "============================================");
}
});
}
/**
* 下拉刷新时,判断控件是否可以上滑
* 1、API大于等于14:调用canScrollVertically,当direction>0时,判断是否可以下滑,当direction<0时,判断是否可以上滑
* 2、API小于14:自己判断
*
* @param view
* @return
*/
public boolean canChildScrollUp(View view) {
if (android.os.Build.VERSION.SDK_INT < 14) {
if (view instanceof AbsListView) {
final AbsListView absListView = (AbsListView) view;
return absListView.getChildCount() > 0
&& (absListView.getFirstVisiblePosition() > 0 || absListView.getChildAt(0).getTop() < absListView.getPaddingTop());
} else {
return view.getScrollY() > 0;
}
} else {
return view.canScrollVertically(-1);
}
}
}
注意:
canScrollVertically,当direction>0时,判断是否可以下滑,当direction<0时,判断是否可以上滑
二、ScrollView的滚动监听:
自定义带滚动监听的ScrollView
/**
* 带滚动监听的ScrollView
*
*/
public class ObservableScrollView extends ScrollView {
public interface ScrollViewListener {
void onScrollChanged(ObservableScrollView scrollView, int x, int y, int oldx, int oldy);
}
private ScrollViewListener scrollViewListener = null;
public ObservableScrollView(Context context) {
super(context);
}
public ObservableScrollView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
public ObservableScrollView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public void setScrollViewListener(ScrollViewListener scrollViewListener) {
this.scrollViewListener = scrollViewListener;
}
@Override
protected void onScrollChanged(int x, int y, int oldx, int oldy) {
super.onScrollChanged(x, y, oldx, oldy);
if (scrollViewListener != null) {
scrollViewListener.onScrollChanged(this, x, y, oldx, oldy);
}
}
}
布局:
<?xml version="1.0" encoding="utf-8"?>
<com.example.lenovo.myscrolltest.ObservableScrollView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/scrollView"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:padding="5dp"
android:text="1"
android:textColor="#ff0000"
android:textSize="25sp" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:padding="5dp"
android:text="2"
android:textColor="#ff0000"
android:textSize="25sp" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:padding="5dp"
android:text="3"
android:textColor="#ff0000"
android:textSize="25sp" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:padding="5dp"
android:text="4"
android:textColor="#ff0000"
android:textSize="25sp" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:padding="5dp"
android:text="5"
android:textColor="#ff0000"
android:textSize="25sp" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:padding="5dp"
android:text="6"
android:textColor="#ff0000"
android:textSize="25sp" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:padding="5dp"
android:text="7"
android:textColor="#ff0000"
android:textSize="25sp" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:padding="5dp"
android:text="8"
android:textColor="#ff0000"
android:textSize="25sp" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:padding="5dp"
android:text="9"
android:textColor="#ff0000"
android:textSize="25sp" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:padding="5dp"
android:text="10"
android:textColor="#ff0000"
android:textSize="25sp" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:padding="5dp"
android:text="11"
android:textColor="#ff0000"
android:textSize="25sp" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:padding="5dp"
android:text="12"
android:textColor="#ff0000"
android:textSize="25sp" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:padding="5dp"
android:text="13"
android:textColor="#ff0000"
android:textSize="25sp" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:padding="5dp"
android:text="14"
android:textColor="#ff0000"
android:textSize="25sp" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:padding="5dp"
android:text="15"
android:textColor="#ff0000"
android:textSize="25sp" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:padding="5dp"
android:text="16"
android:textColor="#ff0000"
android:textSize="25sp" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:padding="5dp"
android:text="17"
android:textColor="#ff0000"
android:textSize="25sp" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:padding="5dp"
android:text="18"
android:textColor="#ff0000"
android:textSize="25sp" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:padding="5dp"
android:text="19"
android:textColor="#ff0000"
android:textSize="25sp" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:padding="5dp"
android:text="20"
android:textColor="#ff0000"
android:textSize="25sp" />
</LinearLayout>
</com.example.lenovo.myscrolltest.ObservableScrollView>
测试MainActivityI
public class MainActivityI extends AppCompatActivity {
private ListView mLv;
private ObservableScrollView scrollview;
@SuppressLint("NewApi")
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_maini);
//一般View都有滚动监听,比如:RecyclerView,ListView
RecyclerView recyclerView = new RecyclerView(this);
recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
@Override
public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
super.onScrollStateChanged(recyclerView, newState);
}
//dy > 0 时为向上滚动
//dy < 0 时为向下滚动
@Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
}
});
//表示是否滚动到顶部,当direction>0时,判断是否可以下滑,当direction<0时,判断是否可以上滑
recyclerView.canScrollVertically(-1);//View的内部方法
ListView listView = new ListView(this);
listView.setOnScrollChangeListener(new View.OnScrollChangeListener() {
@Override
public void onScrollChange(View v, int scrollX, int scrollY, int oldScrollX, int oldScrollY) {
}
});
//表示是否滚动到顶部,当direction>0时,判断是否可以下滑,当direction<0时,判断是否可以上滑
listView.canScrollVertically(-1);//View的内部方法
//ScrollView需要自己定义滚动监听
scrollview = ((ObservableScrollView) this.findViewById(R.id.scrollView));
scrollview.setOnScrollChangeListener(new View.OnScrollChangeListener() {
@Override
public void onScrollChange(View v, int scrollX, int scrollY, int oldScrollX, int oldScrollY) {
//水平无滚动,均为0
// Log.e("000000", "111scrollX==" + scrollX);
// Log.e("000000", "111oldScrollX==" + oldScrollX);
// Log.e("000000", "111scrollX-oldScrollX==" + (scrollX - oldScrollX));
//竖直滚动:scrollY为滚动的当前绝对位置,oldScrollY为上次滚动停止时的绝对位置
Log.e("000000", "222scrollY==" + scrollY);
Log.e("000000", "222oldScrollY==" + oldScrollY);
//差值不为零表示有滚动操作,大于0上滑,小于0下滑
Log.e("000000", "222scrollY-oldScrollY==" + (scrollY - oldScrollY));
// Log.e("000000", "v instanceof ScrollView==" + (v instanceof ScrollView));
Log.e("000000", "======================================================");
}
});
}
}
注意:
//竖直滚动:
scrollY为滚动的当前绝对位置,起始为0
oldScrollY为上次滚动停止时的绝对位置
//差值不为零表示有滚动操作,大于0上滑,小于0下滑
dx = scrollX-oldScrollX
dy = scrollY-oldScrollY
打印log如下:
898 222scrollY==73
898 222oldScrollY==0
898 222scrollY-oldScrollY==73
915 222scrollY==281
915 222oldScrollY==73
915 222scrollY-oldScrollY==208
931 222scrollY==482
932 222oldScrollY==281
932 222scrollY-oldScrollY==201
948 222scrollY==665
948 222oldScrollY==482
948 222scrollY-oldScrollY==183
962 222scrollY==758
962 222oldScrollY==665
962 222scrollY-oldScrollY==93
965 222scrollY==796
965 222oldScrollY==758
965 222scrollY-oldScrollY==38
965 222scrollY==796
965 222oldScrollY==758
965 222scrollY-oldScrollY==38
982 222scrollY==1009
982 222oldScrollY==796
982 222scrollY-oldScrollY==213
982 222scrollY==1009
982 222oldScrollY==796
982 222scrollY-oldScrollY==213
999 222scrollY==1066
999 222oldScrollY==1009
999 222scrollY-oldScrollY==57
999 222scrollY==1066
999 222oldScrollY==1009
999 222scrollY-oldScrollY==57
033 222scrollY==1065
033 222oldScrollY==1066
033 222scrollY-oldScrollY==-1
033 222scrollY==1065
033 222oldScrollY==1066
033 222scrollY-oldScrollY==-1
050 222scrollY==1063
050 222oldScrollY==1065
050 222scrollY-oldScrollY==-2
050 222scrollY==1063
050 222oldScrollY==1065
050 222scrollY-oldScrollY==-2