{ "id": "176187", "key": "TIMOB-28446", "fields": { "issuetype": { "id": "1", "description": "A problem which impairs or prevents the functions of the product.", "name": "Bug", "subtask": false }, "project": { "id": "10153", "key": "TIMOB", "name": "Titanium SDK/CLI", "projectCategory": { "id": "10100", "description": "Titanium and related SDKs used in application development", "name": "Client" } }, "fixVersions": [], "resolution": null, "resolutiondate": null, "created": "2021-05-13T18:15:09.000+0000", "priority": { "name": "Critical", "id": "1" }, "labels": [], "versions": [ { "id": "21177", "name": "Release 9.3.1", "archived": false, "released": true, "releaseDate": "2021-01-26" }, { "id": "21050", "name": "Release 10.0.0", "archived": false, "released": true, "releaseDate": "2021-05-17" } ], "issuelinks": [ { "id": "59265", "type": { "id": "10003", "name": "Relates", "inward": "relates to", "outward": "relates to" }, "inwardIssue": { "id": "176195", "key": "TIMOB-28454", "fields": { "summary": "Android: \"longpress\" event wrongly fires when tapping a touch disabled view", "status": { "description": "The issue is considered finished, the resolution is correct. Issues which are closed can be reopened.", "name": "Closed", "id": "6", "statusCategory": { "id": 3, "key": "done", "colorName": "green", "name": "Done" } }, "priority": { "name": "Low", "id": "4" }, "issuetype": { "id": "1", "description": "A problem which impairs or prevents the functions of the product.", "name": "Bug", "subtask": false } } } } ], "assignee": { "name": "jquick", "key": "jquick", "displayName": "Joshua Quick", "active": true, "timeZone": "America/Los_Angeles" }, "updated": "2021-05-18T21:40:35.000+0000", "status": { "description": "The issue is open and ready for the assignee to start work on it.", "name": "Open", "id": "1", "statusCategory": { "id": 2, "key": "new", "colorName": "blue-gray", "name": "To Do" } }, "components": [ { "id": "10202", "name": "Android", "description": "Android Platform" } ], "description": "We have been advised by Google that we need proper ripple effects in our app. Unfortunately, Titanium does not cover these requirements so far:\r\n\r\n- Ripple effect on image views\r\n- Ripple effect on labels\r\n- Ripple effect on child views of other views (like a label inside a card view)\r\n\r\nPositive side now: Ripple effects inside list views / table views are working very well already - even with child views!", "attachment": [], "flagged": false, "summary": "Android: Issues with touch feedback / ripple effect", "creator": { "name": "hknoechel", "key": "hansknoechel", "displayName": "Hans Knöchel", "active": true, "timeZone": "Europe/Berlin" }, "subtasks": [], "reporter": { "name": "hknoechel", "key": "hansknoechel", "displayName": "Hans Knöchel", "active": true, "timeZone": "Europe/Berlin" }, "environment": null, "comment": { "comments": [ { "id": "458679", "author": { "name": "jquick", "key": "jquick", "displayName": "Joshua Quick", "active": true, "timeZone": "America/Los_Angeles" }, "body": "First, let me clarify that \"touchFeedback\" is applied to a view's \"background\". It is not applied to a view's foreground components. We document this here...\r\nhttps://docs.appcelerator.com/platform/latest/#!/api/Titanium.UI.View-property-touchFeedback\r\n\r\n*Regarding ImageView:*\r\nIf you display a completely *opaque* image in an {{ImageView}} via its \"image\" property (such as a camera photo), then you won't see the \"touchFeedback\" effect. This is not a bug. This is the expected behavior since touch feedback is applied to the background which is completely covered up. However, if you display the image via the \"backgroundImage\" instead, then you will see the touch feedback effect. The downside of using \"backgroundImage\" is it doesn't load images async and it ignores JPEG EXIF orientation. _(Note that if the foreground \"image\" had transparency, then you would see the ripple effect happening in the transparent areas which I know is the behavior some people want.)_\r\n\r\nIf you want touch feedback to be applied to the {{ImageView}} object's \"image\" property (which a foreground drawable), then this is really a feature request. We would need to add new APIs, such as \"imageTouchFeedback\" and \"imageTouchFeedbackColor\" so that Titanium will know to apply the native {{RippleDrawable}} to the foreground drawable.\r\n\r\n*Regarding Label:*\r\nTouch feedback does work on {{Ti.UI.Label}}. The below proves it.\r\n{code:javascript}\r\nconst window = Ti.UI.createWindow();\r\nwindow.add(Ti.UI.createLabel({\r\n\ttext: \"\\n Hello World \\n\",\r\n\ttouchFeedback: true,\r\n\ttouchFeedbackColor: \"yellow\",\r\n}));\r\nwindow.open();\r\n{code}\r\n\r\nAlthough, if you're using Titanium 10.0.0, then I recommend you use {{Ti.UI.Button}} instead with it's [style|https://docs.appcelerator.com/platform/latest/#!/api/Titanium.UI.Button-property-style] property set to {{Titanium.UI.BUTTON_STYLE_TEXT}}. The material text-only button will show you the ripple effect for free and this constant is supported on iOS as well. This assumes you are simulating a text-only button to begin with of course. _(Why else would you want a touch feedback effect on a label?)_\r\n{code:javascript}\r\nconst window = Ti.UI.createWindow();\r\nconst button = Ti.UI.createButton({\r\n\ttitle: \"Click Me\",\r\n\tstyle: Ti.UI.BUTTON_STYLE_TEXT,\r\n});\r\nbutton.addEventListener(\"click\", function() {\r\n\talert(\"Button clicked!\");\r\n});\r\nwindow.add(button);\r\nwindow.open();\r\n{code}\r\n\r\n*Regarding Child Views:*\r\nBy default, all Titanium view's have touch enabled. This means they will steal the native touch event from the parent hierarchy, preventing the parent from showing the touch feedback effect. You will have to set the \"touchFeedback\" property on the child views to {{false}} so that the parent can receive the native touch event needed to trigger the native touch feedback/ripple effect. Which leads to...\r\n\r\n*Regarding CardView:*\r\nSee the code example for CardView with labels in ticket [TIMOB-28082]. This shows touch feedback in the CardView correctly working the way you want it. Note that all CardViews show the ripple effect by default and we do have to disable touch on the child labels so that the native event will pass through to the parent.\r\n", "updateAuthor": { "name": "jquick", "key": "jquick", "displayName": "Joshua Quick", "active": true, "timeZone": "America/Los_Angeles" }, "created": "2021-05-13T21:55:46.000+0000", "updated": "2021-05-13T21:55:46.000+0000" }, { "id": "458681", "author": { "name": "jquick", "key": "jquick", "displayName": "Joshua Quick", "active": true, "timeZone": "America/Los_Angeles" }, "body": "I wrote up a feature request for a new \"imageTouchFeedback\" property for {{Ti.UI.ImageView}}.\r\nPlease see ticket: [TIMOB-28447]", "updateAuthor": { "name": "jquick", "key": "jquick", "displayName": "Joshua Quick", "active": true, "timeZone": "America/Los_Angeles" }, "created": "2021-05-14T06:06:08.000+0000", "updated": "2021-05-14T06:06:08.000+0000" }, { "id": "458682", "author": { "name": "hknoechel", "key": "hansknoechel", "displayName": "Hans Knöchel", "active": true, "timeZone": "Europe/Berlin" }, "body": "Most of the issues can be resolved by setting the \"touchEnabled\" property to \"false\". Thank you for that hint! The one critical issue remaining is that the click event handling seem broken if a child view (like a label) is inside a non-card-view parent. See the following case for reference:\r\n{code:js}\r\nvar win = Ti.UI.createWindow({\r\n backgroundColor: '#fff'\r\n});\r\n\r\nvar childView = Ti.UI.createView({ backgroundColor: 'red' });\r\nvar cardView = Ti.UI.Android.createCardView({ width: 300, height: 300, backgroundColor: 'green' });\r\ncardView.add(Ti.UI.createLabel({ text: 'Title', touchEnabled: false }));\r\nchildView.add(cardView);\r\n\r\nchildView.addEventListener('click', () => {\r\n\talert('Click on child view!');\r\n})\r\n\r\nvar scrollableView = Ti.UI.createScrollableView({\r\n views: [childView]\r\n});\r\n\r\nscrollableView.addEventListener('longpress', () => {\r\n\talert('Longpress!')\r\n});\r\n\r\nwin.add(scrollableView);\r\nwin.open();\r\n{code}", "updateAuthor": { "name": "hknoechel", "key": "hansknoechel", "displayName": "Hans Knöchel", "active": true, "timeZone": "Europe/Berlin" }, "created": "2021-05-14T08:28:50.000+0000", "updated": "2021-05-14T08:28:50.000+0000" }, { "id": "458685", "author": { "name": "jquick", "key": "jquick", "displayName": "Joshua Quick", "active": true, "timeZone": "America/Los_Angeles" }, "body": "[~hknoechel], I'm able to reproduce the \"longpress\" event issue. Thanks for the reproducible case.\r\n\r\nWe're actually running into a similar issue mentioned below where taps are being registered as long-presses because we're not handling the initial down press in this case... but we don't want to return true via the {{GestureListener.onDown()}} listener because that would prevent the touch from being propagated to the parent which you need for the touch feedback/ripple effect to work. _(sigh)_\r\nhttps://stackoverflow.com/questions/24326530/long-press-in-gesturedetector-also-fires-on-tap\r\n\r\nI just wrote up a custom \"longpress\" solution in Java. I'll see about getting a PR for this tomorrow once I'm done fully testing it.\r\n\r\nAlternatively, you could work-around this by using the Android-only [longclick|https://titaniumsdk.com/api/titanium/ui/view.html#longclick] event, but the downside to this event is it is fired as you drag within the view. That's the native behavior and you might not like it.", "updateAuthor": { "name": "jquick", "key": "jquick", "displayName": "Joshua Quick", "active": true, "timeZone": "America/Los_Angeles" }, "created": "2021-05-18T06:55:44.000+0000", "updated": "2021-05-18T06:55:44.000+0000" }, { "id": "458686", "author": { "name": "hknoechel", "key": "hansknoechel", "displayName": "Hans Knöchel", "active": true, "timeZone": "Europe/Berlin" }, "body": "This is awesome news, thank you so much, Josh! :-)", "updateAuthor": { "name": "hknoechel", "key": "hansknoechel", "displayName": "Hans Knöchel", "active": true, "timeZone": "Europe/Berlin" }, "created": "2021-05-18T06:57:56.000+0000", "updated": "2021-05-18T06:57:56.000+0000" }, { "id": "458690", "author": { "name": "jquick", "key": "jquick", "displayName": "Joshua Quick", "active": true, "timeZone": "America/Los_Angeles" }, "body": "[~hknoechel], I made a separate ticket for the \"longpress\" issue. Please see: [TIMOB-28454]", "updateAuthor": { "name": "jquick", "key": "jquick", "displayName": "Joshua Quick", "active": true, "timeZone": "America/Los_Angeles" }, "created": "2021-05-18T21:40:35.000+0000", "updated": "2021-05-18T21:40:35.000+0000" } ], "maxResults": 6, "total": 6, "startAt": 0 } } }