Android ListView监听上下滑动(判断是否显示返回顶部按钮)

在有些listview上面和ScrollView上,当滑动到底部的时候,在右下角会出现一个回到顶部的按钮,提供更好的用户体验。

效果图如下:

Android ListView监听上下滑动(判断是否显示返回顶部按钮)


布局 

先说布局,可以用帧布局Framelayout,也可以用相对布局relativelayout.看下listview的布局文件:

<RelativeLayout 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"
    android:background="@android:color/white" >

    <ListView
        android:id="@+id/my_listView"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:layout_marginLeft="10dp"
        android:layout_marginRight="10dp" />

    <Button
        android:id="@+id/top_btn"
        android:layout_width="50dp"
        android:layout_height="50dp"
        android:visibility="gone"
        android:layout_alignParentBottom="true"
        android:layout_alignParentRight="true"
        android:layout_marginBottom="6dp"
        android:layout_marginRight="6dp"
        android:background="@drawable/top_btn_bg"
        android:gravity="center"
        android:text="顶" />

</RelativeLayout>

Listview 回到顶部的活动代码 
是从网上找到的代码,作者为:zihao 
/**
 * 主界面
 * 
 * @author zihao
 * @details 因为有些手机是有虚拟按键的(在计算屏幕分辨率的时候,有些可以去除掉虚拟区域的区域->如三星,有些不行->如MX3),为了计算的准确性,
 *          各位可以设置Activity为Theme
 *          .NoTitleBar.Fullscreen填满屏幕(解决类似MX3这种在计算过程中把虚拟键盘算入屏幕高度的)。
 */
public class ListActivity extends Activity implements OnClickListener {

	private ListView listView;// List数据列表
	private Button toTopBtn;// 返回顶部的按钮
	private MyAdapter adapter;
	private boolean scrollFlag = false;// 标记是否滑动
	private int lastVisibleItemPosition = 0;// 标记上次滑动位置

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_list);

		initView();
	}

	/**
	 * 初始化视图
	 */
	private void initView() {
		listView = (ListView) findViewById(R.id.my_listView);
		toTopBtn = (Button) findViewById(R.id.top_btn);

		adapter = new MyAdapter(this, getTitleDatas());
		listView.setAdapter(adapter);

		toTopBtn.setOnClickListener(this);
		listView.setOnScrollListener(new OnScrollListener() {

			@Override
			public void onScrollStateChanged(AbsListView view, int scrollState) {
				// TODO Auto-generated method stub
				switch (scrollState) {
				// 当不滚动时
				case OnScrollListener.SCROLL_STATE_IDLE:// 是当屏幕停止滚动时
					scrollFlag = false;
					// 判断滚动到底部
					if (listView.getLastVisiblePosition() == (listView
							.getCount() - 1)) {
						toTopBtn.setVisibility(View.VISIBLE);
					}
					// 判断滚动到顶部
					if (listView.getFirstVisiblePosition() == 0) {
						toTopBtn.setVisibility(View.GONE);
					}

					break;
				case OnScrollListener.SCROLL_STATE_TOUCH_SCROLL:// 滚动时
					scrollFlag = true;
					break;
				case OnScrollListener.SCROLL_STATE_FLING:// 是当用户由于之前划动屏幕并抬起手指,屏幕产生惯性滑动时
					scrollFlag = false;
					break;
				}
			}

			/**
			 * firstVisibleItem:当前能看见的第一个列表项ID(从0开始)
			 * visibleItemCount:当前能看见的列表项个数(小半个也算) totalItemCount:列表项共数
			 */
			@Override
			public void onScroll(AbsListView view, int firstVisibleItem,
					int visibleItemCount, int totalItemCount) {
				// 当开始滑动且ListView底部的Y轴点超出屏幕最大范围时,显示或隐藏顶部按钮
				if (scrollFlag
						&& ScreenUtil.getScreenViewBottomHeight(listView) >= ScreenUtil
								.getScreenHeight(ListActivity.this)) {
					if (firstVisibleItem > lastVisibleItemPosition) {// 上滑
						toTopBtn.setVisibility(View.VISIBLE);
					} else if (firstVisibleItem < lastVisibleItemPosition) {// 下滑
						toTopBtn.setVisibility(View.GONE);
					} else {
						return;
					}
					lastVisibleItemPosition = firstVisibleItem;
				}
			}
		});
	}

	/**
	 * 获取标题数据列表
	 * 
	 * @return
	 */
	private List<String> getTitleDatas() {
		List<String> titleArray = new ArrayList<String>();
		for (int i = 0; i < 30; i++) {
			titleArray.add("这是第" + i + "个item");
		}
		return titleArray;
	}

	/**
	 * 滚动ListView到指定位置
	 * 
	 * @param pos
	 */
	private void setListViewPos(int pos) {
		if (android.os.Build.VERSION.SDK_INT >= 8) {
			listView.smoothScrollToPosition(pos);
		} else {
			listView.setSelection(pos);
		}
	}

	@Override
	public void onClick(View v) {
		// TODO Auto-generated method stub
		switch (v.getId()) {
		case R.id.top_btn:// 点击按钮返回到ListView的第一项
			setListViewPos(0);
			break;
		}
	}

}

