5

I am developing a custom UI on top of ExoPlayer, and I noticed that the controls (PlaybackControlView) hide when I touch the screen, not when I click.

I wanted to change to a click and checked how I can change the event listener, but so far could not find an easy solution. I checked the source SimpleExoPlayerView.java and I noticed that it actually is hardcoded:

  @Override
  public boolean onTouchEvent(MotionEvent ev) {
    if (!useController || player == null || ev.getActionMasked() != MotionEvent.ACTION_DOWN) {
      return false;
    }
    if (controller.isVisible()) {
      controller.hide();
    } else {
      maybeShowController(true);
    }
    return true;
  }

So far I could think of two solutions. One is to change the ExoPlayer's source code, but I do not like it since I will have to make modifications every time I update the ExoPlayer.

The second solution I could think of is simply to try to handle it myself, for example, to add my own listeners, and show and hide the controls myself. I have not tried this yet, but it seems possible.

Is there another better solution, like overriding the listeners, etc?

Update: I am using custom UI by inflating exo_playback_control_view.xml

Ahmed Alnabhan
  • 608
  • 1
  • 9
  • 13
AMD
  • 1,278
  • 4
  • 15
  • 33

3 Answers3

5

By looking at this answer you can see that an OnTouchListener#onTouch is called BEFORE the View#onTouchEvent so you can set an OnTouchListener to the view, consume the MotionEvent and it will not be passed onto the onTouchEvent method.

For example, using this code only "onTouch: LISTENER!!!" is logged when touching the view, and not "onTouchEvent: onTouchEvent!!!":

EDIT - to add your request for a click event handling I added the use of GestureDetector, using this answer - so now upon click "onSingleTapUp: TAP DETECTED" is logged as well.

public class TouchingView extends View {

    private final static String TAG="TouchingView";

    private OnTouchListener touchListener;
    private GestureDetector gestureDetector;

    public TouchingView(Context context) {
        super(context);
        touchListener = new TouchListener();
        gestureDetector = new GestureDetector(getContext(), 
                         (GestureDetector.OnGestureListener) touchListener);
        setOnTouchListener(touchListener);
    }

    public TouchingView(Context context, AttributeSet attrs) {
        super(context, attrs);
        touchListener = new TouchListener();
        gestureDetector = new GestureDetector(getContext(), 
                         (GestureDetector.OnGestureListener) touchListener);
        setOnTouchListener(touchListener);
    }

    public TouchingView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        touchListener = new TouchListener();
        gestureDetector = new GestureDetector(getContext(), 
                         (GestureDetector.OnGestureListener) touchListener);
        setOnTouchListener(touchListener);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        Log.d(TAG, "onTouchEvent: onTouchEvent!!!"); //not logged
        return super.onTouchEvent(event);
    }

    private class TouchListener extends GestureDetector.SimpleOnGestureListener 
                                implements View.OnTouchListener{

        @Override
        public boolean onTouch(View v, MotionEvent event) {
            Log.d(TAG, "onTouch: LISTENER!!!"); //logged upon every touch event. twice upon click (for UP and for DOWN)
            gestureDetector.onTouchEvent(event);
            return true; //preventing the view's onTouchEvent from firing
        }

        @Override
        public boolean onSingleTapUp(MotionEvent e) { //you can override onSingleTapConfirmed if you don't want doubleClick to fire it
            Log.d(TAG, "onSingleTapUp: TAP DETECTED"); //logged only upon click
            return true;
        }
    }
}
Community
  • 1
  • 1
et_l
  • 1,868
  • 17
  • 29
  • Thank you. I did like you suggest here and it works. So in this case I am actually using the second method, where I cancel the default action, and handle myself, for example on onClick. – AMD Jan 01 '17 at 13:08
  • I'm glad you like it. Please accept it if it's a good answer for your question :) – et_l Jan 01 '17 at 13:12
  • Your solution correctly stops the ontouch actions, however it does not work when using onClick – AMD Jan 01 '17 at 13:25
  • Added handling of click by using `GestureDetector` and `SimpleOnGestureListener`, using [this answer](http://stackoverflow.com/a/19539206/3836051) – et_l Jan 01 '17 at 15:31
  • Can you help me on this @et_l , how can i use your class on my View to use your touch custom methods – Babar Shamsi Aug 11 '22 at 09:47
  • 1
    @BabarShamsi It's been a long while since I wrote this answer. But from glancing at the question and my answer -- the solution here is to NOT use touch methods (the problem was it is hardcoded, so they are consumed beforehand and not passed on) and use click events instead. That was the request. That's what the `return true` does in the `onTouch` method of the inner class. The constructor creates an instance of this inner class and attaches it as a listener. I have no idea what your use case is, but from your wording it sounds different. I suggest creating a new question for that. – et_l Sep 05 '22 at 08:56
4

I am facing same problem but i resolved this problem by flowing set controllerHideOnTouch property of exoplayerview

i used by following line of code

mExoPlayerView!!.controllerHideOnTouch=false

its working for me

Prince Kumar
  • 593
  • 2
  • 7
  • 17
1

To always show controls on exo player use hide_on_touch property:

<com.google.android.exoplayer2.ui.PlayerView
    android:id="@+id/video_view"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    app:controller_layout_id="@layout/layout_exo_player"
    app:show_timeout="0"
    app:hide_on_touch="false"/>
SANAT
  • 8,489
  • 55
  • 66