A simple library to create a marquee-like elements in your Appcelerator Titanium Apps for both Classic and Alloy projects.
- You can create multiple scrolling views and customize them separately
- Each scrolling view can display one or multiple messages, cycle between them or display them in random order
- You can update its content at any time ( messages, color, position, delay, etc. )
- Works with Android & iOS
Every scrolling view is kept in an internal registry so the library can pause/resume all of them when the app goes to the background. Starting with v1.2.0, call destroy() when you close the window that contains a scrolling view, so it gets released from that registry ( otherwise it stays retained for the lifetime of the app ):
win.addEventListener('close', () => {
scrollingMessage.destroy()
})You can now assign a callback for the paused, resumed and complete events. The callback receives the scrolling view instance:
scrollingMessage.on('complete', (source) => {
// Fired every time a message finishes scrolling
})play() starts playback even if autoplay is set to false. The autoplay property now only controls automatic starts ( at creation and when setting new messages ).
In v1.1.0 the deprecated animate() method became a no-op. It now behaves like play() again, but it will still be deleted in v2.0.0, so use play() instead.
pause()now sticks: pausing during thedelaywindow between messages is no longer reverted by an internal timer.- Fixed a race condition that could start two scrolling loops at once when updating messages mid-cycle.
- The automatic pause/resume on app background/foreground now respects manual pauses: if you paused a scrolling view yourself, it won't auto-resume when the app comes back to the foreground.
- The
|separator for multiple messages in a single string now works everywhere ( it was documented for Alloy but not implemented ). - Boolean attributes set from Alloy XML (
autoplay="false",random="false",debug="true") now work as expected. - Colors in
#AARRGGBBformat are handled correctly by the side label's darkened background ( the default#BF000000no longer renders red ). randomcan now be turned off withupdate({ random: false }), restoring the original message order.update()called without arguments no longer throws, andupdate({ speed: 0 })is ignored instead of freezing the scroller.- The messages array you pass is no longer mutated when using
random. - Message widths are cached per text, so repeated cycles no longer re-measure the same message.
updateLabel()now creates the side label on the fly if the scrolling view didn't have one ( as it was always documented ).
Each scrolling view will start playing immediately after initialization if either message or messages properties are set.
This means that you no longer need to call the animate() method ( now deprecated ) after initialization.
They won't autoplay if there is no message set at initialization, this is useful when you need to get the data from the internet. They will start playing the moment you set a new message(s) with update() or updateMessage/Messages() methods.
If you set the message(s) property and still don't want the scrolling views to start playing immediately, set the new autoplay property to false.
Then use the play() method ( or resume() ) to start playing the scrolling view when needed. Since v1.2.0, play() starts playback even if autoplay is false. You only need to set autoplay back to true if you want new messages set with update() / updateMessage(s)() to start playing automatically.
In order to be more like a native Ti element in Alloy projects, you now create your scrolling views with the <ScrollingView> element provided by ti.scroller.js
<ScrollingView module='ti.scroller' ... />The library listens to the Ti.App lifecycle events paused and resume, so you no longer need to handle them manually. They will pause/resume every scrolling view created in your app.
The animate() method is deprecated and will be deleted in the future.
For Classic Apps, put ti.scroller.js file inside the Resources folder.
let ScrollingView = require('ti.scroller')
let win = Ti.UI.createWindow({
title: 'ti.scroller lib',
backgroundColor: '#fff'
})
let scrollingMessage = new ScrollingView({
message: 'Appcelerator Titanium: Everything you need to create great, native mobile apps — All from a single JavaScript code base.'
})
win.add(scrollingMessage.getView())
win.open()* low framerate gif
let ScrollingView = require('ti.scroller')
let win = Ti.UI.createWindow({
title: 'ti.scroller',
backgroundColor: '#fff'
})
let container = Ti.UI.createView({
layout: 'vertical',
height: Ti.UI.SIZE
})
let famousPeopleQuotes = new ScrollingView({
top: 8,
speed: 7,
random: true,
color: '#dddfe1',
label: 'Famous People:',
backgroundColor: '#53606b',
messages: [
'The greatest glory in living lies not in never falling, but in rising every time we fall. - Nelson Mandela',
'The way to get started is to quit talking and begin doing. - Walt Disney',
'Your time is limited, so don\'t waste it living someone else\'s life. Don\'t be trapped by dogma – which is living with the results of other people\'s thinking. - Steve Jobs',
'If life were predictable it would cease to be life, and be without flavor. - Eleanor Roosevelt',
'If you look at what you have in life, you\'ll always have more. If you look at what you don\'t have in life, you\'ll never have enough. - Oprah Winfrey',
'If you set your goals ridiculously high and it\'s a failure, you will fail above everyone else\'s success. - James Cameron',
'Life is what happens when you\'re busy making other plans. - John Lennon'
]
})
let bestQuotesOfAllTimes = new ScrollingView({
top: 8,
speed: 6,
label: 'Best Quotes:',
backgroundColor: '#79a342',
messages: [
'Whoever is happy will make others happy too. - Anne Frank',
'It is during our darkest moments that we must focus to see the light. - Aristotle',
'Always remember that you are absolutely unique. Just like everyone else. - Margaret Mead',
'Spread love everywhere you go. Let no one ever come to you without leaving happier. - Mother Teresa',
'When you reach the end of your rope, tie a knot in it and hang on. - Franklin D. Roosevelt',
'Don\'t judge each day by the harvest you reap but by the seeds that you plant. - Robert Louis Stevenson',
'The future belongs to those who believe in the beauty of their dreams. - Eleanor Roosevelt',
'Tell me and I forget. Teach me and I remember. Involve me and I learn. - Benjamin Franklin',
'The best and most beautiful things in the world cannot be seen or even touched — they must be felt with the heart. - Helen Keller',
'Do not go where the path may lead, go instead where there is no path and leave a trail. - Ralph Waldo Emerson'
]
})
let marketStocks = new ScrollingView({
top: 8,
speed: 8,
height: 36,
debug: true,
label: 'Market:',
name: 'Market Stocks',
message: 'Loading data...',
backgroundColor: '#F3650C'
})
// Simulated API response
setTimeout(() => {
// Just set the new message(s) with `updateMessages` method
marketStocks.updateMessages('EUR/USD 1.18664 0 0% · USD/JPY 110.399 0.06 0.05% · GBP/USD 1.38902 0 0% · EUR/JPY 130.9959 0.109 0.08% · GBP/JPY 153.3323 0.116 0.08% · USD/CAD 1.24481 -0.001 -0.08% · XAU/USD 1806.7484 -0.684 -0.04% · AUD/USD 0.74878 0.001 0.13% · USD/CHF 0.91462 -0.001 -0.11% · NZD/USD 0.69921 0.001 0.14%')
}, 3000)
container.add(famousPeopleQuotes.getView())
container.add(bestQuotesOfAllTimes.getView())
container.add(marketStocks.getView())
win.add(container)
win.open()* low framerate gif
For Alloy projects drop ti.scroller in /app/lib folder.
app
└─ lib
└─ ti.scroller.jsIn your View file, create a ScrollingView Alloy element and add a module attribute like this module="ti.scroller".
You can set any of the supported attributes directly in the ScrollingView.
IMPORTANT: For multiple messages you'll need to separate them with the | symbol like shown below.
<Alloy>
<NavigationWindow>
<Window title="ti.scroller">
<ScrollingView id="scrollingMessage" module='ti.scroller' backgroundColor="#c91326" label="Famous Quotes:" speed="4" delay="2" height="32" random="true" top="0" font.fontFamily="Gill Sans" font.fontWeight="semibold" font.fontSize="16" message="Whoever is happy will make others happy too. - Anne Frank|It is during our darkest moments that we must focus to see the light. - Aristotle|Always remember that you are absolutely unique. Just like everyone else. - Margaret Mead" />
</Window>
</NavigationWindow>
</Alloy>* low framerate gif
In your controller you can call any of the available methods: update, updateLabel, updateMessage/updateMessages, updateBackground, play, pause, resume, destroy or on at anytime.
$.scrollingMessage.update({
top: 48,
delay: 3,
label: 'Appcelerator:',
message: 'Build great mobile experiences faster - Native apps. Mobile APIs. Real-time analytics. One Platform'
})To prevent unexpected behaviors, the library itself listens to the following Ti.App events, so you don't need to add any listener:
pausedevent: In order to pause the scrolling effect while the app is in the backgroundresumeevent: To resume scrolling when in the foreground.
They will handle every scrolling view created in your app. Since v1.2.0, a scrolling view that you paused manually stays paused when the app comes back to the foreground.
Remember to call destroy() when closing a window that contains scrolling views, so they get released from the internal registry:
win.addEventListener('close', () => {
scrollingMessage.destroy()
})You can customize the text color, background color, vertical position, font size, font weight, font family, scrolling speed, delay between messages, autoplay messages, random order display, side label text, name and debug mode with the following properties:
idnamecolorlabeldelayspeeddebugheightrandomshadowautoplaytop/bottombackgroundColormessage/messagesfontobject withfontSize,fontWeight,fontFamily
The text to display can be set with message or messages property using an array ( for a single message you can set it using a string ).
You can also pass multiple messages in a single string by separating them with the | symbol. This is how multiple messages are set from Alloy XML, and since v1.2.0 it also works in JavaScript:
let scrollingMessage = new ScrollingView({
message: 'First message|Second message|Third message',
...
})let scrollingMessage = new ScrollingView({
messages: [
'Every moment is a fresh beginning. – T.S Eliot',
'Change the world by being yourself. – Amy Poehler',
'Love For All, Hatred For None. – Khalifatul Masih III'
],
...
})To display a left-side label set the label property.
The side label text is always bold, on a slightly darker shade of the scrolling view's backgroundColor.
Defaults to: null
let scrollingMessage = new ScrollingView({
label: 'Breaking News:',
...
})Color for the text message(s) and side label in hex value.
Defaults to: #fff
let scrollingMessage = new ScrollingView({
color: '#79a342',
...
})Background color for the scrolling view, as a hex triplet.
Defaults to: #BF000000
let scrollingMessage = new ScrollingView({
backgroundColor: '#53606b',
...
})ScrollingView height, in platform-specific units.
Defaults to: 28 ( platform default units )
let scrollingMessage = new ScrollingView({
height: 44
...
})Set shadow to true to display a drop shadow under the scrolling view.
Defaults to: false
let scrollingMessage = new ScrollingView({
shadow: true,
...
})Set a font object to set the following properties:
Specifies the font family or specific font to use.
Defaults: Uses the default system font
Font size, in platform-dependent units.
Defaults: 14dp
Font weight. Valid values are "bold", "semibold", "normal", "thin", "light" and "ultralight".
The "semibold", "thin", "light" and "ultralight" weights are recognized on iOS only. "thin", "light" and "ultralight" are only available on iOS 8.2 and later.
Defaults: normal
let scrollingMessage = new ScrollingView({
font: {
fontSize: 16,
fontWeight: 'bold',
fontFamily: 'Gill Sans'
}
...
})The scrolling view's top OR bottom position. This position is relative to the scrolling view's parent.
You can use px, % or dp values.
Defaults to: undefined
let scrollingMessage = new ScrollingView({
top: 44,
// OR
bottom: 0
...
})You can turn off automatic playing by setting the autoplay property to false.
Defaults to: true
let scrollingMessage = new ScrollingView({
autoplay: false,
...
})Pause the animation between messages in seconds.
Defaults to: 0
let scrollingMessage = new ScrollingView({
delay: 3,
...
})The speed of the scrolling text, a constant speed no matter the text length, the higher the number the faster the scrolling speed.
Only values greater than 0 are accepted; 0 and negative values are ignored.
Defaults to: 5
let scrollingMessage = new ScrollingView({
speed: 7,
...
})To display the messages in random order set random to true.
Since v1.2.0 you can turn it off at any time with update({ random: false }), which restores the original message order.
Defaults to: false
let scrollingMessage = new ScrollingView({
random: true,
...
})There are 4 methods to update the content and properties at any time.
update()updateLabel()updateBackground()updateMessage()orupdateMessages()
Is a general purpose method to change any or all of the following properties:
- name
- color
- label
- delay
- speed
- debug
- height
- random
- autoplay
- top or bottom
- backgroundColor
- message or messages
fontobject withfontSize,fontWeight,fontFamily
When updating the message ( or messages ), the text will be shown after completing the currently running message.
scrollingMessage.update({
top: 0,
delay: 0,
speed: 10,
label: 'Appcelerator:',
message: 'Build great mobile experiences faster - Native apps. Mobile APIs. Real-time analytics. One Platform',
font: {
fontWeight: 'bold'
}
})If you need to update only the message or messages, you can use the updateMessage or updateMessages methods.
You can use either of them with a string or an array. A string with | separators is split into multiple messages. Calling them with an empty string or an empty array returns false and keeps the current messages.
The updated text will be shown after completing the currently running message.
scrollingMessage.updateMessage('Build great mobile experiences faster - Native apps. Mobile APIs. Real-time analytics. One Platform')
scrollingMessage.updateMessages( [
'Build: Write in JavaScript, run native on any device and OS',
'Connect: Get mobile-optimized access to any data source',
'Measure: See usage & adoption, detect crashes, tune performance'
])This method will instantly update the label property.
If the scrolling view does not originally contained a label, it will be add it automatically.
scrollingMessage.updateLabel('Breaking News:')Use it to change the scrolling view's background color, including the label property if available.
scrollingMessage.updateBackground('#79a342')Starts playing the scrolling view. Since v1.2.0 it works even if autoplay is set to false ( autoplay only controls automatic starts ). If a message is already scrolling, calling it again has no effect.
scrollingMessage.play()Pauses the scrolling view. The message currently on screen finishes its scroll, and no further messages are played until you call play() or resume().
scrollingMessage.pause()Resumes a paused scrolling view.
scrollingMessage.resume()Releases the scrolling view from the library's internal registry ( used for the automatic pause/resume on app background/foreground ) and cancels any pending timers. Call it when closing the window that contains the scrolling view:
win.addEventListener('close', () => {
scrollingMessage.destroy()
})Returns the actual Ti.UI.View so you can add it to your layout ( Classic projects ):
win.add(scrollingMessage.getView())Assigns a callback for the paused, resumed and complete events. The callback receives the scrolling view instance as its only argument.
paused: fired when the scrolling view is paused ( manually or automatically when the app goes to the background )resumed: fired when the scrolling view is resumedcomplete: fired every time a message finishes scrolling
scrollingMessage.on('complete', (source) => {
console.log('A message finished scrolling')
})
scrollingMessage.on('paused', (source) => {
console.log('The scrolling view was paused')
})In order to identify each Scrolling View while debuging, you can set the name property at initialization.
let scrollingMessage = new ScrollingView({
name: 'My Scrolling View',
...
})<ScrollingView id="scrollingMessage" module='ti.scroller' name="My Scrolling View" />When you enable debug mode you'll see multiple outputs with the name of the Scrolling View.
[WARN] ::ti.scroller:: My Scrolling View: Add side label
[WARN] ::ti.scroller:: My Scrolling View: Apply properties to side label
[WARN] ::ti.scroller:: My Scrolling View: Apply properties to scrolling view’s label
[WARN] ::ti.scroller:: My Scrolling View: Apply properties to scrolling view
[WARN] ::ti.scroller:: My Scrolling View: Play method
[WARN] ::ti.scroller:: My Scrolling View: Update messages method
[WARN] ::ti.scroller:: My Scrolling View: Complete event
[WARN] ::ti.scroller:: My Scrolling View: Play methodIf no name is set, the output will be its id, and if none is set, it will generate an internal one.
You can debug the scrolling view by setting the debug property to true at initialization or with the update() method.
Defaults to: false
let scrollingMessage = new ScrollingView({
debug: true,
...
})
// OR
scrollingMessage.update({
debug: true
})<ScrollingView id="scrollingMessage" module='ti.scroller' debug="true" />To turn it off
scrollingMessage.update({
debug: false
})
// OR
$.scrollingMessage.update({
debug: false
})Copyright 2021 César Estrada Licensed under the Apache License, Version 2.0 (the “License”); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an “AS IS” BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.


