Custom Mobile Scroller
Moderators: Klaus, FourthWorld, heatherlaine, kevinmiller
-
- VIP Livecode Opensource Backer
- Posts: 212
- Joined: Fri Feb 01, 2013 1:31 am
- Location: Palo Alto, CA put williamdjamieso into tEmail / put n@gmail.com after tEmail/ revmail tEmail
- Contact:
Custom Mobile Scroller
Hello. I have a number of stacks built and tested on Android that all function perfectly well except that the native mobile scroller that I am using is intercepting the touch messages to the card after half a centimeter distance is swiped. Has anyone created a custom scroller that works in the message path, or within livecode so that I can intercept messages from the scroller? Anyone have any proposed ideas how to build a really smooth functioning mobile scroller?
Code:
I am using this command to be specific: MobileControlCreate "Scroller"
Device:
I am testing on this device: Samsung Galaxy s3
Object:
I have a sliding object that acts as a switch under the Native scroller object created by the code above.
Problem:
After a few pixel swipe, all mouse and touch messages cease to get passed to any of my livecode scripts and get intercepted by the mobile scroller rendering all my controls on the screen useless.
Thank you all for your input and your help!!
Lets hope that we can come up with one common solution for everyone!
-Will
Code:
I am using this command to be specific: MobileControlCreate "Scroller"
Device:
I am testing on this device: Samsung Galaxy s3
Object:
I have a sliding object that acts as a switch under the Native scroller object created by the code above.
Problem:
After a few pixel swipe, all mouse and touch messages cease to get passed to any of my livecode scripts and get intercepted by the mobile scroller rendering all my controls on the screen useless.
Thank you all for your input and your help!!
Lets hope that we can come up with one common solution for everyone!
-Will
-
- Posts: 192
- Joined: Tue Mar 11, 2014 12:57 pm
Re: Custom Mobile Scroller
I have the scroller created in on opencard - I think I read this somewhere on the forum.
I also use in:
on scrollerDidScroll....
set the top of group "entry" to -vOffset
where group "entry" are all my scrolling fields etc grouped.
This was my own 'trial and error-lots' approach when all other means failed.
I have downloaded the standard LC examples and they work - but I suspect it was because I was using old/new Mobgui objects that I had problems and ended up with my very strange answer - that works.
I'd love to find a way to set the fullscreenmode of me to ?[ideally working like exactfit] to work with a scrolling group. So a scrolling group resizes landscape/portrait on all Android devices. If you figure this out for Android let me know.
One of my scrolling apps is:
https://play.google.com/store/apps/deta ... p&hl=en_GB
I also use in:
on scrollerDidScroll....
set the top of group "entry" to -vOffset
where group "entry" are all my scrolling fields etc grouped.
This was my own 'trial and error-lots' approach when all other means failed.
I have downloaded the standard LC examples and they work - but I suspect it was because I was using old/new Mobgui objects that I had problems and ended up with my very strange answer - that works.
I'd love to find a way to set the fullscreenmode of me to ?[ideally working like exactfit] to work with a scrolling group. So a scrolling group resizes landscape/portrait on all Android devices. If you figure this out for Android let me know.
One of my scrolling apps is:
https://play.google.com/store/apps/deta ... p&hl=en_GB
-
- VIP Livecode Opensource Backer
- Posts: 212
- Joined: Fri Feb 01, 2013 1:31 am
- Location: Palo Alto, CA put williamdjamieso into tEmail / put n@gmail.com after tEmail/ revmail tEmail
- Contact:
Re: Custom Mobile Scroller
Thank you for your input newTronsols
Using the method you described above (using the vScroll) I have got the page to sucessfully scroll without pixelation or "jumping" (movements that should be smooth looking but move more than a few pixels at a time) but the difficult part for me was including the momentum and physics in such a way that the vScroll remained smooth. The main reason I believe is that I created a loop. But when I timed the loop on my android device, it was sending the message to change the vScroll every 130 milliseconds because that is how fast the processor could function, but still made the movement of the scroll very choppy for me.
If anyone has a solution to that issue, that would be another way of solving the overall problem.
-Will
Using the method you described above (using the vScroll) I have got the page to sucessfully scroll without pixelation or "jumping" (movements that should be smooth looking but move more than a few pixels at a time) but the difficult part for me was including the momentum and physics in such a way that the vScroll remained smooth. The main reason I believe is that I created a loop. But when I timed the loop on my android device, it was sending the message to change the vScroll every 130 milliseconds because that is how fast the processor could function, but still made the movement of the scroll very choppy for me.
If anyone has a solution to that issue, that would be another way of solving the overall problem.
-Will
-
- VIP Livecode Opensource Backer
- Posts: 212
- Joined: Fri Feb 01, 2013 1:31 am
- Location: Palo Alto, CA put williamdjamieso into tEmail / put n@gmail.com after tEmail/ revmail tEmail
- Contact:
Re: Custom Mobile Scroller
So I solved the issue. I ended up using a moving group with the touch handlers. It is not perfect like facebook, but I think its as good as the scrolling done by Linkedin's app.
To create momentum, I modified the animation engine to have a new handler called "decelerate". aeMoveTo and aeGeneral have to modified as well.
The next issue was to understand the way people were using their finger to gently and briefly swipe the screen. The problem with this is that the sample rate from the touchMove handler or the MouseMove handler are about 130 milliseconds which is in no way possible on a touch that is less than that. To overcome this I created a repeat loop that samples and builds a list that goes for about 110 milliseconds or so with 10 datapoints, then used that to calculate an initial velocity.
I kept the equations for distance and velocity simple by using physics equations rather than calculus. They are: X = Xi + Vo * t - (0.5) * a * t ^ 2 and Vf = sqrt(Vo^2 - 2 * a * X)
Below I will post the scripts I used to get the mobile scroller to scroll smoothly while accepting light and quick swipes.
Group Script:
Here is the AE General handler rewritten for deceleration
Here is the AE MoveTo handler rewritten for deceleration
Here is a handler that I wrote to stop the momentum when a new touch is placed on the group
Here is the AE Deceleration Handler that I wrote
On the stack I preopened with this:
I also set the layermode of all the objects within the group to "dynamic"
BTW If you dont have the Animation Engine, give up livecoding now because you are making it way more difficult than it needs to be. The animation engine is a must have for anyone that is not an expert programmer and it is opensource and able to be modified. My code above only works with the Animation Engine open in Livecode. Well worth every penny.
I hope this helps anyone else who has been frustrated with trying to get smooth and responsive scrolling of large groups on mobile devices. Old skoolers, please feel free to contribute if you have any improvements!
-Will
To create momentum, I modified the animation engine to have a new handler called "decelerate". aeMoveTo and aeGeneral have to modified as well.
The next issue was to understand the way people were using their finger to gently and briefly swipe the screen. The problem with this is that the sample rate from the touchMove handler or the MouseMove handler are about 130 milliseconds which is in no way possible on a touch that is less than that. To overcome this I created a repeat loop that samples and builds a list that goes for about 110 milliseconds or so with 10 datapoints, then used that to calculate an initial velocity.
I kept the equations for distance and velocity simple by using physics equations rather than calculus. They are: X = Xi + Vo * t - (0.5) * a * t ^ 2 and Vf = sqrt(Vo^2 - 2 * a * X)
Below I will post the scripts I used to get the mobile scroller to scroll smoothly while accepting light and quick swipes.
Group Script:
Code: Select all
local sTracking, yMousei, yLoci, xLoci, sIsScrolling, tUpperBound, tLowerBound
local sIsMoving, sTouchEnded, sMovement
constant kTouchSensitivity = 5 --minimum pixels on a swipe-tap
constant kMoveSensitivity = 0.06 --minimum velocity to create momentum
constant kScreenSwipeTime = 250 --number of milliseconds that are considered a long scroll rather than a swipe
on Momentum
if sIsScrolling is "true" then -- from the initial touch
put "false" into sIsScrolling
put "false" into sIsMoving
##calculate the speed
if abs((item 2 of line 1 of sTracking) - (item 2 of the last line of sTracking)) >= kScreenSwipeTime then --total screen touch time big
put "Scrolling" & cr after sMovement
if ((item 2 of line 1 of sTracking) - (item 2 of line 3 of sTracking)) <> 0 then --Dont move if stopped
put ((item 1 of line 1 of sTracking) - (item 1 of line 3 of sTracking)) / \
((item 2 of line 1 of sTracking) - (item 2 of line 3 of sTracking)) into tInitialVelocity
if abs(tInitialVelocity) > kMoveSensitivity then --No micro adjustments
put "true" into sIsMoving
aeMoveTo (the long id of me), (item 1 of the loc of me), 1, 20000, "decelerate", tInitialVelocity, tUpperBound, tLowerBound
end if
end if
end if
##Makes sure that swipe gets sent too if sScrolling is true, and touch is released
Swipe
end if
end Momentum
on Swipe
if sIsMoving is "false" then
##Swipe --Not caught by the handlers
if line 10 of sMovement is empty then exit Swipe
if abs((item 1 of line 1 of sMovement) - (item 1 of line 10 of sMovement)) > kTouchSensitivity then
put ((item 1 of line 1 of sMovement) - (item 1 of line 10 of sMovement)) / \
((item 2 of line 1 of sMovement) - (item 2 of line 10 of sMovement)) into tInitialVelocity
put "true" into sIsMoving
aeMoveTo (the long id of me), (item 1 of the loc of me), 1, 20000, "decelerate", (1.3 * tInitialVelocity), tUpperBound, tLowerBound
end if
end if
end Swipe
on aeMoveDone
put "false" into sIsMoving
ChangeMovingStatus "false"
end aeMoveDone
on TouchRelease
Momentum
end TouchRelease
on TouchStart
global gGap
if sIsMoving is "true" then
aeCancel
end if
ChangeMovingStatus "true"
put "false" into sIsMoving
put empty into sTracking
put the mouseV into yMousei
put item 1 of the loc of me into xLoci
put item 2 of the loc of me into yLoci
put "true" into sIsScrolling
put the bottom of grp "Nav Bar" of this card + (0.5 * the height of me) into tUpperBound
put the bottom of this card - (0.5 * the height of me) into tLowerBound
startRecording
end TouchStart
on TouchMove pID, pX, pY
if sIsScrolling is "true" then
if the mouse is down then
put the mouseV - yMousei into tDelta
##Create lower and upper boundaries
if item 2 of the loc of me + tDelta > tUpperBound then
set the loc of me to xLoci, tUpperBound
else if item 2 of the loc of me + tDelta < tLowerBound then
set the loc of me to xLoci, tLowerBound
else
set the loc of me to xLoci, yLoci + tDelta
end if
put tDelta & comma & the milliseconds & cr before sTracking
else
Momentum
end if
end if
end TouchMove
on TouchEnd
Momentum
end TouchEnd
on StartRecording
put empty into sMovement
repeat with i = 1 to 10
put the mouseV & comma & the milliseconds & cr before sMovement
wait 10 milliseconds with messages
end repeat
if abs((item 1 of line 1 of sMovement) - (item 1 of line 10 of sMovement)) > kTouchSensitivity then
if sIsScrolling is "false" then
put "false" into sMoving
swipe
end if
end if
end StartRecording
Code: Select all
command aeGeneral
lock screen
local tTimeLost,tFramesLost,tElapsed
local tX,tY,tDuration,tMethod,tEndX,tStartX,tDestX,tStartY,tDestY,tStartTime,tStartVelocity,tDirection
local tUpperBound,tLowerBound
##Stops the move immediately
if tCancel is "true" then
put "false" into tCancel
repeat for each line pControl in the keys of tAEEasing
send "aeMoveDone" to pControl
end repeat
exit aeGeneral
end if
if sAEFrameRate is not a number then aeResetFrameRate
put the milliseconds into tElapsed
put the milliseconds - sTimeTaken into tTimeLost
put tTimeLost - (1000/ sAEFrameRate) into tTimeLost
put ((1000/sAeFramerate) + tTimeLost) into tFramesLost
if tFramesLost<>0 then
put 1000/tFramesLost into tFramesLost
end if
if tFramesLost>sAEFrameRate then put sAEFrameRate into tFramesLost
put tFramesLost into sAERealFrameRate
put the millisecs into sTimeTaken
--lock screen
repeat for each line pControl in the keys of tAEEasing
send "aeEnterFrame" && "aeMoveTo" to pcontrol
put item 1 of tAEEasing[pControl] into tDestX
put item 2 of tAEEasing[pControl] into tDestY
put item 3 of tAEEasing[pControl] into tDuration
put item 4 of tAEEasing[pControl] into tMethod
put item 5 of tAEEasing[pControl] into tStartX
put item 6 of tAEEasing[pControl] into tStartY
put item 7 of tAEEasing[pControl] into tStartTime
put item 8 of tAEEasing[pControl] into tStartVelocity
put item 9 of tAEEasing[pControl] into tUpperBound
put item 10 of tAEEasing[pControl] into tLowerBound
##Determine if the velocity is negative or positive
if tStartVelocity > 0 then
put "down" into tDirection
put tStartY + ((tStartVelocity ^ 2) * 0.5 * (1/sAcceleration)) - 5 into tDestY
else if tStartVelocity < 0 then
put "up" into tDirection
put tStartY + ((-1) * ((tStartVelocity ^ 2) * 0.5 * (1/sAcceleration))) + 5 into tDestY
end if
if tStartTime="pending" then next repeat
switch tMethod
case "in"
put aeEaseIn(tStartX,tDestX,tDuration,the milliseconds-tStartTime,3) into tX
put aeEaseIn(tStartY,tDestY,tDuration,the milliseconds-tStartTime,3) into ty
break
case "out"
put aeEaseOut(tStartX,tDestX,tDuration,the milliseconds-tStartTime,aeExponent) into tX
put aeEaseOut(tStartY,tDestY,tDuration,the milliseconds-tStartTime,aeExponent) into ty
break
case "decelerate"
-- put aeDecelerate(tStartX,the milliseconds-tStartTime,tStartVelocity) into tX
put tStartX into tX
put aeDecelerate(tStartY,the milliseconds-tStartTime,tStartVelocity,tDirection,tDestY,tUpperBound,tLowerBound) into ty
break
case "inOut"
put aeEaseInOut(tStartX,tDestX,tDuration,the milliseconds-tStartTime,3) into tX
put aeEaseInOut(tStartY,tDestY,tDuration,the milliseconds-tStartTime,3) into ty
break
case "bounce"
put aeBounceEaseOut(tStartX,tDestX,tDuration,the milliseconds-tStartTime) into tX
put aeBounceEaseOut(tStartY,tDestY,tDuration,the milliseconds-tStartTime) into ty
break
case "overshoot"
put aeOverShootEaseOut(tStartX,tDestX,tDuration,the milliseconds-tStartTime) into tX
put aeOverShootEaseOut(tStartY,tDestY,tDuration,the milliseconds-tStartTime) into ty
break
default
put aeEaseIn(tStartX,tDestX,tDuration,the milliseconds-tStartTime,1) into tX
put aeEaseIn(tStartY,tDestY,tDuration,the milliseconds-tStartTime,1) into ty
break
end switch
if the milliseconds-tStartTime<tDuration then
set the loc of pControl to tX,tY
else
if tMethod is not "decelerate" then
if tDestx,tDestY is a point then
set the loc of pControl to tDestX,tDestY
end if
else
##Case decelerate ending
end if
delete variable tAeEasing[pControl]
send "aeMoveDone" to pControl
end if
send "aeExitFrame" && "aeMoveTo" to pControl
end repeat
-- unlock screen
unlock screen
put the milliseconds-tElapsed into tElapsed
if the keys of tAeEasing is not empty then
if tElapsed < 1000 / sAEFrameRate then
if "aeGeneral" is not in the pendingmessages then
send "aeGeneral" to me in (1000/sAEFRameRate)- tElapsed millisecs
end if
else
if "aeGeneral" is not in the pendingmessages then
send "aeGeneral" to me in 5 millisecs
end if
end if
end if
-- wait 0 milliseconds with messages
end aeGeneral
Code: Select all
on aeMoveTo
local tControl,tX,tY,tDuration,tMethod,theValue,tVelocity,tUpperBound,tLowerBound
if sAEFrameRate is empty then aeResetFrameRate
repeat with i=1 to paramcount()
if i<paramcount() then
put param(i)&"," after theValue
else
put param(i) after theValue
end if
end repeat
put item 1 of theValue into tControl
put item 2 of theValue into tX
put item 3 of theValue into tY
put item 4 of theValue into tDuration
put item 5 of theValue into tMethod
put item 6 of theValue into tVelocity
put item 7 of theValue into tUpperBound
put item 8 of theValue into tLowerBound
if there is no tControl then return "error:"&&tControl&&"is not a valid control or group or stack"
if word 1 of the long name of tControl is "card" then return "error: can not move a card"
if tX is not an integer then return "error:"&&tX&","&tY&&"is not a valid point"
if tY is not an integer then return "error:"&&tX&","&tY&&"is not a valid point"
if tduration is not a number then return "error:"&&tDuration&&"is not a valid duration"
if tMethod is not among the items of "in,out,inout,bounce,overshoot,decelerate" then return "error:"&&tDuration&&"is not a valid easing method. Must be in,out,inout,bounce,overshoot,decelerate"
if not sAELockMoves then
put tX,tY,tDuration,tMethod,item 1 of the the loc of tControl,item 2 of the loc of tControl,the milliseconds,tVelocity,tUpperBound,tLowerBound into tAeEasing[the long id of tControl]
if "aeGeneral" is not in the pendingmessages then
aeGeneral
end if
else
put tX,tY,tDuration,tMethod,item 1 of the the loc of tControl,item 2 of the loc of tControl,"pending",tVelocity,tUpperBound,tLowerBound into tAeEasing[the long id of tControl]
end if
end aeMoveTo
Code: Select all
local aeExponent, tCancel
command SetAEExponent pExponent
put pExponent into aeExponent
end SetAEExponent
command aeCancel
put "true" into tCancel
end aeCancel
Code: Select all
function aeDecelerate pStart,pElapsedTime,pStartVelocity,pDirection,pFinish,pUpperBound,pLowerBound
try
if pDuration<=pElapsedTime then return pEnd
if pElapsedTime<=0 then return pStart
if pDirection = "down" then
put pStart + pStartVelocity * pElapsedTime - (0.5 * (sAcceleration) * ((pElapsedTime) ^ 2)) into Xf
if pFinish <= Xf or pUpperBound < Xf then
aeCancel
end if
else if pDirection = "up" then
put pStart + pStartVelocity * pElapsedTime - (0.5 * ((-1) * sAcceleration) * ((pElapsedTime) ^ 2)) into Xf
if pFinish > Xf or pLowerBound > Xf then
aeCancel
end if
end if
return Xf
catch theError
return theError
end try
end aeDecelerate
Code: Select all
on preOpenStack
set the compositorTileSize of this stack to 128
set the compositorType of this stack to "software"
set the acceleratedrendering of me to true
set the fullscreenmode of me to "ShowAll"
go to card "Edit Event"
end preOpenStack
BTW If you dont have the Animation Engine, give up livecoding now because you are making it way more difficult than it needs to be. The animation engine is a must have for anyone that is not an expert programmer and it is opensource and able to be modified. My code above only works with the Animation Engine open in Livecode. Well worth every penny.
I hope this helps anyone else who has been frustrated with trying to get smooth and responsive scrolling of large groups on mobile devices. Old skoolers, please feel free to contribute if you have any improvements!
-Will
Re: Custom Mobile Scroller
Hi Will,
I'm mainly interested in making the Data Grid scrolling more responsive and faster.
keram
Will your scroller work with any group, like Data Grid?William Jamieson wrote:I hope this helps anyone else who has been frustrated with trying to get smooth and responsive scrolling of large groups on mobile devices.
I'm mainly interested in making the Data Grid scrolling more responsive and faster.
keram
Using the latest stable version of LC Community 6.7.x on Win 7 Home Premium, 64bit
-
- Posts: 192
- Joined: Tue Mar 11, 2014 12:57 pm
Re: Custom Mobile Scroller
Interestingly I was testing using:
set the top of group "entry" to -vOffset
set the left of group "entry" to -hOffset
It 'feels' horribly wrong when you combine the two.
For left/right with Twitter on Android it is entirely different to the up/down motion. Perhaps I need left/right 'traction'.
set the top of group "entry" to -vOffset
set the left of group "entry" to -hOffset
It 'feels' horribly wrong when you combine the two.
For left/right with Twitter on Android it is entirely different to the up/down motion. Perhaps I need left/right 'traction'.
-
- VIP Livecode Opensource Backer
- Posts: 212
- Joined: Fri Feb 01, 2013 1:31 am
- Location: Palo Alto, CA put williamdjamieso into tEmail / put n@gmail.com after tEmail/ revmail tEmail
- Contact:
Re: Custom Mobile Scroller
Yeah I havent tried it with side to side motion. Let me know what changes you make to do that.
I also noticed that there is a really big bug in the code when testing. (BTW I have barely tested this) On my Android device, I don't know the action that does it, but I was able to accelerate the group at rapid speeds flying to, evidently the loc of 320,32000!!! LOL Please help me debug this...
@Keram
I suggest you use the Merg Datagrid Scroller. It is a plugin that does a lot better than my script at scrolling and works really well with the datagrid. It is real easy to implement and only costs a few bucks. Find it at http://www.mergext.com
I also noticed that there is a really big bug in the code when testing. (BTW I have barely tested this) On my Android device, I don't know the action that does it, but I was able to accelerate the group at rapid speeds flying to, evidently the loc of 320,32000!!! LOL Please help me debug this...
@Keram
I suggest you use the Merg Datagrid Scroller. It is a plugin that does a lot better than my script at scrolling and works really well with the datagrid. It is real easy to implement and only costs a few bucks. Find it at http://www.mergext.com
-
- Posts: 192
- Joined: Tue Mar 11, 2014 12:57 pm
Re: Custom Mobile Scroller
Have you been able to combine Livecode 7, a scroller (LC/or Mobgui, other) and set the fullscreenmode - any mode - that works successfully?
I simply... [laugh]..want a scroller that resizes with a fullscreenmode - ideally exactFit - and works portrait/landscape.
I simply... [laugh]..want a scroller that resizes with a fullscreenmode - ideally exactFit - and works portrait/landscape.
-
- VIP Livecode Opensource Backer
- Posts: 212
- Joined: Fri Feb 01, 2013 1:31 am
- Location: Palo Alto, CA put williamdjamieso into tEmail / put n@gmail.com after tEmail/ revmail tEmail
- Contact:
Re: Custom Mobile Scroller
@ NewTronsols: I have not had any issue with using the native scroller with fullscreenmode "exactfit". Although I have not tried it in Livecode 7 yet. I am still doing the deployment of my apps through 6.6.2 due the amount of bugs still in the system for android on 7.