@maccesar/titools 2.0.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 (120) hide show
  1. package/AGENTS-TEMPLATE.md +173 -0
  2. package/README.md +867 -0
  3. package/agents/ti-researcher.md +108 -0
  4. package/bin/titools.js +53 -0
  5. package/lib/commands/agents.js +126 -0
  6. package/lib/commands/install.js +188 -0
  7. package/lib/commands/uninstall.js +215 -0
  8. package/lib/commands/update.js +159 -0
  9. package/lib/config.js +119 -0
  10. package/lib/downloader.js +153 -0
  11. package/lib/installer.js +253 -0
  12. package/lib/platform.js +108 -0
  13. package/lib/symlink.js +142 -0
  14. package/lib/utils.js +270 -0
  15. package/package.json +67 -0
  16. package/skills/alloy-expert/SKILL.md +247 -0
  17. package/skills/alloy-expert/assets/ControllerAutoCleanup.js +182 -0
  18. package/skills/alloy-expert/references/alloy-structure.md +381 -0
  19. package/skills/alloy-expert/references/anti-patterns.md +133 -0
  20. package/skills/alloy-expert/references/code-conventions.md +469 -0
  21. package/skills/alloy-expert/references/contracts.md +280 -0
  22. package/skills/alloy-expert/references/controller-patterns.md +520 -0
  23. package/skills/alloy-expert/references/error-handling.md +484 -0
  24. package/skills/alloy-expert/references/examples.md +735 -0
  25. package/skills/alloy-expert/references/migration-patterns.md +298 -0
  26. package/skills/alloy-expert/references/patterns.md +448 -0
  27. package/skills/alloy-expert/references/performance-patterns.md +855 -0
  28. package/skills/alloy-expert/references/security-patterns.md +847 -0
  29. package/skills/alloy-expert/references/state-management.md +779 -0
  30. package/skills/alloy-expert/references/testing.md +872 -0
  31. package/skills/alloy-guides/SKILL.md +214 -0
  32. package/skills/alloy-guides/references/CLI_TASKS.md +243 -0
  33. package/skills/alloy-guides/references/CONCEPTS.md +191 -0
  34. package/skills/alloy-guides/references/CONTROLLERS.md +298 -0
  35. package/skills/alloy-guides/references/MODELS.md +1028 -0
  36. package/skills/alloy-guides/references/PURGETSS.md +56 -0
  37. package/skills/alloy-guides/references/VIEWS_DYNAMIC.md +242 -0
  38. package/skills/alloy-guides/references/VIEWS_STYLES.md +388 -0
  39. package/skills/alloy-guides/references/VIEWS_WITHOUT_CONTROLLERS.md +109 -0
  40. package/skills/alloy-guides/references/VIEWS_XML.md +558 -0
  41. package/skills/alloy-guides/references/WIDGETS.md +176 -0
  42. package/skills/alloy-howtos/SKILL.md +203 -0
  43. package/skills/alloy-howtos/references/best_practices.md +138 -0
  44. package/skills/alloy-howtos/references/cli_reference.md +253 -0
  45. package/skills/alloy-howtos/references/config_files.md +87 -0
  46. package/skills/alloy-howtos/references/custom_tags.md +147 -0
  47. package/skills/alloy-howtos/references/debugging_troubleshooting.md +101 -0
  48. package/skills/alloy-howtos/references/samples.md +167 -0
  49. package/skills/purgetss/SKILL.md +442 -0
  50. package/skills/purgetss/assets/purgetss.config.cjs +17 -0
  51. package/skills/purgetss/references/EXAMPLES.md +247 -0
  52. package/skills/purgetss/references/animation-system.md +1294 -0
  53. package/skills/purgetss/references/apply-directive.md +375 -0
  54. package/skills/purgetss/references/arbitrary-values.md +612 -0
  55. package/skills/purgetss/references/class-index.md +1350 -0
  56. package/skills/purgetss/references/cli-commands.md +948 -0
  57. package/skills/purgetss/references/configurable-properties.md +654 -0
  58. package/skills/purgetss/references/custom-rules.md +161 -0
  59. package/skills/purgetss/references/customization-deep-dive.md +722 -0
  60. package/skills/purgetss/references/dynamic-component-creation.md +489 -0
  61. package/skills/purgetss/references/grid-layout.md +455 -0
  62. package/skills/purgetss/references/icon-fonts.md +609 -0
  63. package/skills/purgetss/references/installation-setup.md +366 -0
  64. package/skills/purgetss/references/opacity-modifier.md +291 -0
  65. package/skills/purgetss/references/platform-modifiers.md +479 -0
  66. package/skills/purgetss/references/smart-mappings.md +42 -0
  67. package/skills/purgetss/references/titanium-resets.md +359 -0
  68. package/skills/purgetss/references/ui-ux-design.md +1526 -0
  69. package/skills/ti-guides/SKILL.md +94 -0
  70. package/skills/ti-guides/references/advanced-data-and-images.md +19 -0
  71. package/skills/ti-guides/references/alloy-cli-advanced.md +84 -0
  72. package/skills/ti-guides/references/alloy-data-mastery.md +29 -0
  73. package/skills/ti-guides/references/alloy-widgets-and-themes.md +19 -0
  74. package/skills/ti-guides/references/android-manifest.md +97 -0
  75. package/skills/ti-guides/references/app-distribution.md +258 -0
  76. package/skills/ti-guides/references/application-frameworks.md +377 -0
  77. package/skills/ti-guides/references/cli-reference.md +402 -0
  78. package/skills/ti-guides/references/coding-best-practices.md +102 -0
  79. package/skills/ti-guides/references/commonjs-advanced.md +134 -0
  80. package/skills/ti-guides/references/hello-world.md +100 -0
  81. package/skills/ti-guides/references/hyperloop-native-access.md +62 -0
  82. package/skills/ti-guides/references/javascript-primer.md +411 -0
  83. package/skills/ti-guides/references/reserved-words.md +36 -0
  84. package/skills/ti-guides/references/resources.md +183 -0
  85. package/skills/ti-guides/references/style-and-conventions.md +48 -0
  86. package/skills/ti-guides/references/tiapp-config.md +609 -0
  87. package/skills/ti-howtos/SKILL.md +174 -0
  88. package/skills/ti-howtos/references/android-platform-deep-dives.md +658 -0
  89. package/skills/ti-howtos/references/automation-fastlane-appium.md +95 -0
  90. package/skills/ti-howtos/references/buffer-codec-streams.md +140 -0
  91. package/skills/ti-howtos/references/cross-platform-development.md +348 -0
  92. package/skills/ti-howtos/references/debugging-profiling.md +543 -0
  93. package/skills/ti-howtos/references/extending-titanium.md +723 -0
  94. package/skills/ti-howtos/references/google-maps-v2.md +169 -0
  95. package/skills/ti-howtos/references/ios-map-kit.md +143 -0
  96. package/skills/ti-howtos/references/ios-platform-deep-dives.md +783 -0
  97. package/skills/ti-howtos/references/local-data-sources.md +301 -0
  98. package/skills/ti-howtos/references/location-and-maps.md +252 -0
  99. package/skills/ti-howtos/references/media-apis.md +210 -0
  100. package/skills/ti-howtos/references/notification-services.md +599 -0
  101. package/skills/ti-howtos/references/remote-data-sources.md +349 -0
  102. package/skills/ti-howtos/references/tutorials.md +502 -0
  103. package/skills/ti-howtos/references/using-modules.md +237 -0
  104. package/skills/ti-howtos/references/web-content-integration.md +307 -0
  105. package/skills/ti-howtos/references/webpack-build-pipeline.md +78 -0
  106. package/skills/ti-ui/SKILL.md +179 -0
  107. package/skills/ti-ui/references/accessibility-deep-dive.md +242 -0
  108. package/skills/ti-ui/references/animation-and-matrices.md +599 -0
  109. package/skills/ti-ui/references/application-structures.md +655 -0
  110. package/skills/ti-ui/references/custom-fonts-styling.md +579 -0
  111. package/skills/ti-ui/references/event-handling.md +393 -0
  112. package/skills/ti-ui/references/gestures.md +473 -0
  113. package/skills/ti-ui/references/icons-and-splash-screens.md +409 -0
  114. package/skills/ti-ui/references/layouts-and-positioning.md +462 -0
  115. package/skills/ti-ui/references/listviews-and-performance.md +619 -0
  116. package/skills/ti-ui/references/orientation.md +362 -0
  117. package/skills/ti-ui/references/platform-ui-android.md +635 -0
  118. package/skills/ti-ui/references/platform-ui-ios.md +469 -0
  119. package/skills/ti-ui/references/scrolling-views.md +252 -0
  120. package/skills/ti-ui/references/tableviews.md +568 -0
