【问题标题】:How to prevent ScrollView from intercepting click/touch events of the view behind it?如何防止 ScrollView 拦截其背后视图的点击/触摸事件?
【发布时间】:2014-11-08 11:51:09
【问题描述】:

我在 FrameLayout 中有一个 ScrollView 和一个 ImageView。 ImageView 在滚动视图的后面

我的 ScrollView 有一个透明空间(LinearLayout s_layout_transparent,高度为 925px)。

所以通过这个透明空间可以看到我的ImageView但是不能点击

我试图添加一些值 (android:clickable="false" android:focusable=" android:focusableInTouchMode="false") 来滚动视图以防止它拦截点击事件ImageView 但这根本不起作用。

这是我的布局:

<FrameLayout 
    xmlns:android="http://schemas.android.com/apk/res/android" 
    android:layout_width="match_parent" 
    android:layout_height="match_parent">
<LinearLayout
        android:gravity="top|center_horizontal"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:paddingRight="10dp"
        >
    <ImageView
            android:visibility="visible"
            android:id="@+id/s_imgv_splash"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:src="@drawable/temp_detail_screen_splash"
            android:adjustViewBounds="true"
            android:scaleType="fitXY"/>
</LinearLayout>
<com.dreambox.android.saven.Views.ScrollView
        android:id="@+id/s_scrollview_event_detail"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:scrollbars="none"
        android:visibility="visible"
        android:clickable="false"
        android:focusable="false"
        android:focusableInTouchMode="false"
        >
    <LinearLayout
            android:orientation="vertical"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:clickable="false"
            android:focusableInTouchMode="false"
            android:focusable="false">
        <LinearLayout
                android:id="@+id/s_layout_transparent"
                android:layout_gravity="center_vertical"
                android:layout_width="match_parent"
                android:layout_height="925px"
                android:orientation="horizontal"
                android:background="@color/trasparent"
                android:clickable="false"
                android:focusableInTouchMode="false"
                android:focusable="false">
        </LinearLayout>
        <LinearLayout...>
        <LinearLayout...>
    </LinearLayout>
</com.dreambox.android.saven.Views.ScrollView>
</FrameLayout>

【问题讨论】:

  • 制作自定义滚动视图
  • 你能说得更具体点吗?如您所见,我的滚动视图已经是自定义的 ScrollView
  • 等等,从头开始。只需将 Imageview 移动到滚动视图内的线性布局内即可。
  • 我故意留下ImageView,因为我希望当scrollview向上滚动时,imageView慢慢被scrollview内容覆盖。注意:滚动视图不仅有透明的线性布局,而且在下面也有一些线性布局(你可以在我的布局中看到
  • 我有一个建议:在ImageView 之上的每个View 使用`requestDisallowInterceptTouchEvent`。

标签: android android-layout touch-event


【解决方案1】:

如果您可以用空视图(我们称之为 dummyView)填充透明部分,您可以执行类似...

dummyView.setOnTouchListener(new View.OnTouchListener() {
    @Override
    public boolean onTouch(View view, MotionEvent event) {
        // pass on the touch event to the ImageView
        s_imgv_splash.dispatchTouchEvent(event);
        // returning true because we handled the event
        return true;
    }
});

【讨论】:

    【解决方案2】:

    我解决了这个问题。为目前/将来面临相同问题的人发布此信息。 感谢马赫什的建议。根据 Mahesh 的建议,我就是这样做的。这是我的 layout.xml

    <?xml version="1.0" encoding="utf-8"?>
    <RelativeLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        android:id="@+id/scroll_view"
        android:background="#ffffff"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
    
        <TextView
            android:id="@+id/bg_tv"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="TestView"
            android:layout_marginTop="5dip"/>
    
        <View android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:background="@android:color/background_dark"
            android:alpha="0"
            />
    
        <ScrollView
            android:id="@+id/sv"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            >
    
           <LinearLayout
                android:id="@id+/wrapper"
                android:layout_width="fill_parent"
                android:layout_height="fill_parent"
                android:background="@android:color/transparent"
                android:orientation="vertical" >
    
               <LinearLayout
                   android:id="@+id/dummy"
                    android:layout_width="fill_parent"
                    android:background="@android:color/transparent"
                    android:layout_height="500dip"
                    android:orientation="vertical"/>
    
               <LinearLayout
                   android:id="@+id/scroll_"
                  android:layout_width="fill_parent"
                  android:layout_height="fill_parent"
                  android:orientation="vertical" >
    
                 ................
                 ................
    
    
              </LinearLayout>
    
            </LinearLayout>
    
        </ScrollView>
    
    </RelativeLayout>
    

    添加 LinearLayouts @id/dummy 和 @id/scroll_ 后,我无法点击 TextView @id/bg_tv。下面的代码解决了我的问题。

    //dispatch touch events
    mDummyView = findViewById(R.id.dummy);
    mDummyView.setOnTouchListener(new View.OnTouchListener() {
        @Override
        public boolean onTouch(View view, MotionEvent motionEvent) {
            mTextView.dispatchTouchEvent(motionEvent);
            return true;
        }
    });
    
    mLayout = (LinearLayout)findViewById(R.id.scroll_);
    mLayout.setOnTouchListener(new View.OnTouchListener() {
        @Override
        public boolean onTouch(View view, MotionEvent motionEvent) {
            if (scrollPercent <= 0.25f) {
                mTextView.dispatchTouchEvent(motionEvent);
                return true;
            }
            return false;
        }
    });
    

    在 mLayout 的情况下,只有在 scrollView 到达屏幕底部后才会调度 TouchEvents。

    PS:我是第一次写答案。如果您发现格式很差,或者答案没有按照应有的方式书写,我很抱歉。

    【讨论】:

      【解决方案3】:

      我不能给出确切的解决方案

      检查它可能会有所帮助

      yourscrollview.setOnTouchListener(new OnTouchListener() {
      
                  @Override
                  public boolean onTouch(View v, MotionEvent event) {
                      if(touch exists inside imageview boundaries)
                      {
                          do imageview click action
                      }
                      return false;
                  }
              })
      

      【讨论】:

        【解决方案4】:

        ScrollView 在 FrameLayout 中排在最后,因此它具有优先权。

        当你的带有 ImageView 的 LinearLayout 被激活时,你需要说

        findViewById(R.id.s_scrollview_event_detail).setVisibility(View.INVISIBLE)
        

        反之亦然,当激活 ScrollView 时,“兄弟”Layout 视图必须设置为不可见。

        【讨论】:

          【解决方案5】:

          检查事件的坐标是否在您希望接收事件的视图范围内。如果有匹配项,请使用performClick 方法将事件传递到所需的视图。这是一个例子:

          override fun onCreate(savedInstanceState: Bundle?) {
              ....
              val viewUnderDummySpace = findViewById<View>(R.id.your_textview_or_button_or_image)
              val dummySpace = scrollView.findViewById<View>(R.id.dummy_space)
              dummySpace.setOnTouchListener(object : View.OnTouchListener {
                  override fun onTouch(p0: View?, event: MotionEvent?): Boolean {
                      event?.let {
                          if (event.getAction() == MotionEvent.ACTION_UP) {
                              if (inViewInBounds(viewUnderDummySpace, event.rawX.toInt(), event.rawY.toInt())) {
                                  //Click performed within bounds of the desired view
                                  viewUnderDummySpace.performClick()
                              }
                          }
                      }
          
                      return true
                  }
              })
          }
          
          private var outRect = Rect()
          private var location = IntArray(2)
          
          private fun inViewInBounds(view: View, x: Int, y: Int): Boolean {
              view.getDrawingRect(outRect)
              view.getLocationOnScreen(location)
              outRect.offset(location[0], location[1])
              return outRect.contains(x, y)
          }
          

          【讨论】:

            【解决方案6】:

            我还使用了滚动偏移,它在点击事件上给出了完美的结果。

            blockingViewInScroll.setOnTouchListener(new View.OnTouchListener() {
                @Override
                public boolean onTouch(View view, MotionEvent event) {
                    event.offsetLocation(-scrollView.getScrollX(), -scrollView.getScrollY());
                    blockedViewUnderScroll.dispatchTouchEvent(event);
                    return true;
                }
            });
            

            【讨论】:

              【解决方案7】:

              如果您的自定义视图在其 onTouchEvent 期间调用requestDisallowInterceptTouchEvent(true),其中操作为 ACTION_DOWN,则滚动视图及其非父视图将拦截触摸事件,直到您使用 false 调用 requestDisallowInterceptTouchEvent

              您可以通过此视频了解更多信息: https://www.youtube.com/watch?v=EZAoJU-nUyI

              【讨论】:

              • 您的答案可以通过额外的支持信息得到改进。请edit 添加更多详细信息,例如引用或文档,以便其他人可以确认您的答案是正确的。你可以找到更多关于如何写好答案的信息in the help center
              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多