Android resuelve conflictos de deslizamiento

Android resuelve conflictos de deslizamiento

Generación de conflicto deslizante

Antes de discutir el método para resolver conflictos deslizantes, necesitamos saber bajo qué escenarios ocurrirán conflictos deslizantes. Los conflictos deslizantes ocurren entre dos componentes (o más), y estos dos componentes están en una relación de contención (control principal y control secundario), cuando el control principal y el control secundario pueden interceptar el evento deslizante, pero no lo hicimos. Se manejan sus conflictos deslizantes , entonces solo un control puede responder al evento de deslizamiento en este momento, generalmente llamamos a esta situación un conflicto de deslizamiento entre el control principal y el control secundario. Hay tres escenarios principales:

Conflicto deslizante escena uno

La dirección de deslizamiento del control principal es diferente de la dirección de deslizamiento del control secundario. La solución a este escenario es relativamente simple. Por ejemplo, generalmente usamos ViewPager+RecyclerView (asumiendo que viewPager se desliza hacia la izquierda y hacia la derecha, mientras que RecyclerView se desliza hacia arriba y hacia abajo). Esto es deslizante y deslizamos el Escenario 1 del conflicto, pero no tuvimos un conflicto deslizante cuando usamos esta arquitectura, porque nos ayudó a darnos cuenta del método para resolver el conflicto deslizante dentro de viewPager. Y si no usamos ViewPager para usar otros controles principales que se pueden deslizar y el interior es una lista RecyclerView o ListView, se producirá un conflicto de deslizamiento en este momento.

La solución específica al escenario de conflicto deslizante 1 es el método de interceptación externa, que se describe en detalle a continuación:

método de intercepción externa

El llamado método de intercepción externa significa que toda la secuencia de eventos debe ser interceptada primero por el control principal. Cuando necesitemos este evento, lo interceptaremos y, si no lo necesitamos, lo entregaremos al control secundario. para procesar. (Si no comprende el mecanismo de distribución de eventos, infórmese sobre el mecanismo de distribución de eventos de Android). Solo necesitamos reescribir el método onInterceptTouchEvent() de nuestro control principal para decidir si interceptar el evento, asumiendo que el externo es ViewPager (deslice el dedo hacia la izquierda y hacia la derecha, y aquí asumimos que ViewPager no maneja los conflictos deslizantes, la fuente real de ViewPager el código ha resuelto el problema de los conflictos de deslizamiento), el interior es RecyclerView (deslizamiento hacia arriba y hacia abajo), luego reescribimos el método onInterceptTouchEvent() de ViewPager. La lógica del código específico es la siguiente:

package com.it.test;

import android.content.Context;
import android.view.MotionEvent;

import androidx.annotation.NonNull;
import androidx.viewpager.widget.ViewPager;

public class MyViewPager extends ViewPager {
    
    

    private float startX;
    private float startY;
    //使用directionSign来作为拦截的标志,0代表没有初始化,1代表父控件拦截,其他情况代表子控件拦截
    private int directionSign = 0; //只有在滑动开始时需要进行判断由谁进行拦截,之后的这一次事件中无需判断

    public MyViewPager(@NonNull Context context) {
    
    
        super(context);
    }

    //onInterceptTouchEvent返回true表示该viewPager拦截事件(不再向子控件中进行分发),返回false代表不拦截,进行分发事件(交由子控件RecyclerView处理)
    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
    
    
        boolean sign = false; //该标志标示是否拦截事件
        switch (ev.getAction()){
    
    
            case MotionEvent.ACTION_DOWN:
                //按下屏幕事件
                sign = false; //此处必须为false,如果为true,则后期滑动的事件将默认会被viewPager拦截,且不在调用onInterceptTouchEvent()方法
                //进行记录当前的坐标
                startX = ev.getX();
                startY = ev.getY();
                break;
            case MotionEvent.ACTION_MOVE:
                //滑动屏幕事件,具体解决滑动冲突的思路在此
                if(checkFatherNeed(ev)){
    
     //检查父控件ViewPager是否需要拦截,如果需要则进行修改sign = true
                    sign = true;
                }else{
    
    
                    sign = false;
                }
                break;
            case MotionEvent.ACTION_UP:
                //松开屏幕事件
                sign = false; //此处为true或false意义不大,一般置为false
                break;
        }
        return sign;
    }

    private boolean checkFatherNeed(MotionEvent event) {
    
    
        if(directionSign == 0){
    
    
            //没有初始化,对directionSign进行初始化
            float currentX = event.getX();
            float currentY = event.getY();
            if(Math.abs(currentX - startX) > Math.abs(currentY-startY)){
    
    
                //代表水平滑动内容多,进行拦截事件
                directionSign = 1;
                return true;
            }else{
    
    
                //代表水平滑动内容多,交给子控件拦截事件
                directionSign = 2;
                return false;
            }
        }else if(directionSign == 1){
    
    
            //父控件拦截
            return true;
        }else{
    
    
            //子控件拦截
            return false;
        }
    }
}

