suchen

Heim  >  Fragen und Antworten  >  Hauptteil

android - scrollView和listview滑动冲突

在scrollview内嵌套了一个viewpager,重写了scrollview的onInterceptTouchEvent()方法,但是我写的没有什么效果,最近刚刚接触这个滑动冲突不能很好理解。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

<code>public class ScrollViewX extends ScrollView {

 

    private static final String TAG = "ScrollViewX";

 

    private ViewPager mViewPager;

 

    private int mLastXIntercepted = 0;

    private int mLastYIntercepted = 0;

 

    public ScrollViewX(Context context) {

        super(context);

    }

 

    public ScrollViewX(Context context, AttributeSet attrs) {

        super(context, attrs);

    }

 

    public ScrollViewX(Context context, AttributeSet attrs, int defStyleAttr) {

        super(context, attrs, defStyleAttr);

    }

 

    @Override

    public boolean onInterceptTouchEvent(MotionEvent ev) {

 

        boolean intercepted = false;

 

        int x = (int) ev.getX();

        int y = (int) ev.getY();

        int deltaX = x - mLastXIntercepted;

        int deltaY = y - mLastYIntercepted;

 

        mLastXIntercepted = x;

        mLastYIntercepted = y;

 

        switch (ev.getAction()) {

            case MotionEvent.ACTION_DOWN: {

                //action_down不拦截

                intercepted = false;

                break;

            }

            case MotionEvent.ACTION_MOVE: {

                if(mViewPager != null && isTouchInView(mViewPager, ev)){

                    //点击事件发生在viewpager范围内

                    if(Math.abs(deltaY) > Math.abs(deltaX)) {

                        //如果竖直方向的滑动距离大于横向, 那么scrollview拦截

                        intercepted = true;

                    } else {

                        intercepted = false;

                    }

                } else {

                    intercepted = false;

                }

                break;

            }

            case MotionEvent.ACTION_UP: {

                intercepted = false;

                break;

            }

            default: break;

        }

        return intercepted;

    }

 

    //判断点击事件是否在当前view中

    private boolean isTouchInView(View view, MotionEvent event) {

        int x = (int) event.getRawX();

        int y = (int) event.getRawY();

        int[] local = new int[2];

        view.getLocationOnScreen(local);

        int subVX = local[0];

        int subVY = local[1];

        int subWidth = view.getWidth();

        int subHeight = view.getHeight();

        if(x > subVX && x < subVX + subWidth && y > subVY && y < subVY + subHeight) {

            return true;

        }

        return false;

    }

 

    public void setViewPager(ViewPager viewPager) {

        mViewPager = viewPager;

    }

}

</code>

我在红色部分左右滑动viewpager能够正常,但是在viewpager中竖直滑动就不能滚动scrollview,但是我觉得我在scrollview的onInterceptTouchEvent()方法中已经判断了,但是最终却没有效果。

感谢采纳的那位,根据他的提示, 我顺便解决了listview的滑动冲突。
现在使用外部拦截法: 重写ScrollView 的 onInterceptedTouchEvent() 方法,

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

<code>public class ScrollViewX extends ScrollView {

 

    private static final String TAG = "ScrollViewX";

 

    private ListViewX mListViewX;

    private ViewPager mViewPager;

 

    private int mLastX = 0;

    private int mLastY = 0;

 

    public ScrollViewX(Context context) {

        super(context);

    }

 

    public ScrollViewX(Context context, AttributeSet attrs) {

        super(context, attrs);

    }

 

    public ScrollViewX(Context context, AttributeSet attrs, int defStyleAttr) {

        super(context, attrs, defStyleAttr);

    }

 

    @Override

    public boolean onInterceptTouchEvent(MotionEvent ev) {

 

        boolean intercepted = false;

 

        int x = (int) ev.getX();

        int y = (int) ev.getY();

 

        int deltaX = x - mLastX;

        int deltaY = y - mLastY;

 

        Log.i(TAG, "deltaY = " + deltaY);

 

        mLastX = x;

        mLastY = y;

 

        switch (ev.getAction()) {

            case MotionEvent.ACTION_DOWN: {

                return super.onInterceptTouchEvent(ev);

            }

            case MotionEvent.ACTION_MOVE: {

                if(mViewPager != null && isTouchInView(mViewPager, ev)){

                    //点击事件发生在viewpager范围内

                    if(Math.abs(deltaY) > Math.abs(deltaX)) {

                        //如果竖直方向的滑动距离大于横向, 那么scrollview拦截

                        return true;

                    } else {

                        return super.onInterceptTouchEvent(ev);

                    }

                } else if(mListViewX != null && isTouchInView(mListViewX, ev)) {

                    if(atTopOrEnd(deltaY)) {

                        return true;

                    } else {

                        return false;

                    }

                } else {

                    return super.onInterceptTouchEvent(ev);

                }

            }

            case MotionEvent.ACTION_UP: {

                return super.onInterceptTouchEvent(ev);

            }

            default:

                break;

        }

        return super.onInterceptTouchEvent(ev);

    }

 

    //如果listView滑到顶端时当前事件向上滑动,需要scrollview接管, 在底端时类似。

    private boolean atTopOrEnd(int len) {

        int count = mListViewX.getCount();

        int topId = mListViewX.getFirstVisiblePosition();

        int endId = mListViewX.getLastVisiblePosition();

        if((endId == count - 1 && len < 0)) {

            View lastView = mListViewX.getChildAt(mListViewX.getChildCount() - 1);

            if(lastView.getBottom() == mListViewX.getHeight()) {

                return true;

            }

        }

        if(topId == 0 && len > 0) {

            View firstView = mListViewX.getChildAt(topId);

            if(firstView.getTop() == 0) {

                return true;

            }

        }

        return false;

    }

 

    //判断点击事件是否在当前view中

    private boolean isTouchInView(View view, MotionEvent event) {

        int x = (int) event.getRawX();

        int y = (int) event.getRawY();

        int[] local = new int[2];

        view.getLocationOnScreen(local);

        int subVX = local[0];

        int subVY = local[1];

        int subWidth = view.getWidth();

        int subHeight = view.getHeight();

        if(x > subVX && x < subVX + subWidth && y > subVY && y < subVY + subHeight) {

            return true;

        }

        return false;

    }

 

    public void setListViewX(ListViewX listViewX) {

        mListViewX = listViewX;

    }

 

    public void setViewPager(ViewPager viewPager) {

        mViewPager = viewPager;

    }

}</code>

