onInterceptTouchEvent、onTouchEvent、GestureDetector、SimpleOnGestureListener

本文深入解析了Android中触摸事件的处理机制,包括onInterceptTouchEvent、onTouchEvent等方法的作用及其实现方式,并通过实例展示了如何利用GestureDetector实现左右滑动功能。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一: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

以上部分代码来自网络,我只是为了理解触摸事件,自己加一些注释记录一下,别骂人啊



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值