1. 程式人生 > >Android-ViewFlipper的滑動與子檢視中item點選的衝突解決

Android-ViewFlipper的滑動與子檢視中item點選的衝突解決

場景:ViewFlipper中添加了幾個View,每個View中有幾條itemView,每個itemView設定了setOnClickListener,ViewFlipper中通過GestureDetector來控制左右翻頁效果。

問題:不滑動,點選每個itemView,執行正常,當觸發了滑動後,手勢擡起時,依然會執行itemView的click事件

解決:在繼承的ViewFlipper中,攔截手勢動作onInterceptTouchEvent來攔截MotionEvent.ACTION_UP動作,如果正在處理滑動,直接返回true,不再下發,放置觸發itemView的點選事件,下面給出ViewFlipper的程式碼,裡面有註釋

package com.custom.views.carousel;

import android.content.Context;
import android.util.AttributeSet;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.View;
import android.view.animation.Animation;
import android.view.animation.TranslateAnimation;
import android.widget.ViewFlipper;

import java.util.ArrayList;
import java.util.List;

/**
 * Created by menghui on 2017/10/23.
 */

public class JRJCarouselFlipper extends ViewFlipper {
    /**
     * 檢視切換監聽
     */
    public interface CarouselChanged{
        void onChanged(int oldIndex,int newIndex,View view);
    }
    private Animation rightInAnim,leftOutAnim,rightOutAnim,leftInAnim;
    private List<View> views;
    private CarouselChanged carouselChanged;
    //動畫週期
    private int duration = 500;
    private GestureDetector gestureDetector;
    private GestureDetector.OnGestureListener gestureListener;
    //是否滑動中,該標誌用來避免gesture的滑動和滑動View中item的點選衝突
    private boolean fling = false;

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

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


    private void init(Context ctx){
        gestureListener = new GestureDetector.OnGestureListener() {
            @Override
            public boolean onDown(MotionEvent e) {
                fling = false;
                return false;
            }

            @Override
            public void onShowPress(MotionEvent e) {

            }

            @Override
            public boolean onSingleTapUp(MotionEvent e) {
                return false;
            }

            @Override
            public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
                return false;
            }

            @Override
            public void onLongPress(MotionEvent e) {

            }

            @Override
            public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
                fling = true;
                if (e1.getX() - e2.getX() > 100) {
                    setInAnimation(rightInAnim);
                    setOutAnimation(leftOutAnim);
                    int old = getDisplayedChild();
                    showNext();
                    int newindex = getDisplayedChild();
                    triggerChanged(old,newindex);
                    return true;
                } else if (e1.getX() - e2.getX() < -100) {
                    setInAnimation(leftInAnim);
                    setOutAnimation(rightOutAnim);
                        int old = getDisplayedChild();
                        showPrevious();
                        int newindex = getDisplayedChild();
                        triggerChanged(old,newindex);
                    return true;
                }
                return false;
            }
        };
        gestureDetector = new GestureDetector(gestureListener);
        views = new ArrayList<>();
        // 圖片從右側滑入
        rightInAnim = new TranslateAnimation(Animation.RELATIVE_TO_PARENT, 1.0f,
                Animation.RELATIVE_TO_PARENT, 0.0f,
                Animation.RELATIVE_TO_PARENT, 0.0f,
                Animation.RELATIVE_TO_PARENT, 0.0f);
        rightInAnim.setDuration(duration);

        // 圖片從左側滑出
        leftOutAnim = new TranslateAnimation(Animation.RELATIVE_TO_PARENT, 0.0f,
                Animation.RELATIVE_TO_PARENT, -1.0f,
                Animation.RELATIVE_TO_PARENT, 0.0f,
                Animation.RELATIVE_TO_PARENT, 0.0f);
        leftOutAnim.setDuration(duration);

        // 圖片從右側滑出
        rightOutAnim = new TranslateAnimation(Animation.RELATIVE_TO_PARENT, 0.0f,
                Animation.RELATIVE_TO_PARENT, 1.0f,
                Animation.RELATIVE_TO_PARENT, 0.0f,
                Animation.RELATIVE_TO_PARENT, 0.0f);
        rightOutAnim.setDuration(duration);

        // 圖片從左側滑入
        leftInAnim = new TranslateAnimation(Animation.RELATIVE_TO_PARENT, -1.0f,
                Animation.RELATIVE_TO_PARENT, 0.0f,
                Animation.RELATIVE_TO_PARENT, 0.0f,
                Animation.RELATIVE_TO_PARENT, 0.0f);
        leftInAnim.setDuration(duration);
    }

    private void triggerChanged(int oldIndex,int newIndex){
        if (views.size() <= 0)
            return;
        if (carouselChanged != null){
            carouselChanged.onChanged(oldIndex,newIndex,views.get(newIndex));
        }
    }

    public CarouselChanged getCarouselChanged() {
        return carouselChanged;
    }

    public void setCarouselChanged(CarouselChanged carouselChanged) {
        this.carouselChanged = carouselChanged;
    }

    /**
     * 設定要輪播的檢視列表
     * @param views
     */
    public void setViews(List<View> views) {
        this.views.clear();
        this.removeAllViews();
        this.views.addAll(views);
        for(View v:views){
            this.addView(v);
        }
    }

    /**
     * 攔截觸屏,當按下時,fling=false,允許點選子檢視中的item,當手勢擡起時,為避免和滑動發生衝突,判斷fling狀態,
     * 如果處於滑動中,並且是手勢擡起,返回true,不再向下傳遞,使item點選事件失效
     * @param ev
     * @return
     */
    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        if (ev.getAction() == MotionEvent.ACTION_DOWN)
            fling = false;
        else if (fling && ev.getAction() == MotionEvent.ACTION_UP){
            return true;
        }
        return super.onInterceptTouchEvent(ev);
    }

    /**
     * 分發觸屏,交給gesture
     * @param ev
     * @return
     */
    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        gestureDetector.onTouchEvent(ev);
        return super.dispatchTouchEvent(ev);
    }

}