In Smartface Framework, touches to the UI components are managed through the API of sf-core. sf-core is exposing four events on the View since version 2.0.10:
If the View is touchEnabled, it can receive the touches. If the object is not touchEnabled, that component cannot capture touch events and built-in native gestures will not work. Also, the touch is relayed to the underlying object is receiving the touch.\ In Android, since sf-core version 2.0.10, touch events can decide to bubble the event up to the underlying object with a return value from the touch events.
- return false - Touch is not handled by the component. It will be passed to the underlying object. All future events and gestures with this touch will not be fired for the same component. This approach totally applies differently for focusable views such as textbox, textarea , materialtextbox & etc. Focusable views does not relayed to the underlying object. Unlike other views, focusable views have a few more events. In Android, consuming focusable view's onTouch events or similars will be blocking other listeners. So to eliminate such kind of cases, consuming should be always be false that will allow you to listen other events as well.
- return true - Touch is handled by the component. Gestures and touch events will work normally for the component. Underlying components will not receive touch.
:::warn iOS Touch Bubble
On iOS, returning true or false at the touch callbacks(events) will not have any effect. Also on iOS, touches will always be relayed to the parent component and cannot be prevented like Android. In order to make a conditional touch handing, please implement appropiate logic on the project side with e.g. flags
In iOS, if the underlying object is accepting some gestures (such as SwipeView Page, ScrollView, ListView) those events are both fired on the component and the underlying component.
Touch Life Cycle
In the normal cycle of touch, it starts with onTouch event and ends with onTouchEnded event. onTouchMoved or onTouchCancelled events might fire in between.
Main logic in iOS, touch is first captured by all of the underlying components, from the most parent and all events to the touched component will be fired in order. Following events occur in order with a touch in iOS:
- onTouch is fired for the underlying component (parent)
- onTouch is fired for the component
- if the component has press gesture, regarding the velocity and direction of the touch onPress effect might be skipped. If the finger is moving fast and in the direction of scroll, then onPress will not be fired (go to step 4); else onPress will be fired (go to step 8)
- if the component has a gesture regarding scroll or swipe gestures, that gesture event is fired. Skip steps 5 & 6
- if the finger is moved and no swipe or scroll gesture is present, onTouchMoved event is fired for the underlying component
- if the finger is moved and no swipe or scroll gesture is present, onTouchMoved event is fired for the component
- If the finger has moved outside of the component, onTouchCancelled event might be fired for the component. In that case, onTouchEnded event and other future touch events (such as onTouchMoved) will not be fired for the same component and the same touch action
- As the finger has been lifted, onTouchEnded event is fired for the underlying component
- As the finger has been lifted, onTouchEnded event is fired for the component
Main logic in Android is, touch is to be captured by the touched object. If it is not capturing it, it is relayed to the parent. Following events occur in order with a touch in Android:
- As the user touches to the to the component, onTouch event is fired for the component
- If that event is returning false, all future touch & gesture events for the same component and for the same touch will not be fired. Also, the touch will be relayed to the underlying component (any component, which is overlapping below). If the touch is relayed to the underlying component, start from the same event for that component
- If that event is returning true, then the all of the future events for this touch will be handled by the current component as long as the touch remains on the component
- If the finger moves on the component, onTouchMoved will be fired. If the underlying component has swipe or scroll gesture and has not attached any onTouchMoved event, then this event will not be fired for the underlying component; It will swipe or scroll for the underlying component
- If the finger moves outside the component and underlying component does not have any built-in gestures for swipe or scroll, then onTouchMoved will be fired for the component with isInside value as false.
- If the finger moves outside the component and underlying component has built-in gestures for swipe or scroll, then onTouchCancelled event will be fired for the component. If onTouchCancelled event is fired, onTouchEnded event will not be fired for this touch action (Skip step 8)
- If the finger moves outside the component and underlying component has built-in gestures for swipe or scroll, onTouchMoved or onScroll event will be fired for the underlying component without going through all of the touch life-cycle (Skip step 8)
- As the finger has been lifted, onTouchEnded event is fired for the component (Skip step 9)
- If the finger has moved outside the component and underlying component has built-in gestures for swipe or scroll and the finger has been lifted, onTouchEnded event is fired for the underlying component
Gesture Enabled Components
Following components are known to be accepting gestures or having pre-defined touch events.
Setting touch events for those type of components might break the expected behavior, especially on Android