Is GestureOverlayView implemented in B4A? (to catch swipe gesture on screen)

NFOBoy

Active Member
Licensed User
Longtime User
Looking through the forum, I have seen a few references to programmers wanting to do Sliding Panels, while capturing if the user starts the slide on something besides the Panel. (or for any other reason, wanting to capture a gesture within the current activity, that starts somewhere other than the panel)

(other forum topics related or similiar)
http://www.b4x.com/forum/basic4android-updates-questions/11227-catching-swipe-gesture.html
http://www.b4x.com/forum/basic4andr...estures-buttons-labels-problem.html#post51557


Reading the link below, it appears this functionality is built into the API?
http://developer.android.com/resources/articles/gestures.html
If so, how do I enable/use/code this functionality?

If not, I have found a workaround. I use the Gestures.SetOnTouchListener on all current Views (my buttons, my labels, etc...)

But, since I still want to parse when a click event comes through, I have to figure out what the user intent is based on length of time (short and no movement to be considered a click, medium with no movement to be a long_press), then pass the user-intent and call the button_click event, but as far as I can tell, I can't pass the Sender remotely? I can write the code such that I call a button_click event with some other variable.. but wow does this seem anti-intuitive to what I want, which is just to catch swipe events, no matter where they occur, and pass click events to the buttons/views below.

I've tried setting up a transparent panel on top, but can not figure out a method to not-consume the event, if it is just a click. (so that it passes it to a button underneath)

Anyone ever figure this out?
Would the GestureOverlayView even work? (it appears that it would)

Ross
 

NFOBoy

Active Member
Licensed User
Longtime User
Erel,

I have.

The log shows that when the .SetOnTouchListener initially gets called, it is with the Down event. In order to determine if the user is doing a click or a move event, have to let .SetOnTouchListener return TRUE to continue. (can't have it return FALSE at the beginning, or else no Move events are ever captured)

Then, can determine if the next event is either a Move or an Up event, and can then return FALSE if no Move Event, but the initial Down event is consumed, so nothing gets passed to the underlying button, except maybe the Up event.

But what to do with that? I can programatically determine if the user wanted to pass a click or a longpress, as I can calculate the time delay between the Down and the Up events, but is there a way to put the Down event back on the stack to send to the View below?

I had it working so that the user could double click (by setting a Global variable to catch the button-down state the first time), with the second click event not including a move event that would then return false and pass to the underlying view. But that doesn't really follow any known Android functionality that I know about.

Ross

Edit: the functionality I'm trying to reproduce is exactly what happens in the App Drawer or Homescreens. The user can tap anywhere on the screen, and start a swipe that is translated to a movement for the screen, whether it is started on an app icon or not. If the user doesn't swipe (i.e. a click event, and it's not on an app icon, then nothing, if the click event is on top of an icon, then start the app, if it is a longpress event, then take whatever action should be started by a longpress.

I'm not trying to do anything that fancy, I have just been trying to figure out how to use the Sliding Panels example code with swipes started on Views other than a Panel, so can swap Panels that way.

Ugh! :)
 
Last edited:
Upvote 0

Erel

B4X founder
Staff member
Licensed User
Longtime User
You can store the first touch position. If you decide that this is not a valid swipe you can use this sub to "click" on the correct view:
B4X:
Sub SendClick(P As Panel, x As Int, y As Int)
   For i = P.NumberOfViews - 1 To 0 Step -1
      Dim v As View
      v = P.GetView(i)
      If v.Left < x AND v.Left + v.Width > x AND v.Top < y AND v.Top + v.Height > y Then
         Dim r As Reflector
         r.Target = v
         r.RunMethod("performClick")
         Return
      End If
   Next
End Sub
There is an assumption that the panel covers the complete screen.
 
Upvote 0

NFOBoy

Active Member
Licensed User
Longtime User
Erel,

I will try that first thing in the morning! If so (which I'm sure it will), genius!

As I've been pondering the past few hours before heading to bed, would intercepting with all Views on screen be possible?

(your idea seems best approach)

Have an idea buzzing around inside that would use the Gestures.SetOnTouchListener.

Basic Idea:

Loop thru Activity.NumberofViews
Assign each .GetView to Gestures.SetOnTouchListener
Within the Sub Called by SetOnTouchListener, pass code to Sender to mimic as if Touch/or LongPress are called, if a Move event Generated, use method similiar to Sliding Panels to move all Views x/y (or whatever way you want screen to respond to move event)

Anyway, will be experimenting after the Sheep are all done jumping thru my head.

Thanks much, again!

Ross
 
Upvote 0

edgeryder1000

Member
Licensed User
Longtime User
You can store the first touch position. If you decide that this is not a valid swipe you can use this sub to "click" on the correct view:
B4X:
Sub SendClick(P As Panel, x As Int, y As Int)
   For i = P.NumberOfViews - 1 To 0 Step -1
      Dim v As View
      v = P.GetView(i)
      If v.Left < x AND v.Left + v.Width > x AND v.Top < y AND v.Top + v.Height > y Then
         Dim r As Reflector
         r.Target = v
         r.RunMethod("performClick")
         Return
      End If
   Next
End Sub
There is an assumption that the panel covers the complete screen.

Old post I know, but I'm trying to do the same thing and "Dim As Reflector" is not working :( Is there a certain lib you need to use it?
 
Upvote 0

edgeryder1000

Member
Licensed User
Longtime User
Here you go :) The coding is terrible I know. Everything works nicely if the gestures listen on the same panel as the buttons and scrolling only works on the "screen" of the calculator.

Thanks for offering to help :)
 

