androidkotlinandroid-recyclerviewandroid-swipe

Error parameter specified as non-null is null when use swipe touch listener in recyclerView - Android


I am using from bellow class for detect swipe in recyclerView:

open class OnSwipeTouchListener(context: Context) : View.OnTouchListener {
    var context: Context? = context

    private val gestureDetector = GestureDetector(context, GestureListener())

    fun onTouchs(event: MotionEvent): Boolean {
        return gestureDetector.onTouchEvent(event)
    }

    private inner class GestureListener : GestureDetector.SimpleOnGestureListener() {

        private val SWIPE_THRESHOLD = 100
        private val SWIPE_VELOCITY_THRESHOLD = 100

        override fun onDown(e: MotionEvent): Boolean {
            return true
        }

        override fun onSingleTapConfirmed(e: MotionEvent): Boolean {
            onTouchs(e)
            return true
        }


        override fun onFling(@NonNull e1: MotionEvent,
                             @NonNull e2: MotionEvent,
                             @NonNull velocityX: Float,
                             @NonNull velocityY: Float): Boolean {
            val result = false
            try {
                val diffY = e2.y - e1.y
                val diffX = e2.x - e1.x
                if (Math.abs(diffX) > Math.abs(diffY)) {
                    if (Math.abs(diffX) > SWIPE_THRESHOLD && Math.abs(velocityX) > SWIPE_VELOCITY_THRESHOLD) {
                        if (diffX > 0) {
                            //onSwipeRight()
                        } else {
                            onSwipeLeft()
                        }
                    }
                } else {
                    // onTouch(e);
                }
            } catch (exception: Exception) {
                exception.printStackTrace()
                Crashlytics.logException(exception)
            }

            return result
        }
    }

    //    @SuppressLint("ClickableViewAccessibility")
    override fun onTouch(@NonNull v: View, @NonNull event: MotionEvent): Boolean {
        v.performClick()
        return gestureDetector.onTouchEvent(event)
    }

    //open fun onSwipeRight() {}

    open fun onSwipeLeft() {}
}

But when I scrolling to end list get me bellow crash when I arrive to end list:

java.lang.IllegalArgumentException: Parameter specified as non-null is null: method kotlin.jvm.internal.Intrinsics.checkParameterIsNotNull, parameter e1
        at xx.xx.xx.tools.OnSwipeTouchListener$GestureListener.onFling(OnSwipeTouchListener.kt)
        at android.view.GestureDetector.onTouchEvent(GestureDetector.java:667)
        at xx.xx.xx.tools.OnSwipeTouchListener.onTouch(OnSwipeTouchListener.kt:65)

And here is my SwipeController.kt:

internal class SwipeController(private val swipeControllerInter: SwipeControllerInter) : ItemTouchHelper.Callback() {
    private var swipeBack = false

    interface SwipeControllerInter {
        fun left()

//        fun right()
    }

    override fun getMovementFlags(recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder): Int {
        return makeMovementFlags(0, LEFT or RIGHT)
    }

    override fun onMove(recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder, target: RecyclerView.ViewHolder): Boolean {
        return false
    }

    override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) {

    }

    override fun convertToAbsoluteDirection(flags: Int, layoutDirection: Int): Int {
        if (swipeBack) {
            swipeBack = false
            return 0
        }
        return super.convertToAbsoluteDirection(flags, layoutDirection)
    }

    override fun onChildDraw(c: Canvas,
                             recyclerView: RecyclerView,
                             viewHolder: RecyclerView.ViewHolder,
                             dX: Float, dY: Float,
                             actionState: Int, isCurrentlyActive: Boolean) {

        if (actionState == ACTION_STATE_SWIPE) {
            if (dX > 0) {
                // then swiping right.
                //swipeControllerInter.right()
            } else if (dX < 0) {
                // then swiping left.
                swipeControllerInter.left()
            }
            // If dX == 0 then at at start position.
        } else {
            super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive)
        }

        if (actionState == ACTION_STATE_SWIPE) {
            setTouchListener(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive)
        }
        super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive)
    }

    @SuppressLint("ClickableViewAccessibility")
    private fun setTouchListener(c: Canvas,
                                 recyclerView: RecyclerView,
                                 viewHolder: RecyclerView.ViewHolder,
                                 dX: Float, dY: Float,
                                 actionState: Int,
                                 isCurrentlyActive: Boolean) {

        recyclerView.setOnTouchListener { v, event ->
            swipeBack = event.action == MotionEvent.ACTION_CANCEL || event.action == MotionEvent.ACTION_UP
            false
        }
    }
}

And I am using in my MainFragment.kt:

val swipeController = SwipeController(this)
val itemTouchhelper = ItemTouchHelper(swipeController)
itemTouchhelper.attachToRecyclerView(recycler_view)

recycler_view.setOnTouchListener(object : OnSwipeTouchListener(activity!!) {
    override fun onSwipeLeft() {
        val intent = Intent(activity, MainActivityMou::class.java)
        intent.putExtra("ONE", 1)
        intent.flags = Intent.FLAG_ACTIVITY_CLEAR_TOP
        startActivity(intent)
        activity!!.finish()
    }
})

Solution

  • Resolved my problem, I changed onTouch to:

    override fun onTouch(v: View, event: MotionEvent): Boolean {
        if (event.action == MotionEvent.ACTION_MOVE) {
            v.performClick()
            return gestureDetector.onTouchEvent(event)
        } else {
            return false
        }
    }
    

    OR:

    override fun onFling(e1: MotionEvent,
                         e2: MotionEvent,
                         velocityX: Float,
                         velocityY: Float): Boolean {
                val result = false
            if(e1 != null && e2 != null){
                try {
                    val diffY = e2.y - e1.y
                    val diffX = e2.x - e1.x
                    if (Math.abs(diffX) > Math.abs(diffY)) {
                        if (Math.abs(diffX) > SWIPE_THRESHOLD && Math.abs(velocityX) > SWIPE_VELOCITY_THRESHOLD) {
                            if (diffX > 0) {
                                //onSwipeRight()
                            } else {
                                onSwipeLeft()
                            }
                        }
                    } else {
                        // onTouch(e);
                    }
                } catch (exception: Exception) {
                    exception.printStackTrace()
                    Crashlytics.logException(exception)
                }
              }
                return result
            }
        }