@maccesar/titools 5.3.0 → 5.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (98) hide show
  1. package/CONTRIBUTING.md +1 -1
  2. package/README.md +31 -60
  3. package/agents/ti-pro.md +3 -1
  4. package/commands/ti-audit.md +6 -4
  5. package/docs/examples.md +9 -0
  6. package/docs/knowledge-index.md +2 -1
  7. package/lib/config.js +1 -0
  8. package/package.json +1 -1
  9. package/skills/alloy-guides/SKILL.md +18 -179
  10. package/skills/alloy-guides/references/CLI_TASKS.md +17 -216
  11. package/skills/alloy-guides/references/CONCEPTS.md +27 -162
  12. package/skills/alloy-guides/references/CONTROLLERS.md +38 -236
  13. package/skills/alloy-guides/references/MODELS.md +47 -723
  14. package/skills/alloy-guides/references/MODELS_ADVANCED.md +21 -482
  15. package/skills/alloy-guides/references/VIEWS_DYNAMIC.md +12 -222
  16. package/skills/alloy-guides/references/VIEWS_STYLES.md +39 -358
  17. package/skills/alloy-guides/references/VIEWS_XML.md +36 -552
  18. package/skills/alloy-guides/references/WIDGETS.md +49 -127
  19. package/skills/alloy-howtos/SKILL.md +14 -169
  20. package/skills/alloy-howtos/references/best_practices.md +9 -113
  21. package/skills/alloy-howtos/references/cli_reference.md +18 -223
  22. package/skills/alloy-howtos/references/config_files.md +50 -133
  23. package/skills/alloy-howtos/references/debugging_troubleshooting.md +19 -63
  24. package/skills/alloy-howtos/references/samples.md +21 -138
  25. package/skills/ti-api/SKILL.md +10 -2
  26. package/skills/ti-api/references/api-android.md +36 -2
  27. package/skills/ti-api/references/api-app-platform.md +39 -3
  28. package/skills/ti-api/references/api-core.md +50 -18
  29. package/skills/ti-api/references/api-data-network.md +49 -35
  30. package/skills/ti-api/references/api-media.md +45 -27
  31. package/skills/ti-api/references/api-services.md +39 -9
  32. package/skills/ti-api/references/api-ui-android.md +33 -13
  33. package/skills/ti-api/references/api-ui-extras.md +41 -15
  34. package/skills/ti-api/references/api-ui-ios-animator.md +42 -26
  35. package/skills/ti-api/references/api-ui-ios.md +74 -2
  36. package/skills/ti-api/references/api-ui-lists.md +32 -16
  37. package/skills/ti-api/references/api-ui-text-input.md +34 -17
  38. package/skills/ti-api/references/api-ui-views.md +27 -1
  39. package/skills/ti-api/references/api-ui-windows-navigation.md +32 -18
  40. package/skills/ti-api/references/api-xml-global.md +66 -16
  41. package/skills/ti-create-release/SKILL.md +98 -0
  42. package/skills/ti-create-release/references/module-discovery.md +69 -0
  43. package/skills/ti-expert/references/adaptive-layouts.md +1 -1
  44. package/skills/ti-guides/SKILL.md +37 -76
  45. package/skills/ti-guides/references/advanced-data-and-images.md +122 -126
  46. package/skills/ti-guides/references/android-manifest.md +24 -83
  47. package/skills/ti-guides/references/app-distribution.md +31 -377
  48. package/skills/ti-guides/references/application-frameworks.md +127 -335
  49. package/skills/ti-guides/references/cli-reference.md +184 -633
  50. package/skills/ti-guides/references/commonjs-advanced.md +81 -231
  51. package/skills/ti-guides/references/compatibility-matrix.md +36 -75
  52. package/skills/ti-guides/references/hello-world.md +95 -70
  53. package/skills/ti-guides/references/hyperloop-native-access.md +52 -448
  54. package/skills/ti-guides/references/resources.md +174 -142
  55. package/skills/ti-guides/references/sdk-release-notes.md +28 -71
  56. package/skills/ti-guides/references/tiapp-config.md +222 -598
  57. package/skills/ti-howtos/SKILL.md +23 -123
  58. package/skills/ti-howtos/references/cross-platform-development.md +119 -324
  59. package/skills/ti-howtos/references/debugging-profiling.md +77 -445
  60. package/skills/ti-howtos/references/extending-titanium.md +199 -673
  61. package/skills/ti-howtos/references/local-data-sources.md +87 -300
  62. package/skills/ti-howtos/references/location-and-maps.md +86 -213
  63. package/skills/ti-howtos/references/media-apis.md +103 -223
  64. package/skills/ti-howtos/references/notification-services.md +86 -506
  65. package/skills/ti-howtos/references/remote-data-sources.md +97 -316
  66. package/skills/ti-howtos/references/using-modules.md +77 -133
  67. package/skills/ti-ui/SKILL.md +28 -143
  68. package/skills/ti-ui/references/icons-and-splash-screens.md +74 -403
  69. package/skills/ti-ui/references/layouts-and-positioning.md +175 -402
  70. package/skills/ti-ui/references/listviews-and-performance.md +100 -703
  71. package/skills/ti-ui/references/platform-conventions.md +180 -0
  72. package/skills/ti-ui/references/user-interface.md +43 -0
  73. package/skills/alloy-guides/references/VIEWS_WITHOUT_CONTROLLERS.md +0 -102
  74. package/skills/alloy-howtos/references/custom_tags.md +0 -148
  75. package/skills/ti-guides/references/coding-best-practices.md +0 -149
  76. package/skills/ti-guides/references/javascript-primer.md +0 -414
  77. package/skills/ti-guides/references/reserved-words.md +0 -36
  78. package/skills/ti-guides/references/style-and-conventions.md +0 -103
  79. package/skills/ti-howtos/references/android-platform-deep-dives.md +0 -624
  80. package/skills/ti-howtos/references/automation-fastlane-appium.md +0 -96
  81. package/skills/ti-howtos/references/buffer-codec-streams.md +0 -162
  82. package/skills/ti-howtos/references/google-maps-v2.md +0 -172
  83. package/skills/ti-howtos/references/ios-map-kit.md +0 -149
  84. package/skills/ti-howtos/references/ios-platform-deep-dives.md +0 -611
  85. package/skills/ti-howtos/references/tutorials.md +0 -565
  86. package/skills/ti-howtos/references/web-content-integration.md +0 -287
  87. package/skills/ti-howtos/references/webpack-build-pipeline.md +0 -124
  88. package/skills/ti-ui/references/accessibility-deep-dive.md +0 -288
  89. package/skills/ti-ui/references/animation-and-matrices.md +0 -569
  90. package/skills/ti-ui/references/application-structures.md +0 -626
  91. package/skills/ti-ui/references/custom-fonts-styling.md +0 -549
  92. package/skills/ti-ui/references/event-handling.md +0 -401
  93. package/skills/ti-ui/references/gestures.md +0 -448
  94. package/skills/ti-ui/references/orientation.md +0 -374
  95. package/skills/ti-ui/references/platform-ui-android.md +0 -727
  96. package/skills/ti-ui/references/platform-ui-ios.md +0 -576
  97. package/skills/ti-ui/references/scrolling-views.md +0 -288
  98. package/skills/ti-ui/references/tableviews.md +0 -542
