android(仿QQ向右滑动退出)在viewpager中onTouchEvent无法监听到ACTION_DOWN的getX的值
Posted 疯狂Max
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了android(仿QQ向右滑动退出)在viewpager中onTouchEvent无法监听到ACTION_DOWN的getX的值相关的知识,希望对你有一定的参考价值。
最近笔者在做项目的时候遇到一个问题,implements OnTouchListener中重写onTouch事件无法获取ACTION_DOWN中getX的值。
笔者想实现的效果:一个A页面,一个B页面(包含4个fragment的viewpager),viewpager可以实现fragment横滑切换,当fragment为0也就是第一个页面时,通过ontouch接口,在ACTION_DOWN获取用户点击屏幕的X距离StartX,再通过action_move获取用户滑动的距离SlipX,通过当StartX-SlipX>100,实现finish页面。再通过overridePendingTransition(int enterAnim, intexitAnim)设置进入,退出的动画,实现仿QQ横滑退出的效果。
;
问题描述:在ViewPager绑定onTouch事件中的ACTION_DOWN中无法获取getX的距离,然而action_move,action_up中确能够获取到getX的值。
好了,想必大家也明白了想要达到的效果以及遇到的问题,那么笔者也不废话了。直接说明出现此问题的原因,以及解决方案,最后当然是源码共享。
核心原因:对于(dispatchTouchEvent、onInterceptTouchEvent、onTouchEvent),以及onTouch这几个方法没有完全搞明白,以及其传递机制。于是本着严谨的态度,通过万能的互联网终于搞明白了这几个之间的关系,以及用法,下面这个图很好的说明了该问题。(后面我会贴出相关参考的帖子链接,大家有兴趣可以看一下).
1.首先onTouch方法是继承OnTouchListener接口需要重写的方法,当一个View绑定了该监听的时候,就会调用onTouch方法来监听用户对该View的手指操作.(什么是View?也就是一般的源生控件.例如button,textview,以本案例的viewpager都属于view或者自定义View).
mViewPager.setOnTouchListener(this);// 为ViewPager设置ontouch监听获取滚动距离
在这种情况下,如果我们在Activity里面为一个View控件绑定了setOnTouchListener,那么当屏幕有touch事件的时候,首先会是绑定该监听的View响应onTouch事件,执行onTouch方法.
如果onTouch返回值为true,表示这个touch事件被onTouch方法处理完毕,不会把touch事件再传递给Activity,也就是说activity的dispatchTouchEvent方法不会被调用,在本案例中,也就是viewpager就不会滑动了(有兴趣可以试一下)。
如果onTouch的返回值是false,表示这个touch事件没有被完全处理,onTouch返回以后,touch事件被传递给Activity,activity的dispatchTouchEvent方法被调用.
2.其次dispatchTouchEvent、onInterceptTouchEvent、onTouchEvent,如下图所示,简单解释一下吧.
*activity里可以重写dispatchTouchEvent,onTouchEvent两个方法,实现监听.
*viewgroup里可以重写dispatchTouchEvent、onInterceptTouchEvent、onTouchEvent三个方法,实现监听.(什么是ViewGroup?也就是一般的放置View的容器,一般是代码自定义button,textview这些)
*view里面可以重写dispatchTouchEvent,onTouchEvent两个方法,实现监听.
3.接下来,就是其传递机制如下图所示
android中默认情况下事件传递是由最终的view的接收到,传递过程是从父布局到子布局,也就是从Activity到ViewGroup到View的过程,从上向下分发.
(可能这里有些同学觉得有点绕,举个例子,如果在一个activity里面都实现了Activity\\ViewGroup\\的dispatchTouchEvent方法以及View的Ontouch方法,那么当用户点击屏幕的时候,获取到用户action_down的getX控制台打印顺序,依次是Activity→ViewGroup→View)
(1) 首先会去触发activity里面的dispatchTouchEvent事件
(2)然后是ViewGroup的dispatchTouchEvent事件(一般是代码自定义控件的时候重写该方法才会去执行)
(3) 最后是View的dispatchTouchEvent事件.因为是为View,setOnTouchListener.所以会去执行onTouch方法.
因此这个问题就迎刃而解了,如果说我在onTouch里面无法获取到ACTION_DOWN的getX的值,那么我就重写activity的dispatchTouchEvent方法,在这里直接获取ACTION_DOWN的getX的值,然后在将touch事件传递下去在ontouch获取ACTION_MOVE的getX的值,那么我就能通过当StartX-SlipX>100,实现finish页面了.
不过要注意的地方有两点:
1.当一个touch事件执行完毕,最后return的true;表示这个touch事件处理完毕,不会把touch事件再向下传递.反之,false,则向下传递
2. 在重写dispatchTouchEvent等方法的时候,一定要 super.dispatchTouchEvent(ev);否则事件会就此打住,任凭你如何滑动,屏幕也会一定不动
最后这里直接上核心代码。
/**
* 带有4个fragment的ViewPager,并且在第一个fragment的时候实现向右滑动finish当前页面返回上一个页面
* @author max
*/
public class SecondActivity extends FragmentActivity implements
OnClickListener, OnTouchListener, OnPageChangeListener
private ViewPager mViewPager;// 滑动的viewpager
private TextView text1, text2, text3, text4;// 点击跳转的fragment页面
private List<Fragment> mTabs = new ArrayList<Fragment>(); // fragment集合
private FragmentPagerAdapter mAdapter; // viewpager的adapter
// 记录开始手指点击的位置,和滑动的X距离
private int StartX, SlipX;
// 当前的页面
private int currentItemNum = 0;
@Override
protected void onCreate(Bundle savedInstanceState)
super.onCreate(savedInstanceState);
setContentView(R.layout.second_activity);
init();
initDatas();
mViewPager.setAdapter(mAdapter);
mViewPager.setOnPageChangeListener(this);// 设置页面滚动监听获取当前页面的页码
mViewPager.setOnTouchListener(this);// 为ViewPager设置ontouch监听获取滚动距离
/** 位fragment的list传值 **/
private void initDatas()
Fragment1 fragment1 = new Fragment1();
Fragment2 fragment2 = new Fragment2();
Fragment3 fragment3 = new Fragment3();
Fragment4 fragment4 = new Fragment4();
// 往list加入4个碎片
mTabs.add(fragment1);
mTabs.add(fragment2);
mTabs.add(fragment3);
mTabs.add(fragment4);
// 初始化适配器
mAdapter = new FragmentPagerAdapter(getSupportFragmentManager())
@Override
public int getCount()
return mTabs.size();
@Override
public Fragment getItem(int arg0)
return mTabs.get(arg0);
;
/** 初始化控件 **/
private void init()
mViewPager = (ViewPager) findViewById(R.id.viewpage);
text1 = (TextView) findViewById(R.id.text1);
text2 = (TextView) findViewById(R.id.text2);
text3 = (TextView) findViewById(R.id.text3);
text4 = (TextView) findViewById(R.id.text4);
text1.setOnClickListener(this);
text2.setOnClickListener(this);
text3.setOnClickListener(this);
text4.setOnClickListener(this);
/** 点击text切换子页面 **/
@Override
public void onClick(View v)
switch (v.getId())
case R.id.text1:
mViewPager.setCurrentItem(0);
break;
case R.id.text2:
mViewPager.setCurrentItem(1);
break;
case R.id.text3:
mViewPager.setCurrentItem(2);
break;
case R.id.text4:
mViewPager.setCurrentItem(3);
break;
default:
break;
@Override
public boolean dispatchTouchEvent(MotionEvent ev)
// 一定要spuer,否则事件打住,不会在向下调用了
super.dispatchTouchEvent(ev);
switch (ev.getAction())
// 记录用户手指点击的位置
case MotionEvent.ACTION_DOWN:
StartX = (int) ev.getX();
Log.i("info", "StartX = " + StartX);
break;
return true;// return false,继续向下传递,return true;拦截,不向下传递
// 默认是重写onTouch事件
@Override
public boolean onTouch(View v, MotionEvent event)
switch (event.getAction())
case MotionEvent.ACTION_DOWN:
StartX = (int) event.getX();
Log.i("info", "StartX11111 = " + StartX);
break;
case MotionEvent.ACTION_MOVE:
// 获取滑动时候的X距离
SlipX = (int) event.getX();
Log.i("info", "1= " + SlipX);
if (currentItemNum == 0 && SlipX - StartX > 100)
// 在第一个页面,手势向右滑动,finish当前页面
finish();
// 设置切换切换动画
overridePendingTransition(R.anim.slide_left_in,
R.anim.slide_right_out);
break;
default:
break;
return false;
@Override
public void onPageScrollStateChanged(int arg0)
@Override
public void onPageScrolled(int arg0, float arg1, int arg2)
@Override
public void onPageSelected(int arg0)
// 获取当前页码
currentItemNum = arg0;
最后当然是源码,仿QQ横滑finish当前 activity,带做右进左出的动画.点击下载
第一次发布博客,稍微有点紧张,如有有纰漏,欢迎各位看官指出,大家一起相互学习
最后感谢万能的互联网,以及各位勤劳的博主,以下贴出参考资料地址,有兴趣的童鞋可以去看看.
http://blog.csdn.net/yanzi1225627/article/details/22592831 (打印出了各事件点击打印日志)
http://blog.csdn.net/xyz_lmn/article/details/12517911 (ontouch事件分发机制图片详解)
以上是关于android(仿QQ向右滑动退出)在viewpager中onTouchEvent无法监听到ACTION_DOWN的getX的值的主要内容,如果未能解决你的问题,请参考以下文章
QQ查看图片时不能向右滑动,往左滑也不行,往左右滑怎么都滑不过来,怎么回事啊?