Android的Touch事件分发的简单应用举例

  Touch事件分发的常见应用就是解决滑动冲突。常见的滑动冲突有父view左右滑动,子view也左右滑动这样,下面从重写父view的onInterceptTouchEvent方法和在子类中调用父类requestDisallowInterceptTouchEvent方法两种方式来举例。

  应用场景1,viewpager嵌套webview,而webview中含有可以左右滑动的选项卡,这样viewpager的左右滑动势必会和webview左右滑动的选项卡冲突。解决思路是,重写viewpager的onInterceptTouchEvent方法,在move事件时判断,当在界面的边缘滑动,并且是左右滑动时(x的滑动绝对值大于y的滑动绝对值),将滑动事件给父view,否则滑动事件还交给子view处理。实现代码如下:

/**
 * Created by lifengmei on 2016/6/20 18:00.
 */
public class EdgeSwitchPageViewPager extends ViewPager{

    private float startX;
    private float startY;

    public EdgeSwitchPageViewPager(Context context) {
        super(context);
    }

    public EdgeSwitchPageViewPager(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        switch (ev.getAction()){
            case MotionEvent.ACTION_DOWN:
                startX = ev.getX();
                startY = ev.getY();
                break;
            case MotionEvent.ACTION_MOVE:
                float nowX = ev.getX();
                float nowY = ev.getY();
                int screenWidth = DeviceUtils.getScreenWidth(getContext());
                //当按下时距离左边框或者右边框小于100px,且横向滑动幅度大于纵向滑动幅度时,将滑动焦点还给viewpager用于整个界面的切换
                //当在内部滑动时将滑动焦点给子类,用于子类滑动操作
                if((startX<100 && Math.abs(nowX - startX)>Math.abs(nowY - startY))
                        || ((screenWidth - startX) <100 && Math.abs(nowX - startX)>Math.abs(nowY - startY))){
                    return true;
                }else{
                    return false;
                }

            case MotionEvent.ACTION_UP:

                break;
        }
        return super.onInterceptTouchEvent(ev);
//        return  false;
    }
    @Override
    public boolean onTouchEvent(MotionEvent ev) {
        return super.onTouchEvent(ev);
    }
}
运行,即可看到滑动冲突被解决了。

  当然也可以在子view的内部拦截,思路是重写子view的dispatchTouchEvent方法,在down的时候调用父view的requestDisallowInterceptTouchEvent(true)不允许父类拦截,在move和up时在恰当的时机调用父view的getparent.requestDisallowInterceptTouchEvent(false)还给父view,同时还需要重写父view的onInterceptTouchEvent方法,默认拦截除了down事件以外的事件。down不能拦截,如果拦截了以后的任何事件就都不能到达子view了。

  应用场景2,scrollview嵌套可滑动的Edittext。实现思路:在Edittext的onTouch方法中判断拦截,当Edittext中的内容实际高度大于控件的固定高度时,表明Edittext中的内容是可以滑动的,此时调用父view的requestDisallowInterceptTouchEvent(true),不允许父view抢占事件,那么事件交给Edittext处理滑动;否则还把事件交给父view处理。在Edittext的onTouch方法中拦截的好处是,确定滑动事件是在Edittext中的,不用再计算滑动事件的位置是否符合条件了,比较快捷省事。实现代码如下:布局文件activity_scroller_and_big_et.xml

<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    >
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        >
        <ImageView
            android:layout_width="match_parent"
            android:layout_height="400dp"
            android:scaleType="fitCenter"
            android:src="@drawable/xueyou"
            />

        <EditText
            android:id="@+id/editText"
            android:layout_width="match_parent"
            android:layout_height="200dp"
            android:layout_margin="10dp"
            android:gravity="top"
            android:background="@drawable/shape_semicircle_gray" />

    </LinearLayout>

</ScrollView>
activity文件:
public class ScrollerAndBigEtActivity extends AppCompatActivity {

    private EditText et;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_scroller_and_big_et);
        et = (EditText) findViewById(R.id.editText);
        et.setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event) {//在onTouch方法中判断的好处是此时触摸事件一定是在edittext中了,不用计算触摸事件的位置是否符合条件了
                if(canEtScroll(et)){//Scrollview和Edittext中内容滑动冲突,Edittext内容滑不动,说明滑动事件被Scrollview抢占了;
                    // down事件肯定没有拦截,此时判断在Edittext滑动时不允许父view拦截事件
                    et.getParent().requestDisallowInterceptTouchEvent(true);
                }else{
                    et.getParent().requestDisallowInterceptTouchEvent(false);
                }
                return false;//不消费事件,还交给onTouchEvent处理滑动事件
            }
        });
    }

    /**
     * 判断edittext中的内容是否可滚动,当内容高度大于控件固定高度时,edittext内容是可以滑动的,返回true
     * */
    private boolean canEtScroll(EditText et){
        //et控件的固定高度
        int etHeight = et.getHeight()-et.getCompoundPaddingTop()-et.getCompoundPaddingBottom();
        //et内容的高度
        int etContentHeight = et.getLayout().getHeight();
        //二者之差
        int dValue = etContentHeight - etHeight;
        return dValue > 0;
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值