Android事件处理机制实例讲解

本文详细分析了一个开源的Android引导页实现,讲解了Touch事件的分派、拦截和处理机制,以及如何实现ChildViewPager和Text的同时响应滑动、点击跳过、不同页面动画切换等功能。还探讨了动画实现的复杂计算,并强调了理解Touch事件传递的重要性。
摘要由CSDN通过智能技术生成

  在android开发技术周报看到了小红书引导页的开源实现,觉得做的很不错,在这里分析一下它的实现,共同学习~

效果

页面组成

这里写图片描述

Touch事件传递

  如果还不理解touch事件的分派、拦截、处理机制,强烈推荐下面的文章:
  Android TouchEvent事件传递机制
  Android:30分钟弄明白Touch事件分发机制
要实现的需求:

  • Req-1 ChildViewPager#image 和 ChildViewPager#text能同时响应滑动事件。
  • Req-2 点击“跳过”按钮进入LoginAnimFragment。
  • Req-3 Text1滑到Text2时,ChildViewPager#image不滑动,FirstFragment播放动画。
  • Req-4 Text2滑到Text3时,切换到SecondFragment并播放动画。
  • Req-5 Text3滑到Text4时,切换到ThirdFragment并播放动画。
  • Req-6 从Text4再向右滑,切换到LoginAnimFragment。
  • Req-7 从LoginAnimFragment向左滑不会滑到WelcomeAnimFragment。

触摸事件拦截
  为了实现Req-1(ChildViewPager#image 和 ChildViewPager#text能同时响应滑动事件),需要在ParentViewPager拦截触摸事件自己来处理touch事件。

@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
if (mLoginPageLock) {
        requestDisallowInterceptTouchEvent(true);
        return super.onInterceptTouchEvent(ev);
    }
    return true;
}

  requestDisallowInterceptTouchEvent(true);的作用是禁止调用onInterceptTouchEvent方法,也就是不再拦截触摸事件。实现了Req-7(从LoginAnimFragment向左滑不会滑到WelcomeAnimFragment)。
那么问题来了,可以把

    requestDisallowInterceptTouchEvent(true);
    return super.onInterceptTouchEvent(ev);

  这两句能换成一句return false吗?试了一下效果跟上面两句是一样的,会不会出现负面影响未知。
处理触摸事件
  ParentViewPager将事件拦截后,在onTouchEvent里做处理。
  Req-2:“跳过”按钮

/**
 * 由于子View被拦截,这里通过计算跳过按钮的坐标手动处理跳过click事件
*/
if (mTvSkipLocation == null) {
    mTvSkipLocation = new int[2];
    mWelcomAnimFragment.tv_skip.getLocationOnScreen(mTvSkipLocation);
    }
    if (left == 0) {
    margin = DisplayUtil.dip2px(getContext(), 10);
    left = mTvSkipLocation[0] - margin;
    top = mTvSkipLocation[1] - margin;
    right = mTvSkipLocation[0] + mWelcomAnimFragment.tv_skip.getWidth() + margin;
    bottom = mTvSkipLocation[1] + mWelcomAnimFragment.tv_skip.getHeight() + margin;
    }
    if (mCx - left > 0 && right - mCx > 0 && mCy - top > 0 && bottom - mCy > 0 && !mLoginPageLock) {
    } else {
    mSkipFlag = false;
    }
    if (ev.getAction() == MotionEvent.ACTION_UP) {
    if (mCx - left > 0 && right - mCx > 0 && mCy - top > 0 && bottom - mCy > 0 && !mLoginPageLock && mSkipFlag) {
    if (mWelcomAnimFragment.mWelcomAnimFragmentInterface != null) {
    mWelcomAnimFragment.mWelcomAnimFragmentInterface.onSkip();
            }
        }
    mSkipFlag = true;
    mCx = 0;
    mCy = 0;
}

  ViewPager控件

/**
 * touch事件由顶层viewpager捕捉,手动分发到两个子viewpager
 */
if (mWelcomAnimFragment.imageViewPager != null && !mWelcomAnimFragment.imageViewPager.mIsLockScoll) {
    mWelcomAnimFragment.imageViewPager.onTouchEvent(ev);
}
if (mWelcomAnimFragment.textViewPager != null) {
    mWelcomAnimFragment.textViewPager.onTouchEvent(ev);
}
if (mWelcomAnimFragment.mIsMoveParent) {
    return super.onTouchEvent(ev);
}

  通过mIsLockScoll控制imageViewPager是否响应触摸事件,实现了Req-3(Text1滑到Text2时,ChildViewPager#image不滑动,FirstFragment播放动画);
  通过mIsMoveParent实现了Req-6(从Text4再向右滑,切换到LoginAnimFragment)。

动画

  下面来看一看酷炫的动画是怎么实现的。
这里写图片描述
  这三个Fragment分别是LoginAnimImageFristFragment,LoginAnimImageSecondFragment,LoginAnimImageThridFragment。
以LoginAnimImageFristFragment为例做分析。
先看资源:
这里写图片描述这里写图片描述
  需要从第一个item滚动到第三个item的头部,涉及到如下问题:

  • 图片缩放到恰当的比例;
  • 精确滚动到第三个item头部;

    经过一系列的计算,播放动画的代码如下:

@Override
public void playInAnim() {
    if (mAnimStartY < 0) {
        mAnimStartY = ViewHelper.getY(iv_scroll);
    }

    if(mObjectAnimator == null){
        mObjectAnimator = ObjectAnimator.ofFloat(iv_scroll, "y", mMarginTopHeigth, -scrollMarginTopHeigth+mMarginTopHeigth);
    }
    if(mAnimatorSet == null){
        mAnimatorSet = new AnimatorSet();
    }

    if(mAnimatorSet.isRunning()){
        mAnimatorSet.cancel();
    }

    mAnimatorSet.play(mObjectAnimator);
    mAnimatorSet.setDuration(3000);
    mAnimatorSet.start();
}

  第二、三页的动画实现类似(看到各种长宽计算有没有晕晕的感觉???刚看到代码我是晕了,找到一种更好的开发动画的方式就好了。。。)

总结

  • 这个例子可以帮助你深入理解Touch事件的传递机制;
  • 为了精确控制动画要进行繁杂的计算,无非是缩放、移动、旋转、隐藏,理解了就不觉得难;

感谢小红书的分享,感谢github,感谢所有支持开源的个人和组织~

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值