Last active
August 15, 2021 13:23
-
-
Save jpriebe/b14d00a660464171464083f2f7b91784 to your computer and use it in GitHub Desktop.
Appcelerator Titanium code for managing scrollviews inside of scrollviews
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
function NestedScrollViewManager (parent_view) | |
{ | |
// Appcelerator Titanium code for managing scrollviews inside of scrollviews (not true Android | |
// NestedScrollViews, but just a horizontal scrollview inside of a vertical scrollview). | |
// | |
// If you want to put a horizontal scrollview inside a vertical scrollview (like the Netflix app UI), | |
// it seems to work reasonably well on iOS. But on android, the user experience is very janky. | |
// Unless the user's drag movements are nearly exactly horizontal, there will be some movement of | |
// the parent scrollview, and then it becomes very difficult to scroll the child view. Flinging is | |
// almost impossible. | |
// | |
// With a little code to detect the horizontal movement, we can temporarily lock the parent view | |
// from scrolling, making the behavior closer to that of ios. | |
// | |
// call it like this: | |
// | |
// var NestedScrollViewManager = require ('/path/to/NestedScrollViewManager'); | |
// var nsvm = new NestedScrollViewManager (v_scrollview); | |
// nsvm.add_child_view (h_scrollview); | |
// | |
// (assuming v_scrollview is the parent scrollview containing h_scrollview) | |
var _parent_view = parent_view; | |
var _child_views = []; | |
var _current_child = null; | |
var _startx, | |
_starty, | |
_direction_detected = false; | |
function log_event (evt, msg) | |
{ | |
var log_msg = "[NSVM] "; | |
if (evt) | |
{ | |
log_msg += "<<" + evt + ">>"; | |
} | |
if (msg) | |
{ | |
log_msg += " " + msg; | |
} | |
Ti.API.info (log_msg); | |
} | |
function set_scrolling_enabled (p, c) | |
{ | |
_parent_view.scrollingEnabled = p; | |
// if user is interacting with one specific child, enable/disable its scrolling | |
if (_current_child !== null) | |
{ | |
_current_child.scrollingEnabled = c; | |
return; | |
} | |
// otherwise, apply the change to all children | |
for (var i = 0; i < _child_views.length; i++) | |
{ | |
_child_views[i].scrollingEnabled = c; | |
} | |
} | |
function on_parent_view_touchstart (e) | |
{ | |
log_event ("parent_view.touchstart"); | |
_current_child = null; | |
set_scrolling_enabled (true, true); | |
} | |
function on_child_view_touchstart (e) { | |
log_event ("touchstart"); | |
_startx = e.x; | |
_starty = e.y; | |
_direction_detected = false; | |
set_scrolling_enabled (false, true); | |
e.cancelBubble = true; | |
} | |
function on_child_view_touchmove (e){ | |
if (_direction_detected) | |
{ | |
return; | |
} | |
log_event ("touchmove"); | |
var deltax = Math.abs (e.x - _startx); | |
var deltay = Math.abs (e.y - _starty); | |
var distance = Math.sqrt (deltax * deltax + deltay * deltay); | |
if (distance > 30) | |
{ | |
if (deltax > deltay) | |
{ | |
log_event ("touchmove", "direction = vertical"); | |
set_scrolling_enabled (false, true); | |
} | |
if (deltay > deltax) | |
{ | |
log_event ("touchmove", "direction = vertical"); | |
set_scrolling_enabled (true, false); | |
} | |
_direction_detected = true; | |
} | |
} | |
this.add_child_view = function (child_view) | |
{ | |
if (Ti.Platform.osname !== 'android') | |
{ | |
return; | |
} | |
child_view.addEventListener('touchstart', function (e) { | |
_current_child = child_view; | |
on_child_view_touchstart (e); | |
}); | |
child_view.addEventListener('touchmove', function (e) { | |
_current_child = child_view; | |
on_child_view_touchmove (e); | |
}); | |
_child_views.push (child_view); | |
}; | |
if (Ti.Platform.osname !== 'android') | |
{ | |
return; | |
} | |
log_event (null, "creating new NSVM..."); | |
_parent_view.addEventListener ('touchstart', on_parent_view_touchstart); | |
} | |
module.exports = NestedScrollViewManager; |
Very useful code snippet here! Thanks for sharing.
This is awesome!
I modified it slightly to support multiple horizontal ScrollViews. See my fork.
Sorry, Jei -- I missed your fork, and meanwhile, I was busy doing something similar. I posted my change to support adding multiple child views. Mine's a little different in that it doesn't need underscore/lodash.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Great work!