1

The app has some UI that receives clicks, e.g. an EditText to receive focus, and a buttons (not in the screenshot below) that triggers an action. But the whole UI piece also needs to slide to the side to reveal Views beneath. I've implemented it as a View that contains the UI and moves on drag (visible), and a top-layer View that's invisible but collects drag input.

The code below partially works in that the visible View drags when the invisible view is dragged, and it can sense the difference between a drag and a click, but despite returning false in View.OnTouchListener.onTouch(), the Views underneath the invisible draggable View do not receive the clicks.

How do I get the clicks to pass through to Views underneath, without disturbing the working drag functionality?

import android.view.MotionEvent
import android.view.View

class ViewHorizontalSlider(dragView: View,
                           private val moveView: View,
                           private val distancePx: Int = 100) {

    private var xPos = 0f
    private var downX = 0f
    private var isOnClick = false
    private val scrollThreshold = 6

    init {
         dragView.setOnTouchListener { _, event ->
            when (event.actionMasked) {
                MotionEvent.ACTION_DOWN -> {
                    downX = event.x
                    xPos = moveView.x - event.rawX
                    isOnClick = true
                    return@setOnTouchListener true
                }
                MotionEvent.ACTION_MOVE -> {
                    var newX = event.rawX + xPos
                    if (newX > distancePx) newX = distancePx.toFloat()
                    if (newX < 0) newX = 0f
                    moveView.x = newX

                    val movement = Math.abs(downX - event.x)
                    if (isOnClick && (movement > scrollThreshold)) {
                        isOnClick = false;
                    }
                    return@setOnTouchListener true
                }
                MotionEvent.ACTION_UP, MotionEvent.ACTION_CANCEL -> {
                    if (isOnClick) {
                        return@setOnTouchListener false
                    } else {
                        return@setOnTouchListener true
                    }
                } else -> {
                    return@setOnTouchListener false
            }
            }
        }
    }

In the screenshot, the "P1" etc are EditText Views. The whole coloured panel should be draggable to the right (like P1, to reveal the Delete UI), but it should also be possible to click (on the invisible overlay draggable View) but give focus to the EditText underneath. I expected to just return false in the code above, but that appears not to be enough for the click to pass through.

<android.support.constraint.ConstraintLayout 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="72dp"
    >

    <ImageView
        android:id="@+id/delete"
        android:layout_width="@dimen/perspective_delete_slide"
        android:layout_height="match_parent"
        android:src="@drawable/ic_delete"
        android:scaleType="center"
        android:background="@color/black_light"
        android:contentDescription="@string/delete_perspective"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        />

    <android.support.constraint.ConstraintLayout
        android:id="@+id/container"
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:focusableInTouchMode="true"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintBottom_toBottomOf="parent"
        tools:layout_marginStart="72dp"
        >

        <EditText
            android:id="@+id/name"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:background="@null"
            android:inputType="text|textCapSentences"
            android:layout_marginStart="12dp"
            android:layout_marginEnd="12dp"
            android:visibility="visible"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintEnd_toStartOf="@id/marker"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent"
            />

        <View
            android:id="@+id/marker"
            android:layout_width="8dp"
            android:layout_height="match_parent"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toEndOf="@id/name"
            app:layout_constraintTop_toTopOf="parent"
            />

        <View
            android:id="@+id/draggable"
            android:layout_width="0dp"
            android:layout_height="0dp"
            android:clickable="false"
            android:focusable="false"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent"
            />

    </android.support.constraint.ConstraintLayout>
</android.support.constraint.ConstraintLayout>

The UI

Ollie C
  • 28,313
  • 34
  • 134
  • 217
  • I've tried creating another intermediate View between the moving View below and the draggable View above, and when a click is detected creating a MotionEvent using the x/y, and dispatching that to the click-catcher View in the middle, but that doesn't appear to work either. – Ollie C Aug 31 '18 at 14:23
  • trying to figure out the same thing. – filthy_wizard Apr 25 '19 at 12:48

1 Answers1

0

if you want menu on swipe then you need this Swipe on menu or like that Swipe on Menu 2

Gaurav Mandlik
  • 525
  • 1
  • 9
  • 42
  • 1
    The UI is not using RecyclerView, and we do not want to use a library to do this which is quite specific functionality. Note that it's swipe-to-reveal, not swipe-to-delete - the swipe is limited to revealing the delete option, and the delete button then needs to be clicked to delete. – Ollie C Aug 31 '18 at 12:58
  • 1
    I am looking for feedback on the code I posted, not third-party libraries which may or may not meet the requirements (especially to allow clicks through the draggable UI segment). – Ollie C Aug 31 '18 at 13:45
  • I cannot see a way to fix the code and AndroidSwipeLayout is actually a very good fit, and handles passing clicks through. Thank you. – Ollie C Aug 31 '18 at 15:51