@@ -0,0 +1,469 @@
1
+ # iOS UI Components and Conventions
2
+
3
+ ## Table of Contents
4
+
5
+ - [iOS UI Components and Conventions](#ios-ui-components-and-conventions)
6
+ - [Table of Contents](#table-of-contents)
7
+ - [1. Overview](#1-overview)
8
+ - [2. iPad-Only UI Components](#2-ipad-only-ui-components)
9
+ - [Popover](#popover)
10
+ - [Popover Events](#popover-events)
11
+ - [SplitWindow](#splitwindow)
12
+ - [SplitWindow in Portrait](#splitwindow-in-portrait)
13
+ - [3. Badges](#3-badges)
14
+ - [App Icon Badge](#app-icon-badge)
15
+ - [Tab Badge](#tab-badge)
16
+ - [Accessing Preferences in App](#accessing-preferences-in-app)
17
+ - [Dynamic Quick Actions](#dynamic-quick-actions)
18
+ - [Handling Quick Actions](#handling-quick-actions)
19
+ - [Peek and Pop](#peek-and-pop)
20
+ - [Enabling Peek and Pop](#enabling-peek-and-pop)
21
+ - [Preview Action Styles](#preview-action-styles)
22
+ - [6. Navigation Bar (iOS)](#6-navigation-bar-ios)
23
+ - [NavigationWindow](#navigationwindow)
24
+ - [Toolbar](#toolbar)
25
+ - [System Buttons](#system-buttons)
26
+ - [7. Tab Bar](#7-tab-bar)
27
+ - [Creating Tab Bar](#creating-tab-bar)
28
+ - [Tab Bar Customization (iOS)](#tab-bar-customization-ios)
29
+ - [8. Activity Indicator](#8-activity-indicator)
30
+ - [iOS-Specific Location](#ios-specific-location)
31
+ - [9. Platform Best Practices](#9-platform-best-practices)
32
+ - [Follow iOS Human Interface Guidelines](#follow-ios-human-interface-guidelines)
33
+ - [iOS-Specific Patterns](#ios-specific-patterns)
34
+ - [10. Common Issues](#10-common-issues)
35
+ - [Settings Not Appearing](#settings-not-appearing)
36
+ - [3D Touch Not Working](#3d-touch-not-working)
37
+ - [SplitWindow Issues](#splitwindow-issues)
38
+
39
+ ---
40
+
41
+ ## 1. Overview
42
+
43
+ iOS offers several UI components and conventions that differ from Android. This guide covers iPad-specific controls, app badges, Settings integration, 3D Touch, and iOS-specific navigation patterns.
44
+
45
+ ## 2. iPad-Only UI Components
46
+
47
+ ### Popover
48
+
49
+ Popovers present content temporarily without taking over the entire screen. Used for menus, options, or detail views.
50
+
51
+ ```javascript
52
+ const button = Ti.UI.createButton({
53
+ title: 'Show popover',
54
+ width: 250,
55
+ height: 50,
56
+ top: 30,
57
+ right: 5
58
+ });
59
+
60
+ const popover = Ti.UI.iPad.createPopover({
61
+ width: 300,
62
+ height: 250,
63
+ title: 'Popover Content',
64
+ arrowDirection: Ti.UI.iPad.POPOVER_ARROW_DIRECTION_RIGHT
65
+ });
66
+
67
+ // Add content to popover
68
+ const popoverContent = Ti.UI.createView({
69
+ backgroundColor: 'white'
70
+ });
71
+ popover.add(popoverContent);
72
+
73
+ button.addEventListener('click', (e) => {
74
+ popover.show({
75
+ view: button, // Anchor to this view
76
+ animated: true
77
+ });
78
+ });
79
+
80
+ win.add(button);
81
+ ```
82
+ ...
83
+ ### Popover Events
84
+
85
+ ```javascript
86
+ popover.addEventListener('hide', (e) => {
87
+ Ti.API.info('Popover hidden');
88
+ });
89
+
90
+ popover.addEventListener('show', (e) => {
91
+ Ti.API.info('Popover shown');
92
+ });
93
+
94
+ // Dismiss programmatically
95
+ popover.hide();
96
+ ```
97
+
98
+ ### SplitWindow
99
+
100
+ SplitWindow manages master-detail interface (left pane list, right pane details). iPad only.
101
+
102
+ ```javascript
103
+ // Master (left) window
104
+ const masterWin = Ti.UI.createWindow({
105
+ backgroundColor: '#fff',
106
+ title: 'Master'
107
+ });
108
+ masterWin.add(Ti.UI.createLabel({
109
+ text: 'Master View - Select an item',
110
+ font: { fontWeight: 'bold', fontSize: 16 }
111
+ }));
112
+
113
+ // Detail (right) window
114
+ const detailWin = Ti.UI.createWindow({
115
+ backgroundColor: '#dfdfdf',
116
+ title: 'Detail'
117
+ });
118
+ detailWin.add(Ti.UI.createLabel({
119
+ text: 'Detail View - Item details',
120
+ font: { fontWeight: 'bold', fontSize: 16 }
121
+ }));
122
+
123
+ // Create split window
124
+ const splitwin = Ti.UI.iPad.createSplitWindow({
125
+ detailView: detailWin,
126
+ masterView: masterWin,
127
+ orientationModes: [
128
+ Ti.UI.LANDSCAPE_LEFT,
129
+ Ti.UI.LANDSCAPE_RIGHT
130
+ ]
131
+ });
132
+
133
+ splitwin.open();
134
+ ```
135
+ ...
136
+ ### SplitWindow in Portrait
137
+
138
+ By default, master view hides in portrait. To show master view:
139
+
140
+ ```javascript
141
+ splitwin.addEventListener('visible', (e) => {
142
+ if (e.view === 'master' && !e.visible) {
143
+ // Master is hidden, show it in a popover or navigation
144
+ splitwin.showMasterViewInPopover();
145
+ }
146
+ });
147
+ ```
148
+
149
+ ## 3. Badges
150
+
151
+ ### App Icon Badge
152
+
153
+ ```javascript
154
+ // Set badge to number
155
+ Ti.UI.iOS.appBadge = 23;
156
+
157
+ // Remove badge (set to null, not 0)
158
+ Ti.UI.iOS.appBadge = null;
159
+
160
+ // Note: Setting to 0 still displays "0"
161
+ ```
162
+
163
+ ### Tab Badge
164
+
165
+ ```javascript
166
+ const tabGroup = Ti.UI.createTabGroup();
167
+
168
+ const win1 = Ti.UI.createWindow({ title: 'Window 1' });
169
+
170
+ const tab1 = Ti.UI.createTab({
171
+ icon: 'myIcon.png',
172
+ title: 'Tab 1',
173
+ window: win1,
174
+ badge: 10 // Show badge with number
175
+ });
176
+
177
+ // Update badge
178
+ tab1.setBadge(5);
179
+ tab1.badge = 5;
180
+
181
+ // Clear badge
182
+ tab1.setBadge(null);
183
+ tab1.badge = null;
184
+ ```
185
+ ...
186
+ ### Accessing Preferences in App
187
+
188
+ ```javascript
189
+ // Must match the "Key" value from Root.plist
190
+ const name = Ti.App.Properties.getString('name_preference');
191
+ const enabled = Ti.App.Properties.getBool('enabled_preference');
192
+ ```
193
+ ...
194
+ #### Dynamic Quick Actions
195
+
196
+ ```javascript
197
+ if (Ti.UI.iOS.forceTouchSupported) {
198
+ const appShortcuts = Ti.UI.iOS.createApplicationShortcuts();
199
+
200
+ appShortcuts.addDynamicShortcut({
201
+ itemtype: 'com.myapp.share',
202
+ title: 'Share Photo',
203
+ subtitle: 'Share last photo',
204
+ icon: Ti.UI.iOS.SHORTCUT_ICON_TYPE_SHARE,
205
+ userInfo: {
206
+ action: 'share_photo',
207
+ photoId: '123'
208
+ }
209
+ });
210
+
211
+ // Remove specific shortcut
212
+ appShortcuts.removeDynamicShortcut('com.myapp.share');
213
+
214
+ // Remove all dynamic shortcuts
215
+ appShortcuts.removeAllDynamicShortcuts();
216
+ }
217
+ ```
218
+
219
+ #### Handling Quick Actions
220
+
221
+ ```javascript
222
+ Ti.App.iOS.addEventListener('shortcutitemclick', (e) => {
223
+ Ti.API.info(`Shortcut clicked: ${e.itemtype}`);
224
+
225
+ switch(e.itemtype) {
226
+ case 'com.myapp.add':
227
+ addNewItem();
228
+ break;
229
+ case 'com.myapp.recent':
230
+ openRecent();
231
+ break;
232
+ case 'com.myapp.share':
233
+ sharePhoto(e.userInfo.photoId);
234
+ break;
235
+ }
236
+ });
237
+ ```
238
+
239
+ ### Peek and Pop
240
+
241
+ Peek provides a preview of content, Pop opens it fully.
242
+
243
+ #### Enabling Peek and Pop
244
+
245
+ ```javascript
246
+ if (Ti.UI.iOS.forceTouchSupported) {
247
+
248
+ const preview = Alloy.createController('preview').getView();
249
+ const detail = Alloy.createController('detail').getView();
250
+
251
+ const shareAction = Ti.UI.iOS.createPreviewAction({
252
+ title: "Share",
253
+ style: Ti.UI.iOS.PREVIEW_ACTION_STYLE_DEFAULT
254
+ });
255
+
256
+ shareAction.addEventListener('click', (e) => {
257
+ // Handle share action
258
+ });
259
+
260
+ const previewContext = Ti.UI.iOS.createPreviewContext({
261
+ preview: preview,
262
+ contentHeight: 400,
263
+ actions: [shareAction]
264
+ });
265
+
266
+ previewContext.addEventListener('peek', () => {
267
+ Ti.API.info('User started peeking');
268
+ });
269
+
270
+ previewContext.addEventListener('pop', () => {
271
+ Ti.API.info('User popped to full view');
272
+ detail.open();
273
+ });
274
+
275
+ // Attach to view
276
+ $.peekView.previewContext = previewContext;
277
+ }
278
+ ```
279
+
280
+ #### Preview Action Styles
281
+
282
+ ```javascript
283
+ Ti.UI.iOS.PREVIEW_ACTION_STYLE_DEFAULT
284
+ Ti.UI.iOS.PREVIEW_ACTION_STYLE_SELECTED // Blue background
285
+ Ti.UI.iOS.PREVIEW_ACTION_STYLE_DESTRUCTIVE // Red background
286
+ ```
287
+
288
+ ## 6. Navigation Bar (iOS)
289
+
290
+ ### NavigationWindow
291
+
292
+ ```javascript
293
+ const win1 = Ti.UI.createWindow({
294
+ backgroundColor: 'white',
295
+ title: 'First Window'
296
+ });
297
+
298
+ const navWindow = Ti.UI.createNavigationWindow({
299
+ window: win1
300
+ });
301
+
302
+ // Open second window
303
+ const win2 = Ti.UI.createWindow({
304
+ backgroundColor: 'gray',
305
+ title: 'Second Window'
306
+ });
307
+
308
+ navWindow.openWindow(win2, { animated: true });
309
+
310
+ // Close to go back
311
+ win2.close();
312
+
313
+ // Hide navigation bar
314
+ win1.navBarHidden = true;
315
+ ```
316
+
317
+ ### Toolbar
318
+
319
+ ```javascript
320
+ const flexSpace = Ti.UI.createButton({
321
+ systemButton: Ti.UI.iOS.SystemButton.FLEXIBLE_SPACE
322
+ });
323
+
324
+ const refreshButton = Ti.UI.createButton({
325
+ title: 'Refresh'
326
+ });
327
+
328
+ const toolbar = Ti.UI.createToolbar({
329
+ items: [refreshButton, flexSpace],
330
+ bottom: 0
331
+ });
332
+
333
+ win.add(toolbar);
334
+ ```
335
+
336
+ ### System Buttons
337
+
338
+ ```javascript
339
+ Ti.UI.iOS.SystemButton.DONE
340
+ Ti.UI.iOS.SystemButton.CANCEL
341
+ Ti.UI.iOS.SystemButton.EDIT
342
+ Ti.UI.iOS.SystemButton.SAVE
343
+ Ti.UI.iOS.SystemButton.ADD
344
+ Ti.UI.iOS.SystemButton.FLEXIBLE_SPACE
345
+ Ti.UI.iOS.SystemButton.FIXED_SPACE
346
+ // ... and more
347
+ ```
348
+
349
+ ## 7. Tab Bar
350
+
351
+ ### Creating Tab Bar
352
+
353
+ ```javascript
354
+ const tabGroup = Ti.UI.createTabGroup();
355
+
356
+ const tab1 = Ti.UI.createTab({
357
+ icon: 'home.png',
358
+ title: 'Home',
359
+ window: Ti.UI.createWindow({ backgroundColor: 'white' })
360
+ });
361
+
362
+ const tab2 = Ti.UI.createTab({
363
+ icon: 'settings.png',
364
+ title: 'Settings',
365
+ window: Ti.UI.createWindow({ backgroundColor: 'gray' })
366
+ });
367
+
368
+ tabGroup.addTab(tab1);
369
+ tabGroup.addTab(tab2);
370
+
371
+ tabGroup.open();
372
+ ```
373
+
374
+ ### Tab Bar Customization (iOS)
375
+
376
+ ```javascript
377
+ tabGroup.setActiveTabIconColor('blue');
378
+ tabGroup.setActiveTabColor('#f0f0f0');
379
+
380
+ // Hide tab bar on specific window
381
+ win1.tabBarHidden = true;
382
+
383
+ // Set tab bar style (deprecated in iOS 13+)
384
+ tabGroup.tabsStyle = Ti.UI.iOS.TABS_STYLE_BOTTOM;
385
+ ```
386
+
387
+ ## 8. Activity Indicator
388
+
389
+ ```javascript
390
+ const activityIndicator = Ti.UI.createActivityIndicator({
391
+ message: 'Loading...',
392
+ color: 'white',
393
+ backgroundColor: '#333',
394
+ font: { fontSize: 16, fontWeight: 'bold' }
395
+ });
396
+
397
+ activityIndicator.show();
398
+
399
+ // Later
400
+ activityIndicator.hide();
401
+ ```
402
+
403
+ ### iOS-Specific Location
404
+
405
+ ```javascript
406
+ const activityIndicator = Ti.UI.createActivityIndicator({
407
+ message: 'Loading...',
408
+ location: Ti.UI.iOS.ACTIVITY_INDICATOR_DIALOG,
409
+ opacity: 0.8
410
+ });
411
+ ```
412
+
413
+ ## 9. Platform Best Practices
414
+
415
+ ### Follow iOS Human Interface Guidelines
416
+
417
+ - Use NavigationWindow for hierarchical navigation
418
+ - Use Tab Bar for top-level categories
419
+ - Present modal views for focused tasks
420
+ - Use Popovers for auxiliary content (iPad)
421
+ - Respect 3D Touch conventions
422
+
423
+ ### iOS-Specific Patterns
424
+
425
+ ```javascript
426
+ // Use system buttons for standard actions
427
+ const doneButton = Ti.UI.createButton({
428
+ systemButton: Ti.UI.iOS.SystemButton.DONE
429
+ });
430
+
431
+ // Use NavigationWindow animations
432
+ navWindow.openWindow(win2, {
433
+ animated: true,
434
+ transition: Ti.UI.iOS.NavigationWindowTransitionStyle.NONE
435
+ });
436
+
437
+ // Respect safe area (iPhone X+)
438
+ const view = Ti.UI.createView({
439
+ top: Ti.Platform.displayCaps.platformHeight > 800 ? 44 : 20 // Account for notch
440
+ });
441
+ ```
442
+
443
+ ## 10. Common Issues
444
+
445
+ ### Settings Not Appearing
446
+
447
+ **Problem**: Settings not visible in Settings app
448
+
449
+ **Solutions**:
450
+ 1. Clean and rebuild project
451
+ 2. Check plist syntax
452
+ 3. Ensure Settings.bundle is in platform/iphone/
453
+ 4. Kill and relaunch Settings app
454
+
455
+ ### 3D Touch Not Working
456
+
457
+ **Problem**: 3D Touch features don't respond
458
+
459
+ **Solutions**:
460
+ 1. Must test on physical 3D Touch device
461
+ 2. Check `Ti.UI.iOS.forceTouchSupported` before using
462
+ 3. Ensure iOS 9 or later
463
+ 4. Verify `previewContext` is properly attached
464
+
465
+ ### SplitWindow Issues
466
+
467
+ **Problem**: Master view not visible in portrait
468
+
469
+ **Solution**: This is default behavior. Use `showMasterViewInPopover()` or handle via NavigationWindow.
@@ -0,0 +1,252 @@
1
+ # Scrolling Views
2
+
3
+ ## Table of Contents
4
+
5
+ - [Scrolling Views](#scrolling-views)
6
+ - [Table of Contents](#table-of-contents)
7
+ - [1. ScrollView vs ScrollableView](#1-scrollview-vs-scrollableview)
8
+ - [2. ScrollView](#2-scrollview)
9
+ - [Creating a ScrollView](#creating-a-scrollview)
10
+ - [ScrollView Events](#scrollview-events)
11
+ - [Android ScrollView Direction](#android-scrollview-direction)
12
+ - [3. ScrollableView](#3-scrollableview)
13
+ - [Creating a ScrollableView](#creating-a-scrollableview)
14
+ - [ScrollableView Events](#scrollableview-events)
15
+ - [Image Gallery](#image-gallery)
16
+ - [Onboarding Wizard](#onboarding-wizard)
17
+ - [Long Form Content](#long-form-content)
18
+ - [Scrollable Form](#scrollable-form)
19
+ - [ScrollableView](#scrollableview)
20
+ - [8. Detecting Scroll Position](#8-detecting-scroll-position)
21
+ - [Best Practices](#best-practices)
22
+
23
+ ---
24
+
25
+ ## 1. ScrollView vs ScrollableView
26
+
27
+ | Feature | ScrollView | ScrollableView |
28
+ | ---------------- | ------------------------------ | -------------------------------- |
29
+ | Purpose | Scrollable area of content | Paging through multiple views |
30
+ | Scroll Direction | Vertical and/or horizontal | Horizontal only |
31
+ | Content Size | `contentHeight`/`contentWidth` | Full-screen views |
32
+ | User Interaction | Drag to scroll | Swipe to snap between pages |
33
+ | Use Case | Long content, forms, images | Image gallery, onboarding wizard |
34
+
35
+ ## 2. ScrollView
36
+
37
+ ### Creating a ScrollView
38
+
39
+ ```javascript
40
+ const scrollView = Ti.UI.createScrollView({
41
+ width: 300,
42
+ height: 200,
43
+ contentWidth: Ti.UI.SIZE, // Auto-fit to content
44
+ contentHeight: Ti.UI.SIZE, // Auto-fit to content
45
+ backgroundColor: 'white'
46
+ });
47
+
48
+ // Add content
49
+ const content = Ti.UI.createView({
50
+ width: 500,
51
+ height: 500,
52
+ backgroundColor: 'blue'
53
+ });
54
+
55
+ scrollView.add(content);
56
+ win.add(scrollView);
57
+ ```
58
+ ...
59
+ ### ScrollView Events
60
+
61
+ ```javascript
62
+ scrollView.addEventListener('scroll', (e) => {
63
+ Ti.API.info('Scrolling...');
64
+ Ti.API.info(`Content offset: x=${e.contentOffset.x} y=${e.contentOffset.y}`);
65
+ });
66
+
67
+ scrollView.addEventListener('dragEnd', (e) => {
68
+ Ti.API.info('Drag ended');
69
+ e.source.setContentOffset({ x: 0, y: 0 }, { animated: true });
70
+ });
71
+
72
+ scrollView.addEventListener('scrollEnd', (e) => {
73
+ Ti.API.info('Scroll completely ended');
74
+ e.source.setContentOffset({ x: 0, y: 0 }, { animated: true });
75
+ });
76
+ ```
77
+ ...
78
+ ### Android ScrollView Direction
79
+
80
+ Android ScrollView can be vertical OR horizontal, not both:
81
+
82
+ ```javascript
83
+ // Explicit horizontal scroll
84
+ const scrollView = Ti.UI.createScrollView({
85
+ width: 300,
86
+ height: 200,
87
+ scrollType: 'horizontal', // Android: horizontal only
88
+ contentWidth: 600, // Must be larger than width
89
+ contentHeight: 200 // Same as height = no vertical scroll
90
+ });
91
+ ```
92
+ ...
93
+ ## 3. ScrollableView
94
+
95
+ ### Creating a ScrollableView
96
+
97
+ ```javascript
98
+ const view1 = Ti.UI.createView({ backgroundColor: '#123' });
99
+ const view2 = Ti.UI.createView({ backgroundColor: '#234' });
100
+ const view3 = Ti.UI.createView({ backgroundColor: '#345' });
101
+
102
+ const scrollableView = Ti.UI.createScrollableView({
103
+ views: [view1, view2, view3],
104
+ showPagingControl: true,
105
+ pagingControlHeight: 30,
106
+ pagingControlColor: 'blue'
107
+ });
108
+
109
+ win.add(scrollableView);
110
+ ```
111
+ ...
112
+ ### ScrollableView Events
113
+
114
+ ```javascript
115
+ scrollableView.addEventListener('scroll', (e) => {
116
+ Ti.API.info(`Current page: ${e.currentPage}`);
117
+ Ti.API.info(`Views: ${e.view}`); // View object reference
118
+ });
119
+
120
+ scrollableView.addEventListener('dragEnd', (e) => {
121
+ Ti.API.info(`Drag ended, settled on page: ${e.currentPage}`);
122
+ });
123
+ ```
124
+ ...
125
+ ### Image Gallery
126
+
127
+ ```javascript
128
+ const images = [];
129
+ for (let i = 1; i <= 10; i++) {
130
+ images.push(Ti.UI.createImageView({
131
+ image: `image${i}.jpg`,
132
+ width: Ti.UI.FILL,
133
+ height: Ti.UI.FILL
134
+ }));
135
+ }
136
+
137
+ const gallery = Ti.UI.createScrollableView({
138
+ views: images,
139
+ showPagingControl: true
140
+ });
141
+ ```
142
+
143
+ ### Onboarding Wizard
144
+
145
+ ```javascript
146
+ const page1 = createOnboardingPage('Welcome', 'Get started with our app');
147
+ const page2 = createOnboardingPage('Features', 'Learn about key features');
148
+ const page3 = createOnboardingPage('Get Started', 'Create your account');
149
+
150
+ const onboarding = Ti.UI.createScrollableView({
151
+ views: [page1, page2, page3],
152
+ showPagingControl: true
153
+ });
154
+
155
+ const nextButton = Ti.UI.createButton({
156
+ title: 'Next',
157
+ bottom: 20
158
+ });
159
+ nextButton.addEventListener('click', () => {
160
+ const current = onboarding.currentPage;
161
+ if (current < 2) {
162
+ onboarding.scrollToView(current + 1);
163
+ } else {
164
+ onboarding.close();
165
+ showMainApp();
166
+ }
167
+ });
168
+ ```
169
+
170
+ ### Long Form Content
171
+
172
+ ```javascript
173
+ const scrollView = Ti.UI.createScrollView({
174
+ width: Ti.UI.FILL,
175
+ height: Ti.UI.FILL,
176
+ contentHeight: Ti.UI.SIZE,
177
+ layout: 'vertical'
178
+ });
179
+
180
+ // Add many components
181
+ for (let i = 0; i < 50; i++) {
182
+ scrollView.add(Ti.UI.createLabel({
183
+ text: `Item ${i}`,
184
+ top: 10,
185
+ height: 40
186
+ }));
187
+ }
188
+ ```
189
+
190
+ ### Scrollable Form
191
+
192
+ ```javascript
193
+ const formScrollView = Ti.UI.createScrollView({
194
+ layout: 'vertical',
195
+ height: Ti.UI.FILL
196
+ });
197
+
198
+ const nameField = Ti.UI.createTextField({
199
+ hintText: 'Name',
200
+ top: 10, height: 40
201
+ });
202
+
203
+ const emailField = Ti.UI.createTextField({
204
+ hintText: 'Email',
205
+ top: 10, height: 40
206
+ });
207
+
208
+ const submitButton = Ti.UI.createButton({
209
+ title: 'Submit',
210
+ top: 10
211
+ });
212
+
213
+ formScrollView.add(nameField);
214
+ formScrollView.add(emailField);
215
+ formScrollView.add(submitButton);
216
+ ```
217
+ ...
218
+ ### ScrollableView
219
+
220
+ ```javascript
221
+ // Move to page 2
222
+ scrollableView.scrollToView(1);
223
+
224
+ // Move to last page
225
+ scrollableView.scrollToView(scrollableView.views.length - 1);
226
+
227
+ // Get current page
228
+ const current = scrollableView.currentPage;
229
+ ```
230
+
231
+ ## 8. Detecting Scroll Position
232
+
233
+ ```javascript
234
+ scrollView.addEventListener('scroll', (e) => {
235
+ const { x, y } = e.contentOffset;
236
+
237
+ // Detect near bottom
238
+ const maxScroll = scrollView.contentHeight - scrollView.height;
239
+ if (y > maxScroll - 50) {
240
+ loadMoreContent();
241
+ }
242
+ });
243
+ ```
244
+
245
+ ## Best Practices
246
+
247
+ 1. **Use ScrollableView** for paginated content (galleries, wizards)
248
+ 2. **Use ScrollView** for continuous scrolling content (long forms, articles)
249
+ 3. **Specify dimensions** explicitly on Android when possible
250
+ 4. **Consider performance** with large datasets
251
+ 5. **Test on real devices** - simulator behavior may differ
252
+ 6. **Use paging controls** for ScrollableView to improve UX