Attachments

  • CalculatorSourceDebug.zip
    21.8 KB · Views: 261
Upvote 0

edgeryder1000

Member
Licensed User
Longtime User
Wow thanks :sign0098: Having someone improve my code is just so awesome!
Notes:
*There will be more panels later that and all will be animated so I think I might need ChangeRight and ChangeLeft?
*I don't understand why it lagged before and I haven't used logging before (hehe) and I don't know what it does (other than for debugging?)
*Thanks a ton, enjoy your food, and looking forward to your explainings of your edits :)
 
Upvote 0

Informatix

Expert
Licensed User
Longtime User
I replaced onSingleTapUp by:
B4X:
Sub Gesture_onTouch(Action As Int, X As Float, Y As Float, MotionEvent As Object)
   If Action = 1 AND FirstScroll Then 'UP
      If   pnlScientific.Left = 0 Then
         SendClick(pnlScientific, X, Y-128)
      Else
         SendClick(pnlSimple, X, Y-128)
      End If
   Else If Action = 0 Then 'DOWN
      FirstScroll = True
   End If
End Sub
and onFling by onScroll:
B4X:
Sub Gesture_onScroll(distanceX As Float, distanceY As Float, MotionEvent1 As Object, MotionEvent2 As Object)
   If FirstScroll Then
      ChangeScreen
      FirstScroll = False
   End If
End Sub
When the finger is down, I allow the user to scroll. If the user scrolls, FirstScroll becomes False and the click won't be triggered. When the finger is up, if he didn't scroll, the click is passed to the underlying view.

All motion events are detected by the same view (the gestures panel). So if you do two taps on it quickly, even if you want to click on two separate buttons, the two clicks are interpreted as a double tap, not two single taps. That's why you can't use these events in this particular case.

And a swipe gesture is detected by a Scroll. The fling gesture is used to know the velocity of the gesture (how fast it has been done).

I'm wondering why you don't use the AHViewPager library for your project.
 
Upvote 0

LucaMs

Expert
Licensed User
Longtime User
This thread has almost two years of life, I know.

But I do not know if the issue has been resolved elsewhere.

NFOBoy wrote:
"I use the Gestures.SetOnTouchListener on all current Views (my buttons, my labels, etc ...)"

This is uncomfortable. It would also be necessary to run all the events of each view with Reflection, not only use "r.RunMethod ("PerformClick")".

The thread ends with:
"I'm using now AHPageViewer"

I have not tested that library but reading its description, I guess that it allows switching between panels added in AHPageContainer and this is not enough for my goal.

I would get the opportunity to move from one activity to another, using the Transitions, when the user slides the finger (keeping active the views below, of course).

Is the solution already in some other thread?



Thanks in advance
 
Upvote 0

LucaMs

Expert
Licensed User
Longtime User
Unfortunately I have not explained well (Erel, stay in Italy a year, so after I'll be able to talk more easily with you... in Italian :)).

I do not want to maintain a shared view between the two activities.
I wish swipe (or slide or how i should say!) a finger on a activity, intercept this movement to launch another activity (with a transition effect).

But in order to intercept the movement of the finger, if you use a transparent panel at full screen, the view below become "inactive."

onTouch on each view is not... etc.

StdActionBar, i suppose, swipes "pages" (panels?) not Activities.


(uhm maybe I could start another activity from within those pages/panels? I'll have to think about this :))
 
Upvote 0
Top