Android事件传递

学习目标:

Android事件传递

学习内容:

再多的文字也不如一张图清晰,上图。
在这里插入图片描述
这个图已经讲的很清楚了,主要再记一些细节。

  • 我们手指触摸屏幕然后滑动一段距离最后抬起,所以在这个过程中所产生的一系列事件从down开始中间有许多move事件最后以up结束。
  • 正常情况下,一个事件序列只能被一个view拦截且消耗,但可以通过一定的方式强行传给别的view处理。
  • 当某个view决定一旦拦截事件,那么这个序列事件都会由他处理,并且它的onInterceptTouchEvent不会再调用。
  • 当某个view一旦开始处理事件,如果不消耗ACTIO_DOWN事件(返回false),那么同一事件序列中的其他事件都不会再在交给它处理。
  • 如果这个view不消耗除ACTION_DOWN以外的事件,那么这个点击事件不会被父元素所调用,而会被activity调用。
  • viewGroup默认是不拦截任何事件的,它的onInterceptTouchEvent返回false。
  • view没有onInterceptTouchEvent方法,一旦有事件,则会调用它的onTouchEvent
  • view的onTouchEvent默认会消耗事件(返回true),除非它的longClickable和clickable为false.
  • 我们可以在子元素干预父元素的事件分发过程,通过调用requestDisallowInterceptTouchEvent(true),但是ACTION_DOWN除外。
    好的,我们下面来实现一个viewgroup,拦截滑动事件,但不拦截点击事件的demo。
package com.suyong.componentization;

import android.content.Context;
import android.content.res.Configuration;
import android.graphics.Point;
import android.graphics.PointF;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewConfiguration;
import android.view.ViewGroup;

public class MyViewGroup extends ViewGroup {

    private String TAG = "MyViewGroup";

    private PointF DownPoint;

    public MyViewGroup(Context context) {
        super(context);
        init();
    }

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

    public MyViewGroup(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init();
    }

    private void init() {
        DownPoint = new PointF();
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec){
        super.onMeasure(widthMeasureSpec,heightMeasureSpec);
        measureChildren(widthMeasureSpec, heightMeasureSpec);
    }

    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        Log.d(TAG,"onLayout");
        int childCount = getChildCount();
        int bottom = 0;
        for (int i = 0; i < childCount; i++){
            View childView = getChildAt(i);
            int cWidth = childView.getMeasuredWidth();
            int cHeight = childView.getMeasuredHeight();
            MarginLayoutParams layoutParams = (MarginLayoutParams) childView.getLayoutParams();
            childView.layout(layoutParams.leftMargin, bottom, cWidth, bottom + cHeight);
            bottom += cHeight;
        }
    }

    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        Log.d(TAG,"dispatchTouchEvent");
        return super.dispatchTouchEvent(ev);
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        int action = ev.getAction();
        if (action == MotionEvent.ACTION_CANCEL || action == MotionEvent.ACTION_UP) {
            return false; // 返回false,不拦截事件,交给子view
        }
        switch (action) {
            case MotionEvent.ACTION_MOVE:
                final float xDiff = calculateDistanceX(ev);
                //如果滑动距离大于最小有效距离,那么就拦截下来
                int scaledTouchSlop = ViewConfiguration.get(getContext()).getScaledTouchSlop();
                if (xDiff > scaledTouchSlop) {
                    return true;
                }
                break;
            case MotionEvent.ACTION_DOWN:
                //手指落下时的坐标,用来计算滑动距离的
                DownPoint.set(ev.getRawX(),ev.getRawY());
                return false;
        }
        //其他情况下我们就不拦截触摸事件了,交给子view处理这个触摸事件
        return false;
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        int action = event.getAction();
        boolean intercept = false;
        switch (action) {
            case MotionEvent.ACTION_DOWN:
                Log.d(TAG,"onTouchEvent   "+"MotionEvent.ACTION_DOWN");
                intercept = true;
                break;
            case MotionEvent.ACTION_MOVE:
                Log.d(TAG,"onTouchEvent   "+"MotionEvent.ACTION_MOVE");
                intercept = true;
                break;
            case MotionEvent.ACTION_UP:
                Log.d(TAG,"onTouchEvent   "+"MotionEvent.ACTION_UP");
                intercept = false;
                break;
        }
        return intercept;
    }

    @Override
    protected LayoutParams generateLayoutParams(LayoutParams p) {
        return new MarginLayoutParams(p);
    }

    @Override
    public LayoutParams generateLayoutParams(AttributeSet attrs) {
        return new MarginLayoutParams(getContext(), attrs);
    }

    @Override
    protected LayoutParams generateDefaultLayoutParams() {
        return new MarginLayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
    }

    private float calculateDistanceX(MotionEvent ev) {
        return Math.abs(ev.getRawX() - DownPoint.y);
    }
}




package com.suyong.componentization;

import android.content.Context;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;

import androidx.annotation.Nullable;

public class MyView extends View {

    private String TAG = "MyView";

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

    public MyView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
    }

    public MyView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    @Override
    public boolean dispatchTouchEvent(MotionEvent event) {
        Log.d(TAG,"dispatchTouchEvent");
        return super.dispatchTouchEvent(event);

    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        return super.onTouchEvent(event);
    }

}


<?xml version="1.0" encoding="utf-8"?>
<com.suyong.componentization.MyViewGroup xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="200dp"
    android:layout_height="200dp"
    android:background="@color/colorAccent"
    tools:context=".MainActivity">

    <com.suyong.componentization.MyView
        android:onClick="click"
        android:id="@+id/myview"
        android:layout_width="100dp"
        android:layout_height="100dp"
        android:background="@color/colorPrimaryDark"
        android:onClick="jumpToWalker"
     />

</com.suyong.componentization.MyViewGroup>

个人总结,欢迎留言讨论!

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值