【问题标题】:OnClickListener on scrollView滚动视图上的 OnClickListener
【发布时间】:2013-05-27 15:51:40
【问题描述】:

我有一个包含很多元素的滚动视图

ScrollView scroller = (ScrollView)findViewById(R.id.scrollView);

我需要将 onClickListener 附加到滚动视图,所以我这样做了

scroller.setOnClickListener(new OnClickListener() { 
            @Override
            public void onClick(View v) { 
                // This is all you need to do to 3D flip
                AnimationFactory.flipTransition(viewAnimator, FlipDirection.LEFT_RIGHT); 
            }

        });

但是当我触摸时这不会被触发。有什么想法吗?

【问题讨论】:

  • 你确定它没有被触发吗?尝试记录它或在 onClick 方法中显示一个 Toast,看看它是否有效。
  • 是的,我试过了。它没有被触发。视图里面有很多子视图是不是因为这个?

标签: android


【解决方案1】:

最好的解决方案似乎是将LinearLayout 放入ScrollView 并在其上设置setOnClickListener

<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="match_parent"
        android:id="@+id/myLayout"
        android:clickable="true"
        android:orientation="vertical">

       <!-- content here -->
   </LinearLayout>
</ScrollView>

在活动中:

LinearLayout lin = (LinearLayout) fragment.rootView.findViewById(R.id.myLayout);

lin.setOnTouchListener(new setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            // Whatever
        }
});

【讨论】:

  • 确保不要给 ScrollView 添加填充,否则这些区域将无法点击
【解决方案2】:

这是因为ScrollView 的孩子正在获取用户的触摸事件,而不是ScrollView。您必须将android:clickable="false" 属性设置为ScrollView 的每个子级,onClickListener 才能在ScrollView 上工作。

否则,替代方法可能是在每个 ScrollView 的子级上设置 onClickListener 并处理它。

【讨论】:

    【解决方案3】:

    您需要在 ScrollView 的子级上直接设置setOnClickListener

    由于ScrollView 可以有只有一个孩子,您可以简单地使用这种方法:

    ScrollView scrollView = //...
    
    View.OnClickListener mOnClickListener = new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            // ...
    }
    
    //Set the onClickListener directly on the ScrollView's child
    scrollView.getChildAt(0).setOnClickListener(mOnClickListener);
    

    【讨论】:

    • 这是正确答案。它有效,这里建议的替代方案是......次优。
    • 此解决方案的唯一问题是您必须等到ScrollView 的孩子添加到树中才能设置侦听器。这并不漂亮,但我只是在运行 getChildAt(0) 之前使用了一个帖子来等待它发生
    【解决方案4】:

    2020 年 12 月 22 日更新

    遗憾的是,这也会在每次滚动事件后触发。

    通过在ScrollView 上使用View.OnTouchListener 而不是View.OnClickListener 并检测手指离开屏幕的MotionEvent.ACTION_UP,这实际上是问题的答案,没有任何奇怪的情况。

    为确保它不是滚动,然后保存MotionEvent.ACTION_DOWN 的先前触摸屏x、y 值并将其与MotionEvent.ACTION_UP 的值进行比较。如果它们不相等,那么用户在离开屏幕之前肯定是在移动手指(即滚动)。

    int mXOld, mYOld; // field values to save the tap down on the ScrollView 
    
    scrollView.setOnTouchListener(new View.OnTouchListener() {
        @Override
        public boolean onTouch(View v, MotionEvent event) {
    
            int x = (int) event.getX();
            int y = (int) event.getY();
    
            if (event.getAction() == MotionEvent.ACTION_DOWN) {
                mXOld = x;
                mYOld = y;
            } else if (event.getAction() == MotionEvent.ACTION_UP) {
    
                if (x == mXOld || y == mYOld) {  // detecting it's not a horizontal/vertical scrolling in ScrollView
                    // HERE add the code you need when the ScrollView is clicked
                    Toast.makeText(MainActivity.this, "Click", Toast.LENGTH_SHORT).show();
                    return false;
                }
            }
    
            return false;
        }
    });
    

    原答案:与问题不同的奇怪案例

    我的问题有点不同,所以我想分享它..

    我有一个ScrollView,我必须在其宽度和高度中使用match_parent;我有一个内部TextView,它以ScrollView 为中心。

    TextView的文字可以很长,占据ScrollView的整个高度,有时也可以很短,所以顶部和底部会有空白区域,所以设置@987654334每当文本很短时,@TextView 上的 @ 对我没有帮助,因为我希望空白区域也检测到单击事件;而且ScrollView 上的OnClickListener 也不起作用..

    所以,我通过在ScrollView 上设置OnTouchListener 并将代码放入MotionEvent.ACTION_UP 来解决这个问题,这样它就可以通过将手指离开屏幕来模拟完整的点击。

    private View.OnTouchListener mScrollViewTouchListener = new View.OnTouchListener() {
        @SuppressLint("ClickableViewAccessibility")
        @Override
        public boolean onTouch(View v, MotionEvent event) {
            if (event.getAction() == MotionEvent.ACTION_UP) { 
                // DO Something HERE...
            }
            return false;
        }
    };
    

    【讨论】:

    • 遗憾的是,这也会在每次滚动事件后触发。
    • @user2965003 感谢您的评论.. 你完全正确.. 我的共享案例与问题不同.. 因为我只是想拦截对TextView 的点击,这就是在不触及ScrollView 的情况下正常工作,但问题是当TextView 没有占据整个ScrollView 高度时,在这种情况下ScrollView 中没有滚动,我的问题是免费的ScrollView 的 /blank 区域不会拦截点击,因为它不是 TextView 的一部分,所以我使用了这个 .. 让我看看我是否能解决你的问题
    • @user2965003 我设法解决了您的问题..请检查更新的答案...希望与您合作
    • 干得好。实际上我昨天不得不解决这个问题并使用了 GestureDetector,覆盖了 onSingleTapUp。必须作为独立答案发布以显示代码。
    【解决方案5】:

    正如@Zain 所指出的,有时需要为 Scrollview 的整个区域捕获 OnClick,而子项可能更小或不可见。 为了规避检测为 onClick 的滚动,我们使用了 GestureDetector:

    final protected GestureDetector gestureDetector = new GestureDetector(getActivity(),
                new GestureDetector.SimpleOnGestureListener() {
    
                    @Override
                    public boolean onSingleTapUp(MotionEvent e) {
                        return true;
                    }
    
                });
    

    在 onCreateView 中

    scrollView.setOnTouchListener(new View.OnTouchListener() {
                @Override
                public boolean onTouch(View v, MotionEvent event) {
                    if(gestureDetector.onTouchEvent(event)){
                        [do stuff]
                    }
    
                    return false;
                }
            });
    

    【讨论】:

      【解决方案6】:

      我觉得你可以自定义一个ScrollView,重写dispatchTouchEvent方法,添加自定义onClick回调。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2016-06-25
        • 2013-03-23
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-08-06
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多