Need to reliably detect the left and right swipe on whole NestedScrollView. I tried various options but nothing worked so far! Please refer the code below -
Following is the layout
<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@android:color/white"
android:fitsSystemWindows="false"
android:orientation="vertical">
<com.google.android.material.appbar.AppBarLayout
android:id="@+id/appbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:animateLayoutChanges="true">
<androidx.appcompat.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:contentInsetStartWithNavigation="0dp"
app:popupTheme="@style/ThemeOverlay.AppCompat.Light">
<LinearLayout
android:id="@+id/title_layout"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:orientation="vertical">
<TextView
android:id="@+id/subtitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:textAlignment="center"
android:textFontWeight="400"
android:maxLines="1"
android:text="@string/app_name"
android:textSize="18sp"
tools:ignore="UnusedAttribute" />
</LinearLayout>
</androidx.appcompat.widget.Toolbar>
</com.google.android.material.appbar.AppBarLayout>
<androidx.core.widget.NestedScrollView
android:id="@+id/article"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fadeScrollbars="false"
app:layout_behavior="@string/appbar_scrolling_view_behavior">
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
app:strokeColor="@null"
android:id="@+id/coverImage"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="350dp"
android:adjustViewBounds="true"
android:gravity="center"
android:scaleType="fitCenter"
android:src="@mipmap/ic_launcher"
android:background="@android:color/holo_blue_bright"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
android:contentDescription="@string/app_name" />
<WebView
android:id="@+id/webView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintTop_toBottomOf="@+id/coverImage"/>
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.core.widget.NestedScrollView>
</androidx.coordinatorlayout.widget.CoordinatorLayout>
The activity code is as follows
package com.example.nestedswipe
import android.annotation.SuppressLint
import android.content.Context
import android.os.Bundle
import android.util.Log
import android.view.GestureDetector
import android.view.MotionEvent
import android.view.View
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import com.example.nestedswipe.MainActivity.GestureListener.Companion.SWIPE_THRESHOLD
import com.example.nestedswipe.MainActivity.GestureListener.Companion.SWIPE_VELOCITY_THRESHOLD
import com.example.nestedswipe.databinding.ActivityMainBinding
import kotlin.math.abs
class MainActivity : AppCompatActivity() {
lateinit var binding: ActivityMainBinding
@SuppressLint("SetJavaScriptEnabled", "ClickableViewAccessibility")
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
val view: View = binding.root
setContentView(view)
binding.webView.settings.javaScriptEnabled = true
binding.webView.loadUrl("https://www.basicwebsiteexample.com/media/")
val gestureDetector = GestureDetector(this, GestureListener(this))
binding.article.setOnTouchListener { view, event ->
Log.d("DEMO", "Article OnTouch")
gestureDetector.onTouchEvent(event)
}
binding.webView.requestDisallowInterceptTouchEvent(true)
binding.webView.setOnTouchListener { view, event ->
Log.d("DEMO", "Webview OnTouch")
gestureDetector.onTouchEvent(event)
}
}
class GestureListener(private var context : Context) : GestureDetector.SimpleOnGestureListener() {
companion object {
private const val SWIPE_THRESHOLD = 100
private const val SWIPE_VELOCITY_THRESHOLD = 100
}
override fun onFling(
e1: MotionEvent,
e2: MotionEvent,
velocityX: Float,
velocityY: Float
): Boolean {
Log.d("DEMO", "onFling")
var result = false
try {
val diffY = e2.y - e1.y
val diffX = e2.x - e1.x
if (abs(diffX) > abs(diffY)) {
if (abs(diffX) > SWIPE_THRESHOLD && abs(velocityX) > SWIPE_VELOCITY_THRESHOLD) {
result = if (diffX > 0) {
//Toast.makeText(context, "Swipe Right", Toast.LENGTH_SHORT).show()
Log.d("DEMO", "Swipe Right")
true
} else {
//Toast.makeText(context, "Swipe Left", Toast.LENGTH_SHORT).show()
Log.d("DEMO", "Swipe Left")
true
}
}
}
} catch (exception: Exception) {
exception.printStackTrace()
}
return result
}
}
}
Build.gradle
implementation 'androidx.core:core-ktx:1.8.0'
implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.3.1'
implementation "androidx.constraintlayout:constraintlayout:2.1.4"
implementation "com.google.android.material:material:1.9.0"
The touch events on Image area are properly detected and swipes are predicted properly. Logcat result is
19:50:44.531 D Article OnTouch
19:50:44.548 D Article OnTouch
19:50:44.582 D Article OnTouch
19:50:44.582 D onFling
19:50:44.582 D Swipe Left
However the swipes on the Webview are not reliably detected. Some swipes are detected while other are lost which are proper swipe.
Logcat shows results as below
19:55:54.485 D Webview OnTouch
19:55:54.530 D Webview OnTouch
19:55:54.547 D Webview OnTouch
19:55:54.563 D Webview OnTouch
19:55:54.579 D Webview OnTouch
19:55:54.596 D Article OnTouch
19:55:54.612 D Article OnTouch
19:55:54.629 D Article OnTouch
19:55:54.645 D Article OnTouch
19:55:54.662 D Article OnTouch
19:55:54.679 D Article OnTouch
19:55:54.696 D Article OnTouch
19:55:54.850 D Article OnTouch
19:55:54.851 D onFling
I suspect that touch events are getting partially consumed by Webview and Article view. Thus even if Fling is detected, it is partial and thus Swipe event is not recognised.
How to reliably detect the left and right swipe on whole NestedScrollView?