onInterceptTouchEvent、onTouchEvent、GestureDetector、SimpleOnGestureListener
2016-01-07 02:24
489 查看
一:Activity
public class AppointActivity extends BaseActivity implements AppointTabbarView.IAppointTabbarItemCheckedListener, PullToRefreshView.OnHeaderRefreshListener, PullToRefreshView.OnFooterRefreshListener{ public static final int APPOINT_SUCCESS = 0; public static final int APPOINT_DONE = 1; public static final int APPOINT_CANCEL = 2; private int type=APPOINT_SUCCESS; private AppointTabbarView tabbarView; private PullToRefreshView mPullToRefreshView; private IphoneTreeView treeView; private AppointManageAdapter adapter; private List<BookingUserGroupVO> userGroupVOs; private TextView tv_setting_hint; private int index = 0; private GestureDetector detector; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.appoint_manage); initView(); initHint(); initPatientList(index); initGestureDetector(); } private void initHint() { boolean isNotFirst = PreferenceHelper.getBoolean(this, PreferenceHelper.APPOINT_SETTING_HINT_IS_FIRST_LOAD, PreferenceHelper.APP_CONFIGURE_NAME); if (!isNotFirst) { tv_setting_hint.setVisibility(View.VISIBLE); PreferenceHelper.setBooleanParam(this, PreferenceHelper.APPOINT_SETTING_HINT_IS_FIRST_LOAD, true, PreferenceHelper.APP_CONFIGURE_NAME); }else { tv_setting_hint.setVisibility(View.GONE); } } private void initView(){ initTitleView(R.string.appoint_manage, getString(R.string.setting), true, this); tv_setting_hint = (TextView) findViewById(R.id.tv_setting_hint); tabbarView = (AppointTabbarView) findViewById(R.id.tabbar); tabbarView.setListener(this); userGroupVOs = new ArrayList<BookingUserGroupVO>(); mPullToRefreshView = (PullToRefreshView) findViewById(R.id.main_pull_refresh_view); treeView = (IphoneTreeView) findViewById(R.id.appoint_list); mPullToRefreshView.setOnHeaderRefreshListener(this); mPullToRefreshView.setOnFooterRefreshListener(this); View head = LayoutInflater.from(this).inflate(R.layout.appoint_group_head, null); treeView.setHeaderView(head, Utils.dip2px(this, 38)); adapter = new AppointManageAdapter(this,userGroupVOs); treeView.setAdapter(adapter); } private void initGestureDetector(){ detector = new GestureDetector(AppointActivity.this,new GestureDetector.SimpleOnGestureListener(){ @Override public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) { /** * 用户按下的动作已经在mPullToRefreshView的onInterceptTouchEvent方法中消费掉了,所以这里e1是null,需要从 * mPullToRefreshView中获取用户按下去时的x值 */ //从左向右滑动 if((e2.getRawX()-mPullToRefreshView.getmLastMotionX())>310){ if(index == 0){ index = 1; tabbarView.setSomeOneChecked(index); initPatientList(index); return true; } if(index == 1){ index = 2; tabbarView.setSomeOneChecked(index); initPatientList(index); } } //从右向左滑动 if((mPullToRefreshView.getmLastMotionX()-e2.getRawX())>310){ if(index == 2){ index = 1; tabbarView.setSomeOneChecked(index); initPatientList(index); return true; } if(index == 1){ index = 0; tabbarView.setSomeOneChecked(index); initPatientList(index); } } return super.onFling(e1, e2, velocityX, velocityY); } }); } private void initPatientList(int index) { if(StringUtils.isEmpty(Utils.getTokenFromDataBase(this))) { return; } TokenRequestParams params=new TokenRequestParams(this); if(index == 0){ params.put("type", "1"); } if(index == 1){ params.put("type", "2"); } if(index == 2){ params.put("type", "3"); } NetRequest.doGetArray(this, true, params, UrlConstants.APPOINT_GET_USER_LIST, new IRequestJSONArraySuccessListener() { @Override public void handle(JSONArray data) { List<BookingUserVO> list = GsonFactory.getNewInstance().fromJson(data.toString(), new TypeToken<List<BookingUserVO>>() { }.getType()); if(list!=null && list.size()>0){ showPatientList(list); } } }); } private void showPatientList(List<BookingUserVO> list){ userGroupVOs.clear(); Set<String> dateSet = new TreeSet<String>(); for(int i=0;i<list.size();i++){ list.get(i).setDate(DateUtil.getDate(list.get(i).getStart()*1000)); dateSet.add(list.get(i).getDate()); } for(String date:dateSet){ List<BookingUserVO> userVOs = new ArrayList<BookingUserVO>(); for(int k=0;k<list.size();k++){ if(list.get(k).getDate().equals(date)){ userVOs.add(list.get(k)); } } BookingUserGroupVO userGroupVO = new BookingUserGroupVO(); userGroupVO.setDate(date); userGroupVO.setUserList(userVOs); userGroupVOs.add(userGroupVO); } notifyDataSetChanged(); } private void notifyDataSetChanged(){ adapter = new AppointManageAdapter(AppointActivity.this,userGroupVOs); treeView.setAdapter(adapter); adapter.notifyDataSetChanged(); } @Override public void onFooterRefresh(PullToRefreshView view) { mPullToRefreshView.postDelayed(new Runnable() { @Override public void run() { mPullToRefreshView.onFooterRefreshComplete(); } }, 1000); } SimpleDateFormat sdf = new SimpleDateFormat("MM-dd HH:mm:ss"); @Override public void onHeaderRefresh(PullToRefreshView view) { mPullToRefreshView.postDelayed(new Runnable() { @Override public void run() { String time = sdf.format(new Date()); mPullToRefreshView.onHeaderRefreshComplete("更新于:"+time); // mPullToRefreshView.onHeaderRefreshComplete(); } }, 1000); } @Override public void tabbarItemChecked(int index) { Log.i("yin","按钮的索引:"+index); this.index = index; initPatientList(index); } @Override public void onClick(View v) { super.onClick(v); if (v.getId() == R.id.title_menu) { Utils.startActivity(this, AppointSettingsActivity.class); } } @Override public boolean onTouchEvent(MotionEvent event) { if(event == null){ Log.i("yin","触摸了null"); }else { Log.i("yin","没有触摸null"); } detector.onTouchEvent(event); return super.onTouchEvent(event); } }
其中上面的关键代码是:
private void initGestureDetector(){ detector = new GestureDetector(AppointActivity.this,new GestureDetector.SimpleOnGestureListener(){ @Override public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) { /** * 用户按下的动作已经在mPullToRefreshView的onInterceptTouchEvent方法中消费掉了,所以这里e1是null,需要从 * mPullToRefreshView中获取用户按下去时的x值 */ //从左向右滑动 if((e2.getRawX()-mPullToRefreshView.getmLastMotionX())>310){ if(index == 0){ index = 1; tabbarView.setSomeOneChecked(index); initPatientList(index); return true; } if(index == 1){ index = 2; tabbarView.setSomeOneChecked(index); initPatientList(index); } } //从右向左滑动 if((mPullToRefreshView.getmLastMotionX()-e2.getRawX())>310){ if(index == 2){ index = 1; tabbarView.setSomeOneChecked(index); initPatientList(index); return true; } if(index == 1){ index = 0; tabbarView.setSomeOneChecked(index); initPatientList(index); } } return super.onFling(e1, e2, velocityX, velocityY); } }); }
@Override public boolean onTouchEvent(MotionEvent event) { detector.onTouchEvent(event); return super.onTouchEvent(event); }
二,布局文件关键代码是
<com.yin.PullToRefreshView android:id="@+id/main_pull_refresh_view" android:layout_width="fill_parent" android:layout_height="fill_parent" android:layout_below="@id/tabbar" android:background="@android:color/white" android:orientation="vertical" > <com.yin.IphoneTreeView android:id="@+id/appoint_list" android:layout_width="fill_parent" android:layout_height="fill_parent" android:divider="@null" android:groupIndicator="@android:color/transparent" android:cacheColorHint="#00000000"/> </com.yin.PullToRefreshView>
三,自定义的控件的关键代码是
/** * 该例子即实现了下拉刷新,上拉加载更多,也实现了左右滑动 * 这里的当前控件就是PullToRefreshView这个控件,其子控件是其包裹的listview等 * 当前控件的onInterceptTouchEvent()与其子控件的onInterceptTouchEvent()的关系: * 如果当前控件的onInterceptTouchEvent()返回false,说明当前控件不拦截该Touch事件,因此会由其子控件的onInterceptTouchEvent() * 接收该Touch事件; * 如果当前控件的onInterceptTouchEvent()返回true,则说明当前控件拦截了当前的onTouch事件,因此该touch事件会由当前控件的onTouchEvent()接收执行, * 当前控件的子控件则接收不到该touch事件; * 需要注意的是touch事件MotionEvent.ACTION_DOWN动作,肯定是首先执行的,且是瞬间的,因此该动作会先由当前控件的onInterceptTouchEvent()消费掉,所以当前控件 * 的onTouchEvent()方法或其子控件的onInterceptTouchEvent()和onTouchEvent()都不可能再接收到MotionEvent.ACTION_DOWN动作。 * 但是MotionEvent.ACTION_MOVE动作是联系的,是随着用户的手势不断执行的,因此如果当前控件onInterceptTouchEvent()在MotionEvent.ACTION_MOVE动作的过程中返回了 * true,则当前控件的onTouchEvent()方法会接收这个MotionEvent.ACTION_MOVE动作继续执行!!!; * 如果当前控件onInterceptTouchEvent()在MotionEvent.ACTION_MOVE动作的过程中返回了false,则其子控件会接收该MotionEvent.ACTION_MOVE动作继续执行??? * * 如果当前控件的onTouchEvent()方法返回true,则说明该onTouch事件被当前控件的onTouchEvent()垄断了,因此当前控件所在的Activity的onTouchEvent()就接收不到该 * onTouch事件了,如果当前控件的onTouchEvent()方法返回false,则当前控件所在的Activity的onTouchEvent()可继续接收该onTouch事件继续执行。 * * 由上可知,用户的一个按下-->滑动-->松开的动作可能有多个控件的多个方法参与处理,例如这里的用户的触摸事件就由PullToRefreshView的onInterceptTouchEvent()、 * onTouchEvent()以及其所在Activity的onTouchEvent()、GestureDetector的onFling()处理,因此我要想实现左右滑动则需要在当前控件的onInterceptTouchEvent()方法 * 中获取用户按下时的开始值,在其所在Activity的onFling()方法中获取其松开时的x值。 * @param e * @return */ @Override public boolean onInterceptTouchEvent(MotionEvent e) { int y = (int) e.getRawY(); int x= (int) e.getRawX(); switch (e.getAction()) { case MotionEvent.ACTION_DOWN: // 首先拦截down事件,记录y坐标 mLastMotionY = y; mLastMotionX = x;//记录用户按下时的x值,以便activity的GestureDetector的onFling()方法获取到用户按下时的起始位置 break; case MotionEvent.ACTION_MOVE: // deltaY > 0 是向下运动,< 0是向上运动 int deltaX = x - mLastMotionX; int deltaY = y - mLastMotionY; if((deltaY>=300)||(deltaY<=(-300))){//给用户的手势一段缓冲的空间(这里给了300),避免用户刚触摸屏幕就触发上拉或下拉 if (isRefreshViewScroll(deltaY)) { mLock = false;//将mLock置为false,则将触摸事件交给当前控件的onTouchEvent()处理下拉和上拉 return true; } } if((deltaX>=300)||(deltaX<=(-300))){ mLock = true;//引入mLock的目的是希望用户左右滑动时将触摸事件交给Activity的onTouchEvent()方法和GestureDetector处理 return true; } break; case MotionEvent.ACTION_UP: case MotionEvent.ACTION_CANCEL: break; } return false; // return true; } /* * 如果在onInterceptTouchEvent()方法中没有拦截(即onInterceptTouchEvent()方法中 return * false)则由PullToRefreshView 的子View来处理; * 否则由下面的方法来处理(即由PullToRefreshView自己来处理) */ @Override public boolean onTouchEvent(MotionEvent event) { if (mLock) { return false; } int y = (int) event.getRawY(); switch (event.getAction()) { case MotionEvent.ACTION_DOWN: // onInterceptTouchEvent已经记录 // mLastMotionY = y; break; case MotionEvent.ACTION_MOVE: int deltaY = y - mLastMotionY; if (mPullState == PULL_DOWN_STATE) { // PullToRefreshView执行下拉 Log.i(TAG, " pull down!parent view move!"); headerPrepareToRefresh(deltaY); // setHeaderPadding(-mHeaderViewHeight); } else if (mPullState == PULL_UP_STATE) { // PullToRefreshView执行上拉 Log.i(TAG, "pull up!parent view move!"); footerPrepareToRefresh(deltaY); } mLastMotionY = y; break; case MotionEvent.ACTION_UP: case MotionEvent.ACTION_CANCEL: int topMargin = getHeaderTopMargin(); if (mPullState == PULL_DOWN_STATE) { if (topMargin >= 0) { // 开始刷新 headerRefreshing(); } else { // 还没有执行刷新,重新隐藏 setHeaderTopMargin(-mHeaderViewHeight); } } else if (mPullState == PULL_UP_STATE) { if (Math.abs(topMargin) >= mHeaderViewHeight + mFooterViewHeight) { // 开始执行footer 刷新 footerRefreshing(); } else { // 还没有执行刷新,重新隐藏 setHeaderTopMargin(-mHeaderViewHeight); } } break; } // return super.onTouchEvent(event); // super.onTouchEvent(event); return true; }
这里例子可以很好的理解onInterceptTouchEvent、onTouchEvent、GestureDetector、SimpleOnGestureListener
以上部分代码来自网络,我只是为了理解触摸事件,自己加一些注释记录一下,别骂人啊
相关文章推荐
- 单链表的增删改查
- 用v7包没有发现ActionBarActivity
- 用v7包没有发现ActionBarActivity
- 史上最详细的Android Studio系列教程四--Gradle基础
- oc的try catch & NSError ....
- Android Studio如何更改JDK和SDK的路径?
- 消除SDK更新时的“https://dl-ssl.google.com refused”异常
- JSP自定义标签rtexprvalue属性用法实例分析
- Webstorm9配置SASS编译环境
- Spring基础—装配bean(二)
- sysbench利用fabric磁盘IO测试
- jquery获得option的值和对option进行操作
- MapReduce 中的两表 join 几种方案简介
- ITOO4.1之NuGet发布问题
- Tips
- 关于以太通道的工程实践与指导原则
- 关于以太通道的工程实践与指导原则
- 全局与接口的BPDU Guard功能是有重大区别的
- 全局与接口的BPDU Guard功能是有重大区别的 推荐
- [置顶] java.net.BindException: Address already in use: JVM_Bind