双击回到顶部在Android应用中用的很多,众所周知的微信消息列表,朋友圈都提供这样的效果,下面我将自己自项目中的实践记录下来,分享给大家
首先:获取双击事件
网上有很多的获取双击事件的方法,这里我讲它稍加封装,整个工程也可以使用
首先我们来定义双击事件的接口
- package com.....activity.info;
- import android.view.View;
- /**
- * @author wfy
- * 单击双击事件接口
- */
- public interface OnDoubleClickListener {
- public void OnSingleClick(View v);
- public void OnDoubleClick(View v);
- }
- package com.....activity.info;
- import android.os.Handler;
- import android.os.Message;
- import android.view.View;
- /**
- * @author wfy
- * 消息列表+好友动态的双击回到顶部
- */
- public class DoubleClick {
- public static void registerDoubleClickListener(View view, final OnDoubleClickListener listener){
- if(listener==null) return;
- view.setOnClickListener(new View.OnClickListener() {
- //双击间隔时间350毫秒
- private static final int DOUBLE_CLICK_TIME = 350;
- private boolean flag = true;
- private Handler handler = new Handler(){
- @Override
- public void handleMessage(Message msg) {
- listener.OnSingleClick((View)msg.obj);
- }
- };
- //等待双击
- public void onClick(final View v) {
- if(flag){
- flag = false;//与执行双击事件
- new Thread(){
- public void run() {
- try {
- Thread.sleep(DOUBLE_CLICK_TIME);
- //此时线程沉睡 而flag被修改为false 在DOUBLE_CLICK_TIME内点击则 进入else
- } catch (InterruptedException e) {
- e.printStackTrace();
- } //等待双击时间,否则执行单击事件
- if(!flag){
- //睡醒了看一看flag被人动过没,没有人动,则认作单击事件
- //因此不建议用此方法执行单击事件 因为会等待睡醒,有点击延迟的存在
- //没有人动,自己把它改成true,以接受下次点击
- flag = true;
- Message msg = handler.obtainMessage();
- msg.obj = v;
- //发个消息,让执行单击
- handler.sendMessage(msg);
- }
- }
- }.start();
- }else{
- flag = true;
- listener.OnDoubleClick(v); //执行双击
- }
- }
- });
- }
- }
其次:给你要双击的组件注册双击事件,此处用button演示一下
- Button button=new Button(this);
- DoubleClick.registerDoubleClickListener(button, new OnDoubleClickListener() {
- @Override
- public void OnSingleClick(View v) {
- // TODO Auto-generated method stub
- }
- @Override
- public void OnDoubleClick(View v) {
- // TODO Auto-generated method stub
- GoTopTask task=new GoTopTask();
- task.execute(firstposition);
- }
- });
最后:细心的会发现,在上面的OnDoubleClick方法中我启动了一个异步任务,下面贴出代码,这是一个内部类
- private class GoTopTask extends AsyncTask<Integer, Integer, String>{
- @Override
- protected void onPreExecute() {
- //回到顶部时间置0 此处的时间不是侠义上的时间
- time=0;
- super.onPreExecute();
- }
- @Override
- protected String doInBackground(Integer... params) {
- // TODO Auto-generated method stub
- for(int i=params[0];i>=0;i--){
- publishProgress(i);
- //返回顶部时间耗费15个item还没回去,则直接去顶部
- //目的:要产生滚动的假象,但也不能耗时过多
- time++;
- if(time>15){
- publishProgress(0);
- return null;
- }
- try {
- Thread.sleep(5);
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- }
- return null;
- }
- @Override
- protected void onProgressUpdate(Integer... values) {
- lv.setSelection(values[0]);
- super.onProgressUpdate(values);
- }
- @Override
- protected void onPostExecute(String result) {
- super.onPostExecute(result);
- }
- @Override
- protected void onCancelled() {
- // TODO Auto-generated method stub
- super.onCancelled();
- }
- }
对于第一个问题和第二个问题:我在异步任务里已经做了判断,先一个一个滚,滚到第十五个(也就是异步任务里的time)还没回去则直接回顶部,这样既有了滚动的动作,也不会因为有好多item让用户等待太久
对于第三个问题:首先在当前的activity里定义一个静态的变量,用来持续追踪当前可见的第一个item,然后通过监听lv滚动事件实时修改firstposition,这里贴出代码
- lv.setOnScrollListener(new OnScrollListener() {
- @Override
- public void onScrollStateChanged(AbsListView view, int scrollState) {
- // TODO Auto-generated method stub
- }
- @Override
- public void onScroll(AbsListView view, int firstVisibleItem,
- int visibleItemCount, int totalItemCount) {
- // TODO Auto-generated method stub
- firstposition=firstVisibleItem;
- }
- });