@@ -1,287 +0,0 @@
1
- # Web content integration
2
-
3
- ## 1. The WebView component
4
-
5
- ### WKWebView (Titanium SDK 8.0.0+)
6
- As of Titanium SDK 8.0.0, WKWebView is the only supported web view on iOS. UIWebView was deprecated and removed. WKWebView behaves differently, so plan for that.
7
-
8
- ### Basic WebView creation
9
-
10
- Remote URL:
11
- ```javascript
12
- const webview = Ti.UI.createWebView({
13
- url: 'https://titaniumsdk.com'
14
- });
15
- win.add(webview);
16
- win.open();
17
- ```
18
-
19
- Local HTML:
20
- ```javascript
21
- const webview = Ti.UI.createWebView({
22
- url: 'local.html' // Relative to Resources or app/assets/app/lib
23
- });
24
- win.add(webview);
25
- ```
26
-
27
- Inline HTML:
28
- ```javascript
29
- const webview = Ti.UI.createWebView({
30
- html: '<html><body><h1>Hello</h1></body></html>'
31
- });
32
- ```
33
-
34
- ### Local web content with assets
35
- Local content can include CSS, JS, and images. Paths are relative to Resources (Classic) or app/assets/app/lib (Alloy).
36
-
37
- `local.html`:
38
- ```html
39
- <html>
40
- <head>
41
- <link rel="stylesheet" type="text/css" href="local.css"/>
42
- <script src="local.js"></script>
43
- </head>
44
- <body>
45
- <p>Local content</p>
46
- </body>
47
- </html>
48
- ```
49
-
50
- ### WebView properties and methods
51
-
52
- Navigation:
53
- - `canGoBack()` - returns true if possible to go back
54
- - `canGoForward()` - returns true if possible to go forward
55
- - `goBack()` - navigate back in history
56
- - `goForward()` - navigate forward in history
57
-
58
- Load control:
59
- - `loading` (Boolean) - current loading state
60
- - `reload()` - refresh the page
61
- - `stopLoading()` - stop loading
62
- - `repaint()` - force repaint
63
-
64
- Data handling:
65
- - `url` - local or remote URL
66
- - `html` - inline HTML string
67
- - `scalesPageToFit` - scale content to dimensions
68
- - `setBasicAuthentication(host, username, password)` - HTTP auth
69
-
70
- ```javascript
71
- webView.setBasicAuthentication('myDomain.com', 'username', 'password');
72
- ```
73
-
74
- Events:
75
- - `beforeload` - fires before loading begins (`e.url` contains the source)
76
- - `load` - fires when content has loaded
77
- - `error` - fires on load failures (`e.url`, `e.message`)
78
-
79
- ## 2. Communication between WebViews and Titanium
80
-
81
- ### Local web content communication
82
-
83
- Logging from WebView: Ti.API methods work inside local HTML.
84
-
85
- ```html
86
- <html>
87
- <body onload="Ti.API.info('Page loaded!');">
88
- <p>Logging works!</p>
89
- </body>
90
- </html>
91
- ```
92
-
93
- Bidirectional events with `Ti.App`:
94
-
95
- In local HTML:
96
- ```html
97
- <html>
98
- <head>
99
- <script>
100
- // Listen for events from Titanium
101
- Ti.App.addEventListener('app:fromTitanium', (e) => {
102
- alert(e.message);
103
- document.getElementById('output').textContent = e.message;
104
- });
105
-
106
- // Send event to Titanium
107
- function sendToApp() {
108
- Ti.App.fireEvent('app:fromWebView', {
109
- message: 'Hello from WebView!'
110
- });
111
- }
112
- </script>
113
- </head>
114
- <body>
115
- <button onclick="sendToApp()">Send to Titanium</button>
116
- <div id="output"></div>
117
- </body>
118
- </html>
119
- ```
120
-
121
- In Titanium:
122
- ```javascript
123
- const webview = Ti.UI.createWebView({ url: 'local.html' });
124
-
125
- // Listen for events from the WebView
126
- Ti.App.addEventListener('app:fromWebView', (e) => {
127
- alert(e.message);
128
- });
129
-
130
- // Send event to the WebView
131
- const button = Ti.UI.createButton({
132
- title: 'Send to WebView'
133
- });
134
- button.addEventListener('click', () => {
135
- Ti.App.fireEvent('app:fromTitanium', {
136
- message: 'Hello from Titanium!'
137
- });
138
- });
139
- ```
140
-
141
- ### Remote web content communication
142
-
143
- Titanium statements (`Ti.API`, `Ti.App`) do not work in remote HTML content.
144
-
145
- Warning: On iOS 12.0+, calling `evalJS()` synchronously from some contexts can deadlock. Prefer the async version with a callback.
146
-
147
- #### Using `evalJS()` for remote content
148
- Inject JavaScript and retrieve results as strings:
149
-
150
- ```javascript
151
- const webview = Ti.UI.createWebView({ url: 'https://example.com' });
152
-
153
- webview.addEventListener('load', (e) => {
154
- // Get the page title
155
- const title = webview.evalJS('document.title');
156
- Ti.API.info(`Page title: ${title}`);
157
-
158
- // Get cookies
159
- const cookies = webview.evalJS('document.cookie');
160
- Ti.API.info(`Cookies: ${cookies}`);
161
-
162
- // Execute a custom function
163
- webview.evalJS('alert("Hello from Titanium!");');
164
- });
165
- ```
166
-
167
- `evalJS()` rules:
168
- - Call it from the `load` event (page must be loaded)
169
- - Pass code as a single string
170
- - Returns a string (or null)
171
- - Use `JSON.stringify()` for complex data
172
-
173
- #### Passing data to remote content
174
-
175
- ```javascript
176
- webview.addEventListener('load', () => {
177
- const data = { user: 'John', score: 100 };
178
- webview.evalJS(`window.appData = ${JSON.stringify(data)};`);
179
- });
180
- ```
181
-
182
- Then in remote HTML:
183
- ```html
184
- <script>
185
- console.log(window.appData.user); // 'John'
186
- </script>
187
- ```
188
-
189
- ## 3. Performance and interaction concerns
190
-
191
- ### WebView performance
192
- WebView consumes significant resources:
193
- - Each WebView has its own rendering context
194
- - Memory overhead is high
195
- - Load time is independent of content complexity
196
-
197
- Best practice: if you can recreate the content with native Titanium components, do it.
198
-
199
- ### WebView in TableViews
200
- Anti-pattern: embedding WebViews in TableViewRows causes slow scrolling.
201
-
202
- ### WebView in scrollable components
203
- WebViews do not behave well inside other scrollable containers (ScrollView, TableView). They consume touch events.
204
-
205
- Workaround: set `touchEnabled: false` on the WebView if it sits inside a scrollable parent:
206
-
207
- ```javascript
208
- const webview = Ti.UI.createWebView({
209
- url: 'content.html',
210
- touchEnabled: false // Allow parent to handle touches
211
- });
212
- ```
213
-
214
- ### Viewport meta tag
215
- For mobile-optimized content, use the viewport meta tag:
216
-
217
- ```html
218
- <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
219
- ```
220
-
221
- ## 4. WebView use cases
222
-
223
- Common WebView use cases:
224
- - HTML forms: auto-scroll to focused fields, next/previous navigation, native keyboard integration
225
- - Rich text or HTML email: render styled content that is hard to replicate with native labels
226
- - Canvas/graphics: HTML5 Canvas provides 2D drawing not available in native Titanium APIs
227
- - OAuth flows: load third-party auth pages in a WebView and intercept redirects
228
-
229
- ### Authentication flows
230
- Many OAuth providers use WebView for login (for example, the Facebook module).
231
-
232
- ```javascript
233
- const authWebView = Ti.UI.createWebView({
234
- url: 'https://auth.example.com/oauth'
235
- });
236
-
237
- authWebView.addEventListener('load', (e) => {
238
- // Detect redirect to callback URL with token
239
- if (e.url.indexOf('myapp://callback') === 0) {
240
- const token = extractTokenFromUrl(e.url);
241
- Ti.App.fireEvent('auth:success', { token: token });
242
- }
243
- });
244
- ```
245
-
246
- ### Canvas and graphics
247
- For complex graphics, use HTML5 Canvas:
248
-
249
- `local.html`:
250
- ```html
251
- <canvas id="myCanvas" width="300" height="200"></canvas>
252
- <script>
253
- const ctx = document.getElementById('myCanvas').getContext('2d');
254
- ctx.fillStyle = 'green';
255
- ctx.fillRect(10, 10, 150, 100);
256
- </script>
257
- ```
258
-
259
- ## 5. WKWebView behavioral differences (iOS)
260
-
261
- - Cookies: WKWebView uses a separate cookie store from `Ti.Network`. Cookies set via HTTPClient are not shared with WebViews.
262
- - `localStorage`/`sessionStorage`: not shared between the native app and the WebView. Each WKWebView has its own storage.
263
- - `evalJS` is async: on iOS 12.0+, synchronous `evalJS()` can deadlock. Use the callback form instead:
264
-
265
- ```javascript
266
- webView.evalJS('document.title', (result) => {
267
- Ti.API.info(`Title: ${result}`);
268
- });
269
- ```
270
-
271
- - Viewport meta tag required: WKWebView needs an explicit viewport tag to scale content correctly:
272
-
273
- ```html
274
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
275
- ```
276
-
277
- - Custom fonts: use a special `@font-face` path format in WKWebView CSS. Fonts must be in the app bundle and referenced correctly.
278
- - Remote HTML limitations: `Ti.API`, `Ti.App.fireEvent()`, and other Titanium calls do not work in remotely-loaded HTML. Only local HTML can communicate with the Titanium runtime.
279
-
280
- ## Best practices summary
281
-
282
- 1. Avoid WebViews when possible. Use native components.
283
- 2. Never embed a WebView in a TableView.
284
- 3. Use local content for integration. Only local content supports `Ti.App` events.
285
- 4. Use `evalJS()` for remote content. It is the only way to interact with remote pages.
286
- 5. Wait for the `load` event before calling `evalJS()`.
287
- 6. Configure the viewport for proper mobile rendering.
@@ -1,124 +0,0 @@
1
- # Webpack build pipeline
2
-
3
- > **⚠️ Appcelerator/Axway era feature**
4
- > The Webpack pipeline documented here was introduced with Titanium SDK 9.1.0 as part of the Axway AMPLIFY toolchain (`appcd` daemon). Since Axway discontinued Appcelerator, this feature is **not maintained** in the current TiDev CLI (`ti`). If you are using the community TiDev CLI, this pipeline may not be available. Prefer the standard `ti build` pipeline unless your project already uses Webpack.
5
-
6
- Webpack integration is an alternative build pipeline starting with Titanium SDK 9.1.0. It is optional. When enabled, Webpack manages asset and code bundling.
7
-
8
- ## 1. Key benefits
9
- - Fast incremental builds: only changed files are processed.
10
- - npm support: install packages in the root and import them directly.
11
- - Build-time resolution: `require` calls are resolved during compilation, not at runtime.
12
-
13
- ## 2. The `@` alias
14
- Webpack adds the `@` alias to reference the source root without deep relative paths.
15
-
16
- | Project type | Path mapped by `@` |
17
- | :----------- | :----------------- |
18
- | Alloy | `app/lib` |
19
- | Classic | `src` |
20
-
21
- Usage example:
22
-
23
- ```javascript
24
- // Before (without webpack)
25
- import Utils from '../../utils/helper';
26
-
27
- // Now (with webpack)
28
- import Utils from '@/utils/helper';
29
- ```
30
-
31
- ## 3. npm dependency management
32
- Install a package in the project root:
33
-
34
- ```bash
35
- npm install lodash
36
- ```
37
-
38
- Use it in Titanium code:
39
-
40
- ```javascript
41
- import _ from 'lodash';
42
- const data = _.chunk(['a', 'b', 'c', 'd'], 2);
43
- ```
44
-
45
- ## 4. Platform-specific files
46
- Webpack detects platform-specific files using the `filename.<platform>.js` pattern.
47
-
48
- Example:
49
- - `utils.js` (common)
50
- - `utils.ios.js` (iOS only)
51
- - `utils.android.js` (Android only)
52
-
53
- When you `import { func } from '@/utils'`, Webpack picks the correct version for the build target.
54
-
55
- ## 5. Diagnostic web UI
56
- Webpack includes a web interface to analyze builds and asset sizes. Default URL: `http://localhost:1732/webpack/latest/web`
57
-
58
- ## 6. Project plugins
59
- Webpack support is powered by plugins chosen based on project type:
60
-
61
- | Plugin | Purpose |
62
- | ---------------------------------- | ----------------------- |
63
- | `@appcd/webpack-plugin-alloy` | Alloy project support |
64
- | `@appcd/webpack-plugin-classic` | Classic project support |
65
- | `@appcd/webpack-plugin-babel` | Babel transpilation |
66
- | `@appcd/webpack-plugin-typescript` | TypeScript support |
67
-
68
- ### Custom plugin configuration
69
- Customize with the `webpack-chain` API in `webpack.config.js`:
70
-
71
- ```javascript
72
- module.exports = (api) => {
73
- // Add a custom alias
74
- api.chainWebpack((config) => {
75
- config.resolve.alias.set('@utils', api.resolve('app/lib/utils'));
76
- });
77
- };
78
- ```
79
-
80
- Common customizations:
81
- - Add alias: `config.resolve.alias.set(name, path)`
82
- - Add loader: `config.module.rule(name).use(name).loader(loader)`
83
- - Delete plugin: `config.plugins.delete(name)`
84
-
85
- ## 7. Advanced configuration
86
- Extend configuration via plugins in `package.json`:
87
-
88
- ```json
89
- {
90
- "appcdWebpackPlugins": [
91
- "my-local-plugin.js"
92
- ]
93
- }
94
- ```
95
-
96
- ## 8. Global configuration
97
- Configure Webpack daemon settings in `~/.appcelerator/appcd/config.json`:
98
-
99
- ```json
100
- {
101
- "webpack": {
102
- "inactivityTimeout": 600000
103
- }
104
- }
105
- ```
106
-
107
- ## 9. Troubleshooting
108
-
109
- Build seems stuck: the Webpack daemon may need a restart.
110
-
111
- ```bash
112
- appcd exec /webpack/latest/stop
113
- ```
114
-
115
- View build logs:
116
-
117
- ```bash
118
- appcd logcat "*webpack*"
119
- ```
120
-
121
- ## 10. Known limitations
122
- - Hyperloop is not compatible with the Webpack pipeline.
123
- - Alloy.jmk build hooks are not supported. Use Webpack plugins instead.
124
- - The first build may be slower due to daemon startup.
@@ -1,288 +0,0 @@
1
- # Accessibility (a11y) deep dive
2
-
3
- ## 1. Overview
4
-
5
- Accessibility makes your app usable for people with visual, hearing, and motor disabilities. Titanium works with Android TalkBack and iOS VoiceOver for spoken feedback.
6
-
7
- ### Design considerations beyond screen readers
8
-
9
- - Motor disabilities often require larger tap targets (minimum 44x44 points on iOS, 48x48 dp on Android). Support alternative input methods and avoid gestures that demand precision or fast timing.
10
- - Color-blindness means color alone cannot carry meaning. Use text labels, icons, or patterns alongside color indicators. Test the UI in grayscale to check usability.
11
- - Screen magnifiers are common for low-vision users (iOS Zoom, Android Magnification). Keep layouts functional when magnified and avoid absolute positioning that breaks at large zoom levels.
12
-
13
- ## 2. Core accessibility properties
14
-
15
- All Titanium view elements support these accessibility properties.
16
-
17
- | Property | Default Value | Description |
18
- | --------------------- | ----------------------------- | ------------------------------------------------------------------------------- |
19
- | `accessibilityHidden` | `false` | If `true`, the view is ignored by the accessibility service |
20
- | `accessibilityLabel` | Title or label of the control | Succinct label identifying the view |
21
- | `accessibilityHint` | - | Briefly describes what performing an action will do (e.g., "Closes the window") |
22
- | `accessibilityValue` | State or value of the control | String describing current state (e.g., "Selected", "50 percent") |
23
-
24
- > Android note: On Android, `accessibilityLabel`, `accessibilityValue`, and `accessibilityHint` are combined (in that order) and mapped to the native `contentDescription`. TalkBack reads them as one string. VoiceOver on iOS reads them as separate announcements.
25
-
26
- ### Basic usage
27
-
28
- ```javascript
29
- const button = Ti.UI.createButton({
30
- title: 'Save',
31
- accessibilityLabel: 'Save changes',
32
- accessibilityHint: 'Saves your modifications to the server'
33
- });
34
-
35
- const slider = Ti.UI.createSlider({
36
- min: 0,
37
- max: 100,
38
- value: 50,
39
- accessibilityLabel: 'Volume control',
40
- accessibilityValue: '50 percent'
41
- });
42
-
43
- // Update accessibilityValue as slider changes
44
- slider.addEventListener('change', (e) => {
45
- slider.accessibilityValue = `${e.value.toFixed(0)} percent`;
46
- });
47
- ```
48
- ...
49
- ### Android TalkBack
50
- ...
51
- ```javascript
52
- // GOOD - Button uses default text
53
- const button = Ti.UI.createButton({
54
- title: 'Submit Form'
55
- // accessibilityLabel NOT needed - title is spoken
56
- });
57
-
58
- // CUSTOM - Override default
59
- const button = Ti.UI.createButton({
60
- title: 'Submit',
61
- accessibilityLabel: 'Submit the registration form'
62
- });
63
- ```
64
- ...
65
- ```javascript
66
- // BAD - Container with accessibility properties
67
- // On iOS, VoiceOver treats the entire container as ONE accessible element,
68
- // completely blocking access to all children inside it (nameField, emailField, etc.)
69
- const container = Ti.UI.createView({
70
- accessibilityLabel: 'Form container', // DON'T DO THIS
71
- accessibilityHint: 'Contains input fields'
72
- });
73
- container.add(nameField);
74
- container.add(emailField);
75
- container.add(submitButton);
76
-
77
- // GOOD - No accessibility on container, children accessible
78
- const container = Ti.UI.createView({
79
- // No accessibility properties
80
- });
81
- container.add(nameField);
82
- container.add(emailField);
83
- container.add(submitButton);
84
- ```
85
- ...
86
- ### Star rating example
87
-
88
- ```javascript
89
- const starView = Ti.UI.createView({
90
- width: 200,
91
- height: 40,
92
- accessibilityLabel: 'Rating',
93
- accessibilityValue: '4 out of 5 stars',
94
- accessibilityHint: 'User rating for this product'
95
- });
96
-
97
- // Visual representation (images or drawn stars)
98
- for (let i = 0; i < 5; i++) {
99
- const star = Ti.UI.createImageView({
100
- image: i < 4 ? 'star-filled.png' : 'star-empty.png',
101
- left: i * 35,
102
- accessibilityHidden: true // Hide individual stars
103
- });
104
- starView.add(star);
105
- }
106
- ```
107
-
108
- ### Toggle button example
109
-
110
- ```javascript
111
- let isMuted = false;
112
- const muteButton = Ti.UI.createButton({
113
- title: 'Mute',
114
- accessibilityLabel: 'Mute audio',
115
- accessibilityValue: 'Off' // Current state
116
- });
117
-
118
- muteButton.addEventListener('click', () => {
119
- isMuted = !isMuted;
120
- muteButton.title = isMuted ? 'Unmute' : 'Mute';
121
- muteButton.accessibilityValue = isMuted ? 'On' : 'Off';
122
- });
123
- ```
124
-
125
- ## 6. System-level accessibility events
126
-
127
- ### Monitor accessibility changes
128
-
129
- ```javascript
130
- Ti.App.addEventListener('accessibilitychanged', (e) => {
131
- Ti.API.info(`Accessibility mode changed: ${e.enabled}`);
132
- // Adjust UI behavior as needed
133
- if (e.enabled) {
134
- // Increase touch targets, simplify animations, etc.
135
- }
136
- });
137
- ```
138
- ...
139
- ### Code patterns
140
-
141
- Do:
142
- ```javascript
143
- // Provide meaningful labels
144
- const iconButton = Ti.UI.createButton({
145
- image: 'settings.png',
146
- accessibilityLabel: 'Open settings'
147
- });
148
-
149
- // Update state changes
150
- checkbox.accessibilityValue = isChecked ? 'Checked' : 'Unchecked';
151
-
152
- // Hide decorative elements
153
- decorativeIcon.accessibilityHidden = true;
154
- ```
155
-
156
- Don't:
157
- ```javascript
158
- // Don't set accessibilityLabel for text controls (Android)
159
- const label = Ti.UI.createLabel({
160
- text: 'Hello',
161
- accessibilityLabel: 'Hello' // REDUNDANT on Android
162
- });
163
-
164
- // Don't set accessibility on containers (iOS)
165
- // VoiceOver treats the container as a single element, making all children unreachable
166
- const container = Ti.UI.createView({
167
- accessibilityLabel: 'Container' // BLOCKS children on iOS
168
- });
169
- ```
170
-
171
- ### Accessibility-first development
172
-
173
- When designing complex UIs, plan accessibility at the start.
174
-
175
- ```javascript
176
- function createAccessibleListItem(title, subtitle, action) {
177
- const item = Ti.UI.createView({
178
- height: 60,
179
- accessibilityLabel: title,
180
- accessibilityHint: `${subtitle}. Double tap to ${action}`
181
- });
182
-
183
- const titleLabel = Ti.UI.createLabel({
184
- text: title,
185
- accessibilityHidden: true // Already announced by container
186
- });
187
-
188
- const subtitleLabel = Ti.UI.createLabel({
189
- text: subtitle,
190
- accessibilityHidden: true // Already announced by container
191
- });
192
-
193
- item.add(titleLabel);
194
- item.add(subtitleLabel);
195
- return item;
196
- }
197
- ```
198
-
199
- ## 9. Platform behavior comparison
200
-
201
- TalkBack (Android) and VoiceOver (iOS) interpret accessibility properties differently.
202
-
203
- | Element | TalkBack Response | VoiceOver Response |
204
- | -------------------------------- | ------------------------------------------------- | ------------------------------------------------------- |
205
- | Button with label "Submit" | "Submit, button, double-tap to activate" | "Submit, button" |
206
- | Slider with value 50% | "50 percent, slider" | "50%, adjustable" |
207
- | Label with hint | Reads label + value + hint as one combined string | Reads label first, then hint as a separate announcement |
208
- | Checkbox, checked | "Checked, checkbox, double-tap to toggle" | "Checked, tick box" |
209
- | Image with label "Profile photo" | "Profile photo" | "Profile photo, image" |
210
-
211
- > On Android, the three accessibility properties are concatenated into `contentDescription`, so they are read as one utterance. On iOS, VoiceOver reads them as distinct pieces with short pauses between them.
212
-
213
- ## 10. Testing procedures
214
-
215
- ### Android emulator
216
-
217
- The Android emulator has no built-in way to test accessibility. Use a physical device for accurate TalkBack behavior.
218
-
219
- ### Android device (TalkBack)
220
-
221
- 1. Open **Settings > Accessibility > TalkBack**
222
- 2. Toggle TalkBack **On**
223
- 3. A confirmation dialog appears; confirm to enable
224
-
225
- TalkBack gestures:
226
- - Tap: Select and hear the element described
227
- - Double-tap: Activate the selected element
228
- - Swipe left/right: Navigate to the previous/next element
229
- - Swipe up/down: Change reading granularity (characters, words, headings)
230
-
231
- To disable TalkBack, go to the same setting and toggle it off. You can also set a hardware shortcut (hold both volume keys for 3 seconds) for quick toggling during development.
232
-
233
- ### iOS simulator (Accessibility Inspector)
234
-
235
- Use the Accessibility Inspector to examine elements without enabling VoiceOver.
236
-
237
- 1. In Xcode, go to **Xcode > Open Developer Tool > Accessibility Inspector**
238
- 2. Select the Simulator as the target device
239
- 3. Hover over or tap elements to inspect their accessibility label, value, hint, and traits
240
-
241
- This is the fastest way to verify properties during development.
242
-
243
- ### iOS device (VoiceOver)
244
-
245
- 1. Open **Settings > Accessibility > VoiceOver**
246
- 2. Toggle VoiceOver **On**
247
-
248
- VoiceOver gestures:
249
- - Tap: Select and hear the element described
250
- - Double-tap: Activate the selected element
251
- - Swipe left/right: Navigate to the previous/next element
252
- - Three-finger swipe: Scroll content
253
- - Two-finger tap: Pause/resume speech
254
-
255
- To disable VoiceOver, go to the same setting and toggle it off. You can also configure the Accessibility Shortcut (triple-click the side button) for quick toggling.
256
-
257
- ## 11. External resources
258
-
259
- - [Accessibility Programming Guide for iOS](https://developer.apple.com/library/ios/documentation/UserExperience/Conceptual/iPhoneAccessibility/Introduction/Introduction.html)
260
- - [Android Accessibility API Guide](http://developer.android.com/guide/topics/ui/accessibility/index.html)
261
- - [Android Accessibility Design Guide](http://developer.android.com/design/patterns/accessibility.html)
262
- - [W3C Web Content Accessibility Guidelines](http://www.w3.org/WAI/WCAG20/quickref/)
263
-
264
- ## 12. Common issues
265
-
266
- ### Issue: VoiceOver cannot access children
267
-
268
- Cause: A container view has accessibility properties set.
269
-
270
- Solution: Remove all accessibility properties from container views.
271
-
272
- ### Issue: TalkBack does not speak text
273
-
274
- Cause: `accessibilityLabel` on a Label/Button overrides visible text.
275
-
276
- Solution: Do not set `accessibilityLabel` on textual controls unless you are intentionally overriding.
277
-
278
- ### Issue: Complex custom controls are not accessible
279
-
280
- Cause: Custom-drawn views have no accessibility properties.
281
-
282
- Solution: Provide `accessibilityLabel`, `accessibilityValue`, and `accessibilityHint` for custom controls.
283
-
284
- ### Issue: State changes are not announced
285
-
286
- Cause: `accessibilityValue` is not updated when state changes.
287
-
288
- Solution: Update `accessibilityValue` in change event handlers.