在上面的代码中,对listview 设置 setOnScrollListener 监听;当有一点滑动(也可以提供一个值)或者是到达底部的时候就出现回到顶部的按钮。 

scrollview的代码 

有很多知识点:

  1. scrollview的滑动停止监听。
  2. scrollview回到顶部,或者底部的方法。
  3. scrollview到达顶部或者底部的判断方法。

上面的参考连接也都写在注释里面了。

public class ScrollViewActivity extends Activity implements OnClickListener {

	private ScrollView scrollView;// scrollView数据列表
	private Button toTopBtn;// 返回顶部的按钮


	private int scrollY = 0;// 标记上次滑动位置

	private View contentView;

	private final String TAG="test";
	
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_scroll);

		initView();
	}

	/**
	 * 初始化视图
	 */
	private void initView() {
		scrollView = (ScrollView) findViewById(R.id.my_scrollView);
		if (contentView == null) {
			contentView = scrollView.getChildAt(0);
		}

		toTopBtn = (Button) findViewById(R.id.top_btn);
		toTopBtn.setOnClickListener(this);

		//http://blog.csdn.net/jiangwei0910410003/article/details/17024287
		/******************** 监听ScrollView滑动停止 *****************************/
		scrollView.setOnTouchListener(new OnTouchListener() {
			private int lastY = 0;
			private int touchEventId = -9983761;
			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()) {
							handleStop(scroller);
						} else {
							handler.sendMessageDelayed(handler.obtainMessage(
									touchEventId, scroller), 5);
							lastY = scroller.getScrollY();
						}
					}
				}
			};

			public boolean onTouch(View v, MotionEvent event) {
				if (event.getAction() == MotionEvent.ACTION_UP) {
					handler.sendMessageDelayed(
							handler.obtainMessage(touchEventId, v), 5);
				}
				return false;
			}

			/**
			 * ScrollView 停止
			 * 
			 * @param view
			 */
			private void handleStop(Object view) {
			
			    Log.i(TAG,"handleStop");
				ScrollView scroller = (ScrollView) view;
				scrollY = scroller.getScrollY();

				doOnBorderListener();
			}
		});
		/***********************************************************/

	}

	/**
	 * ScrollView 的顶部,底部判断:
	 * http://www.trinea.cn/android/on-bottom-load-more-scrollview-impl/
	 * 
	 * 其中getChildAt表示得到ScrollView的child View, 因为ScrollView只允许一个child
	 * view,所以contentView.getMeasuredHeight()表示得到子View的高度,
	 * getScrollY()表示得到y轴的滚动距离,getHeight()为scrollView的高度。
	 * 当getScrollY()达到最大时加上scrollView的高度就的就等于它内容的高度了啊~
	 * 
	 * @param pos
	 */
	private void doOnBorderListener() {
		Log.i(TAG,ScreenUtil.getScreenViewBottomHeight(scrollView) + "  "
				+ scrollView.getScrollY()+" "+ ScreenUtil
				.getScreenHeight(ScrollViewActivity.this));
		
		
		// 底部判断
		if (contentView != null
				&& contentView.getMeasuredHeight() <= scrollView.getScrollY()
						+ scrollView.getHeight()) {
			toTopBtn.setVisibility(View.VISIBLE);
			Log.i(TAG,"bottom");
		}
		// 顶部判断
		else if (scrollView.getScrollY() == 0) {
			
			Log.i(TAG,"top");
		}

		else if (scrollView.getScrollY() > 30) {
			toTopBtn.setVisibility(View.VISIBLE);
			Log.i(TAG,"test");
		}

	}

	/**
	 * 下面我们看一下这个函数: scrollView.fullScroll(ScrollView.FOCUS_DOWN);滚动到底部
	 * scrollView.fullScroll(ScrollView.FOCUS_UP);滚动到顶部
	 * 
	 * 
	 * 需要注意的是,该方法不能直接被调用 因为Android很多函数都是基于消息队列来同步,所以需要一部操作,
	 * addView完之后,不等于马上就会显示,而是在队列中等待处理,虽然很快, 但是如果立即调用fullScroll,
	 * view可能还没有显示出来,所以会失败 应该通过handler在新线程中更新
	 * 
	 * http://blog.csdn.net/t12x3456/article/details/12799825
	 * http://www.tuicool.com/articles/zayIjq
	 */
	@Override
	public void onClick(View v) {
		// TODO Auto-generated method stub
		switch (v.getId()) {
			case R.id.top_btn :
				scrollView.post(new Runnable() {
					@Override
					public void run() {
						scrollView.fullScroll(ScrollView.FOCUS_UP);
					}
				});
				toTopBtn.setVisibility(View.GONE);
				break;
		}
	}

}

很多细节都注释在代码里面了,参考链接也已经加上。大家下载下代码执行一下看看。

代码http://download.csdn.net/detail/jjdhshdahhdd/9059757
上一篇:深入JUnit源码之Assert与Hamcrest


下一篇:加载一张图片到ImageView到底占据多少内存