La solución general es juzgar la dirección del deslizamiento del dedo (puede comparar la distancia de deslizamiento horizontal y la distancia de deslizamiento vertical) para determinar quién interceptará y procesará el evento. (Deslice el dedo hacia la izquierda y hacia la derecha hasta ViewPager y deslice hacia arriba y hacia abajo hasta RecyclerView)

Conflicto deslizante escena dos

El segundo escenario de conflicto de deslizamiento es que la dirección de deslizamiento externa es la misma que la dirección de deslizamiento interna, por ejemplo, un RecyclerView que se desliza hacia arriba y hacia abajo está anidado dentro de un ScrollView que se desliza hacia arriba y hacia abajo. La solución específica a este escenario es el método de interceptación interna.

método de intercepción interna

El método de intercepción interna significa que necesitamos reescribir el método de distribución dispatcherTouchEvent del control secundario, y podemos juzgar el estado del evento para distribuir el derecho de procesamiento al control principal o al control secundario. (Por ejemplo, cuando se encuentra en un determinado estado, queremos que el control secundario maneje los eventos y los demás estados se transfieren al control principal).

La idea de implementación específica es la siguiente:

Necesitamos reescribir el método dispatcherTouchEvent del control secundario y reescribir el método onInterceptTouchEvent del control principal. Necesitamos asegurarnos de que cuando se presiona el dedo por un momento, es decir, cuando se genera el evento ACTION_DOWN, debemos asegurarnos de que que el control principal no lo intercepte, y luego se debe distribuir el control secundario. Realice parent.requestDisallowInterceptTouchEvent(true) para evitar que el control principal intercepte el evento. Cuando llamamos a parent.requestDisallowInterceptTouchEvent(false), el control principal puede interceptar el evento.

El código específico es el siguiente:

control de niños

package com.it.test;

import android.content.Context;
import android.view.MotionEvent;

import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;

public class MyRecyclerview extends RecyclerView {
    
    

    float x;
    float y;
    
    public MyRecyclerview(@NonNull Context context) {
    
    
        super(context);
    }

    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
    
    
        switch (ev.getAction()){
    
    
            case MotionEvent.ACTION_DOWN:
                float x = ev.getX();
                float y = ev.getY();
                getParent().requestDisallowInterceptTouchEvent(true); //父控件之后不再拦截事件
                break;
            case MotionEvent.ACTION_MOVE:
                if(父控件需要此类事件){
    
    
                    getParent().requestDisallowInterceptTouchEvent(false); //父控件可以进行拦截事件  
                } 
                break;
        }
        return super.dispatchTouchEvent(ev);
    }
}


control de los padres

package com.it.test;

import android.content.Context;
import android.view.MotionEvent;

import androidx.annotation.NonNull;
import androidx.viewpager.widget.ViewPager;

public class MyViewPager extends ViewPager {
    
    

    public MyViewPager(@NonNull Context context) {
    
    
        super(context);
    }


    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
    
    
        if(ev.getAction() == MotionEvent.ACTION_DOWN){
    
    
            return false; //不拦截
        }else{
    
    
            return true; //除了按下事件其他进行全部拦截(前提是子控件的parent.requestDisallowInterceptTouchEvent(false))
        }
    }

}

Conflicto deslizante escena tres

El tercer escenario de conflicto deslizante es la combinación o ocurrencia simultánea de las dos situaciones anteriores, la solución es utilizar el uso conjunto de la interceptación interna y la interceptación externa.

Supongo que te gusta

Origin blog.csdn.net/weixin_45927121/article/details/124873613
Recomendado
Clasificación