Touch Handling

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:

  • onTouch

  • onTouchMoved

  • onTouchCancelled

  • onTouchEnded

Touch Reciever

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.

return undefined or do not return anything

In JavaScript terms undefined == false. However, with the sf-core@2.0.10 implementation, returning undefined works same as returning true. This will change with the future implementations. It is advised to return true or false with the touch events.

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.

iOS

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:

  1. onTouch is fired for the underlying component (parent)

  2. onTouch is fired for the component

  3. 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)

  4. if the component has a gesture regarding scroll or swipe gestures, that gesture event is fired. Skip steps 5 & 6

  5. if the finger is moved and no swipe or scroll gesture is present, onTouchMoved event is fired for the underlying component

  6. if the finger is moved and no swipe or scroll gesture is present, onTouchMoved event is fired for the component

  7. 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

  8. As the finger has been lifted, onTouchEnded event is fired for the underlying component

  9. As the finger has been lifted, onTouchEnded event is fired for the component

Android

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:

  1. As the user touches to the to the component, onTouch event is fired for the component

  2. 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

  3. 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

  4. 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

  5. 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.

  6. 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)

  7. 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)

  8. As the finger has been lifted, onTouchEnded event is fired for the component (Skip step 9)

  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.

Do not set touch events

Setting touch events for those type of components might break the expected behavior, especially on Android

Mimic Press

FlexLayouts are commonly used a button like touch receivers. In that case, just setting onTouchEnded event will not be sufficient. Smartface has developed a util library to solve the common problems to mimic the press action on the View components.

Simple addPressEvent
Simple addPressEvent
const touch = require("sf-extension-utils").touch;
//inside page load
touch.addPressEvent(myButtonLikeFlexLayoutOrLabel, ()=> {
alert("myButtonLikeFlexLayoutOrLabel has been pressed");
});

Using the implemented behavior above will solve the problems of moving finger out of the component or the component is in a scrolling container. The first argument is the target component, is required. The second argument is press event function, is required The third argument is the effect manager for giving the press effect, is optional. If the third argument is not supplied, this method will add the default effects to give and remove the pressed effect. Those pressed effects are differing per platform: iOS Background color property of the target is darkened using the TinyColor library at the rate of 22.74. If the target does not have this background color property, it is ignored Android Elevation of the target is increased by 14 with a short animation. Regular Button has elevation at 7 by default. If the target is given an elevation of 7 as the base, it will be increased to 21. The same behavior can be observed with the Button component.

Adding touch effects
Adding touch effects
const touch = require("sf-extension-utils").touch;
const Color = require('sf-core/ui/color');
//inside page load
target.backgroundColor = Color.BLUE; //regular state
touch.addPressEvent(target, ()=> {
alert("target has been pressed");
}, {
startTouchEffect: ()=> {target.backgroundColor = Color.RED;},
endTouchEffect: ()=> {target.backgroundColor = Color.BLUE;}
});