采用内部拦截法: 重写listview 的 dispatchTouchEvent() 方法

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

<code>public class ListViewX extends ListView {

 

    private static final String TAG = "ListViewX";

 

    private int mLastX = 0;

    private int mLastY = 0;

 

    public ListViewX(Context context) {

        super(context);

    }

 

    public ListViewX(Context context, AttributeSet attrs) {

        super(context, attrs);

    }

 

    public ListViewX(Context context, AttributeSet attrs, int defStyleAttr) {

        super(context, attrs, defStyleAttr);

    }

 

    //ListView 在 ScrollView中显示需要处理

    @Override

    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

        int widthMode = MeasureSpec.getMode(widthMeasureSpec);

        int widthSize = MeasureSpec.getSize(widthMeasureSpec);

        int heightMode = MeasureSpec.getMode(heightMeasureSpec);

        int heightSize = MeasureSpec.getSize(heightMeasureSpec);

        int width;

        int height;

        if(widthMode == MeasureSpec.AT_MOST && heightMode == MeasureSpec.AT_MOST) {

            width = MeasureSpec.makeMeasureSpec(500, MeasureSpec.AT_MOST);

            height = MeasureSpec.makeMeasureSpec(500, MeasureSpec.AT_MOST);

        } else if(widthMode == MeasureSpec.AT_MOST) {

            width = MeasureSpec.makeMeasureSpec(500, MeasureSpec.AT_MOST);

            height = heightMeasureSpec;

        } else if(heightMode == MeasureSpec.AT_MOST) {

            width = widthMeasureSpec;

            height = MeasureSpec.makeMeasureSpec(500, MeasureSpec.AT_MOST);

        } else {

            width = widthMeasureSpec;

            height = heightMeasureSpec;

        }

        super.onMeasure(width, height);

    }

 

    //requestDisallowInterceptTouchEvent参数为false表示父容器拦截

    @Override

    public boolean dispatchTouchEvent(MotionEvent ev) {

        int x = (int) ev.getX();

        int y = (int) ev.getY();

 

        switch (ev.getAction()) {

            case MotionEvent.ACTION_DOWN: {

                //父容器不拦截

                getParent().requestDisallowInterceptTouchEvent(true);

                break;

            }

            case MotionEvent.ACTION_MOVE: {

                int deltaX = x - mLastX;

                int deltaY = y - mLastY;

                if(atTopOrEnd(deltaY)) {

                    getParent().requestDisallowInterceptTouchEvent(false);

                }

                break;

            }

            case MotionEvent.ACTION_UP: {

                break;

            }

            default:

                break;

        }

 

        mLastX = x;

        mLastY = y;

 

        return super.dispatchTouchEvent(ev);

    }

 

    //如果listView滑到顶端时当前事件向上滑动,需要scrollview接管, 在底端时类似。

    private boolean atTopOrEnd(int len) {

        int count = getCount();

        int topId = getFirstVisiblePosition();

        int endId = getLastVisiblePosition();

        if((endId == count - 1 && len < 0)) {

            View lastView = getChildAt(getChildCount() - 1);

            if(lastView.getBottom() == getHeight()) {

                return true;

            }

        }

        if(topId == 0 && len > 0) {

            View firstView = getChildAt(topId);

            if(firstView.getTop() == 0) {

                return true;

            }

        }

        return false;

    }

}</code>

巴扎黑巴扎黑2892 Tage vor541

Antworte allen(2)Ich werde antworten

  • PHP中文网

    PHP中文网2017-04-17 17:58:37

    因为ViewPager的onTouch事件已经“吃掉”了手势,你可以重写ViewPager的onTouch事件,假如手势是竖直方向的移动,return false

    Antwort
    0
  • 伊谢尔伦

    伊谢尔伦2017-04-17 17:58:37

    要重写listview的测量子Item的宽高的方法,你这个网上搜一下很多的

    Antwort
    0
  • StornierenAntwort