@maccesar/titools 2.2.12 → 2.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 (104) hide show
  1. package/README.md +255 -713
  2. package/bin/titools.js +9 -1
  3. package/lib/cache.js +49 -0
  4. package/lib/commands/auto-update.js +138 -0
  5. package/lib/commands/skills.js +11 -0
  6. package/lib/commands/uninstall.js +17 -1
  7. package/lib/commands/update.js +5 -6
  8. package/lib/config.js +3 -0
  9. package/lib/downloader.js +10 -0
  10. package/lib/hooks.js +59 -0
  11. package/lib/utils.js +1 -0
  12. package/package.json +1 -1
  13. package/skills/alloy-guides/SKILL.md +46 -48
  14. package/skills/alloy-guides/references/CONTROLLERS.md +4 -6
  15. package/skills/alloy-guides/references/MODELS.md +340 -184
  16. package/skills/alloy-guides/references/VIEWS_DYNAMIC.md +3 -4
  17. package/skills/alloy-guides/references/VIEWS_STYLES.md +44 -46
  18. package/skills/alloy-guides/references/VIEWS_WITHOUT_CONTROLLERS.md +4 -5
  19. package/skills/alloy-guides/references/VIEWS_XML.md +51 -17
  20. package/skills/alloy-guides/references/WIDGETS.md +1 -1
  21. package/skills/alloy-howtos/SKILL.md +12 -13
  22. package/skills/alloy-howtos/references/cli_reference.md +40 -41
  23. package/skills/alloy-howtos/references/samples.md +3 -4
  24. package/skills/purgetss/SKILL.md +369 -356
  25. package/skills/purgetss/references/EXAMPLES.md +24 -25
  26. package/skills/purgetss/references/animation-advanced.md +555 -0
  27. package/skills/purgetss/references/animation-system.md +395 -995
  28. package/skills/purgetss/references/apply-directive.md +111 -141
  29. package/skills/purgetss/references/arbitrary-values.md +206 -480
  30. package/skills/purgetss/references/class-categories.md +277 -0
  31. package/skills/purgetss/references/class-index.md +1 -420
  32. package/skills/purgetss/references/cli-commands.md +446 -556
  33. package/skills/purgetss/references/configurable-properties.md +163 -599
  34. package/skills/purgetss/references/custom-rules.md +33 -76
  35. package/skills/purgetss/references/customization-deep-dive.md +319 -518
  36. package/skills/purgetss/references/dynamic-component-creation.md +33 -37
  37. package/skills/purgetss/references/grid-layout.md +42 -371
  38. package/skills/purgetss/references/icon-fonts.md +82 -475
  39. package/skills/purgetss/references/installation-setup.md +159 -331
  40. package/skills/purgetss/references/migration-guide.md +54 -109
  41. package/skills/purgetss/references/opacity-modifier.md +25 -222
  42. package/skills/purgetss/references/performance-tips.md +2 -2
  43. package/skills/purgetss/references/platform-modifiers.md +21 -407
  44. package/skills/purgetss/references/tikit-components.md +237 -104
  45. package/skills/purgetss/references/titanium-resets.md +20 -21
  46. package/skills/purgetss/references/ui-ux-design.md +171 -1702
  47. package/skills/ti-api/SKILL.md +109 -0
  48. package/skills/ti-api/references/api-android.md +675 -0
  49. package/skills/ti-api/references/api-app-platform.md +636 -0
  50. package/skills/ti-api/references/api-core.md +764 -0
  51. package/skills/ti-api/references/api-data-network.md +641 -0
  52. package/skills/ti-api/references/api-media.md +655 -0
  53. package/skills/ti-api/references/api-modules-ble-bluetooth.md +657 -0
  54. package/skills/ti-api/references/api-modules-coremotion-urlsession.md +411 -0
  55. package/skills/ti-api/references/api-modules-map.md +632 -0
  56. package/skills/ti-api/references/api-modules-nfc.md +725 -0
  57. package/skills/ti-api/references/api-modules-social-misc.md +526 -0
  58. package/skills/ti-api/references/api-services.md +700 -0
  59. package/skills/ti-api/references/api-ui-android.md +499 -0
  60. package/skills/ti-api/references/api-ui-extras.md +702 -0
  61. package/skills/ti-api/references/api-ui-ios-animator.md +378 -0
  62. package/skills/ti-api/references/api-ui-ios.md +756 -0
  63. package/skills/ti-api/references/api-ui-lists.md +581 -0
  64. package/skills/ti-api/references/api-ui-text-input.md +607 -0
  65. package/skills/ti-api/references/api-ui-views.md +572 -0
  66. package/skills/ti-api/references/api-ui-windows-navigation.md +676 -0
  67. package/skills/ti-api/references/api-xml-global.md +743 -0
  68. package/skills/ti-expert/SKILL.md +46 -45
  69. package/skills/ti-expert/references/adaptive-layouts.md +414 -0
  70. package/skills/ti-expert/references/alloy-builtins.md +16 -20
  71. package/skills/ti-expert/references/alloy-structure.md +40 -42
  72. package/skills/ti-expert/references/anti-patterns.md +34 -0
  73. package/skills/ti-expert/references/code-conventions.md +5 -3
  74. package/skills/ti-expert/references/error-handling.md +14 -7
  75. package/skills/ti-expert/references/examples.md +4 -2
  76. package/skills/ti-expert/references/performance-optimization.md +26 -24
  77. package/skills/ti-expert/references/security-device.md +17 -14
  78. package/skills/ti-expert/references/security-fundamentals.md +60 -101
  79. package/skills/ti-expert/references/state-management.md +15 -14
  80. package/skills/ti-expert/references/testing-e2e-ci.md +30 -21
  81. package/skills/ti-expert/references/theming.md +12 -20
  82. package/skills/ti-guides/SKILL.md +13 -17
  83. package/skills/ti-guides/references/advanced-data-and-images.md +30 -10
  84. package/skills/ti-guides/references/application-frameworks.md +3 -3
  85. package/skills/ti-guides/references/coding-best-practices.md +31 -2
  86. package/skills/ti-guides/references/commonjs-advanced.md +46 -4
  87. package/skills/ti-guides/references/hello-world.md +9 -13
  88. package/skills/ti-guides/references/hyperloop-native-access.md +4 -1
  89. package/skills/ti-guides/references/javascript-primer.md +13 -5
  90. package/skills/ti-guides/references/resources.md +0 -2
  91. package/skills/ti-guides/references/style-and-conventions.md +1 -0
  92. package/skills/ti-guides/references/tiapp-config.md +0 -32
  93. package/skills/ti-howtos/SKILL.md +43 -45
  94. package/skills/ti-howtos/references/buffer-codec-streams.md +25 -3
  95. package/skills/ti-howtos/references/debugging-profiling.md +14 -25
  96. package/skills/ti-howtos/references/google-maps-v2.md +3 -3
  97. package/skills/ti-howtos/references/ios-map-kit.md +8 -1
  98. package/skills/ti-howtos/references/notification-services.md +0 -1
  99. package/skills/ti-howtos/references/webpack-build-pipeline.md +3 -0
  100. package/skills/ti-ui/SKILL.md +47 -49
  101. package/skills/ti-ui/references/application-structures.md +3 -2
  102. package/skills/ti-ui/references/orientation.md +17 -9
  103. package/skills/ti-ui/references/platform-ui-ios.md +63 -0
  104. package/skills/ti-ui/references/scrolling-views.md +39 -0
@@ -8,11 +8,17 @@ Buffers are mutable, resizable containers for bytes (byte arrays).
8
8
 
9
9
  ### Creating buffers
10
10
  ```javascript
11
+ // Empty buffer (initial length 0)
12
+ const buffer0 = Ti.createBuffer();
13
+
11
14
  // Empty 512-byte buffer
12
15
  const buffer1 = Ti.createBuffer({ length: 512 });
13
16
 
14
17
  // Buffer initialized with a string (UTF-8 by default)
15
18
  const buffer2 = Ti.createBuffer({ value: 'Hello World' });
19
+
20
+ // Buffer initialized with explicit charset
21
+ const buffer3 = Ti.createBuffer({ value: 'Hello World', type: Ti.Codec.CHARSET_UTF16 });
16
22
  ```
17
23
 
18
24
  ### Common operations
@@ -20,14 +26,18 @@ const buffer2 = Ti.createBuffer({ value: 'Hello World' });
20
26
  const b1 = Ti.createBuffer({ value: 'Part 1. ' });
21
27
  const b2 = Ti.createBuffer({ value: 'Part 2.' });
22
28
 
23
- // Append
29
+ // Append (resizes b1)
24
30
  b1.append(b2);
25
31
 
32
+ // Insert at position (resizes buffer as needed)
33
+ const extra = Ti.createBuffer({ value: 'X' });
34
+ b1.insert(extra, 1); // insert extra at index 1
35
+
26
36
  // Truncate
27
37
  b1.length = 10;
28
38
 
29
- // Direct access (array-like)
30
- b1[0] = 72; // 'H' character in ASCII
39
+ // Direct array access — buffer is NOT auto-extended; values must be byte values
40
+ b1[0] = 72; // 'H' (ASCII). b1[100] = 1 would throw if index >= b1.length
31
41
 
32
42
  // Free memory
33
43
  b1.release();
@@ -48,6 +58,18 @@ Ti.Codec.encodeNumber({
48
58
  });
49
59
  ```
50
60
 
61
+ ### Encoding strings
62
+ ```javascript
63
+ // Encode a string into a buffer; returns the byte length written
64
+ const buffer = Ti.createBuffer({ length: 1024 });
65
+ const encodedLength = Ti.Codec.encodeString({
66
+ source: 'hello world',
67
+ dest: buffer
68
+ });
69
+ // Trim buffer to actual content
70
+ buffer.length = encodedLength;
71
+ ```
72
+
51
73
  ### Decoding strings
52
74
  ```javascript
53
75
  const text = Ti.Codec.decodeString({
@@ -180,11 +180,11 @@ Setup:
180
180
  5. Click Record
181
181
 
182
182
  Key columns:
183
- | Column | What it shows |
184
- | --------------------------------- | ----------------------- |
185
- | Persistent Bytes (Live Bytes) | Memory currently in use |
186
- | #Persistent (#Living) | Active object count |
187
- | #Transient (#Transitory) | Ready to garbage collect |
183
+ | Column | What it shows |
184
+ | ----------------------------- | ------------------------ |
185
+ | Persistent Bytes (Live Bytes) | Memory currently in use |
186
+ | #Persistent (#Living) | Active object count |
187
+ | #Transient (#Transitory) | Ready to garbage collect |
188
188
 
189
189
  Identifying leaks:
190
190
  1. Filter for `Ti` prefix (Titanium objects)
@@ -348,27 +348,22 @@ SELECT * FROM tablename;
348
348
 
349
349
  ### Creating emulators
350
350
 
351
- Command line:
351
+ > **⚠️ AVD Manager moved to Android Studio**
352
+ > The legacy `android` CLI (`android create avd`, `android avd`) was removed in Android SDK Tools 25.3. Use Android Studio's built-in **AVD Manager** (Tools → Device Manager) or the command-line `avdmanager` tool instead.
353
+
354
+ Command line (modern):
352
355
  ```bash
353
- # List available targets
354
- android list targets
356
+ # List available system images
357
+ sdkmanager --list | grep system-images
355
358
 
356
- # Create AVD
357
- android create avd -n my_emulator -t 1 -s WVGA800 --abi x86
359
+ # Create AVD with avdmanager
360
+ avdmanager create avd -n my_emulator -k "system-images;android-34;google_apis;x86_64"
358
361
 
359
362
  # Launch emulator
360
363
  emulator -avd my_emulator
361
364
  ```
362
365
 
363
- AVD Manager (GUI):
364
- ```bash
365
- android avd
366
- ```
367
-
368
- 1. Click New
369
- 2. Enter name, select device/target
370
- 3. Choose x86 ABI if available
371
- 4. Click OK
366
+ Android Studio (GUI): Tools → Device Manager → Create Device.
372
367
 
373
368
  ### Modifying emulators
374
369
 
@@ -378,12 +373,6 @@ Edit `~/.android/avd/<NAME>.avd/config.ini`:
378
373
  disk.dataPartition.size=1024m
379
374
  ```
380
375
 
381
- Resize emulator:
382
- 1. Close emulator
383
- 2. AVD Manager → Select emulator → Edit
384
- 3. Change resolution
385
- 4. Save
386
-
387
376
  Scale on-the-fly:
388
377
  ```bash
389
378
  # Get emulator port
@@ -143,13 +143,13 @@ mapView.addEventListener('click', (e) => {
143
143
  });
144
144
 
145
145
  // Detect drag state changes
146
+ // e.newState holds the drag state constant; e.annotation holds the annotation object
146
147
  mapView.addEventListener('pinchangedragstate', (e) => {
147
- if (e.annotation.dragState === MapModule.ANNOTATION_DRAG_STATE_END) {
148
+ if (e.newState === MapModule.ANNOTATION_DRAG_STATE_END) {
148
149
  Ti.API.info(`Dropped at: ${e.annotation.latitude}, ${e.annotation.longitude}`);
149
150
  }
150
151
  });
151
- // Drag states: ANNOTATION_DRAG_STATE_START, ANNOTATION_DRAG_STATE_DRAG,
152
- // ANNOTATION_DRAG_STATE_CANCEL, ANNOTATION_DRAG_STATE_END
152
+ // Drag states: ANNOTATION_DRAG_STATE_START, ANNOTATION_DRAG_STATE_END
153
153
 
154
154
  // Detect region changes
155
155
  mapView.addEventListener('regionchanged', (e) => {
@@ -77,6 +77,12 @@ mapView.showsBuildings = true; // 3D buildings
77
77
 
78
78
  ## 4. iOS annotations
79
79
 
80
+ ### iOS pin colors
81
+ iOS supports only three pin color constants (unlike Android's ten):
82
+ - `MapModule.ANNOTATION_GREEN`
83
+ - `MapModule.ANNOTATION_PURPLE`
84
+ - `MapModule.ANNOTATION_RED`
85
+
80
86
  ### System buttons and callouts
81
87
  iOS allows native buttons in the pin callout (popup window).
82
88
 
@@ -134,8 +140,9 @@ mapView.addEventListener('click', (e) => {
134
140
  }
135
141
  });
136
142
 
143
+ // e.newState holds the drag state constant; e.annotation holds the annotation object
137
144
  mapView.addEventListener('pinchangedragstate', (e) => {
138
- if (e.annotation.dragState === MapModule.ANNOTATION_DRAG_STATE_END) {
145
+ if (e.newState === MapModule.ANNOTATION_DRAG_STATE_END) {
139
146
  Ti.API.info(`Dropped at: ${e.annotation.latitude}, ${e.annotation.longitude}`);
140
147
  }
141
148
  });
@@ -531,7 +531,6 @@ Use `UNMutableNotificationContent` with attachments (images, video, audio).
531
531
 
532
532
  - Service lifecycle: services may be killed if app is swiped away. For critical notifications, use FCM instead of local services.
533
533
  - Notification channels: Android 8.0+ requires notification channels.
534
- - Limitations: legacy MapView only supports a single map view.
535
534
 
536
535
  ### iOS
537
536
 
@@ -1,5 +1,8 @@
1
1
  # Webpack build pipeline
2
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
+
3
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.
4
7
 
5
8
  ## 1. Key benefits
@@ -11,22 +11,21 @@ A practical guide to Titanium SDK UI. Covers layouts, event handling, animations
11
11
 
12
12
  ## Project detection
13
13
 
14
- :::info auto-detects titanium projects
15
- This skill detects Titanium projects and provides UI guidance.
16
-
17
- Detection happens automatically. You do not need to run a command.
18
-
19
- Titanium project indicator:
20
- - `tiapp.xml` (required for all Titanium projects)
21
-
22
- Applicable to both:
23
- - Alloy projects (app/ folder structure)
24
- - Classic projects (Resources/ folder)
25
-
26
- Behavior based on detection:
27
- - Titanium detected: Provide UI guidance for Alloy and Classic, ListView/TableView patterns, and platform differences
28
- - Not detected: State this is for Titanium projects only and skip UI guidance
29
- :::
14
+ > **️ℹ️ auto-detects titanium projects**
15
+ > This skill detects Titanium projects and provides UI guidance.
16
+ >
17
+ > Detection happens automatically. You do not need to run a command.
18
+ >
19
+ > Titanium project indicator:
20
+ > - `tiapp.xml` (required for all Titanium projects)
21
+ >
22
+ > Applicable to both:
23
+ > - Alloy projects (app/ folder structure)
24
+ > - Classic projects (Resources/ folder)
25
+ >
26
+ > Behavior based on detection:
27
+ > - Titanium detected: Provide UI guidance for Alloy and Classic, ListView/TableView patterns, and platform differences
28
+ > - Not detected: State this is for Titanium projects only and skip UI guidance
30
29
 
31
30
  ## Quick reference
32
31
 
@@ -65,39 +64,38 @@ Behavior based on detection:
65
64
 
66
65
  ### Platform-specific properties
67
66
 
68
- :::danger critical: platform-specific properties require modifiers
69
- Using `Ti.UI.iOS.*` or `Ti.UI.Android.*` properties without platform modifiers will crash cross-platform compilation.
70
-
71
- Example of the damage:
72
- ```javascript
73
- // Wrong: adds Ti.UI.iOS to an Android build
74
- const win = Ti.UI.createWindow({
75
- statusBarStyle: Ti.UI.iOS.StatusBar.LIGHT_CONTENT
76
- })
77
- ```
78
-
79
- Correct approaches:
80
-
81
- Option 1: TSS modifier (Alloy projects):
82
- ```tss
83
- "#mainWindow[platform=ios]": {
84
- statusBarStyle: Ti.UI.iOS.StatusBar.LIGHT_CONTENT
85
- }
86
- ```
87
-
88
- Option 2: Conditional code:
89
- ```javascript
90
- if (OS_IOS) {
91
- $.mainWindow.statusBarStyle = Ti.UI.iOS.StatusBar.LIGHT_CONTENT
92
- }
93
- ```
94
-
95
- Properties that always require platform modifiers:
96
- - iOS: `statusBarStyle`, `modalStyle`, `modalTransitionStyle`, any `Ti.UI.iOS.*`
97
- - Android: `actionBar` config, any `Ti.UI.Android.*` constant
98
-
99
- For platform-specific UI patterns, see [platform-ui-ios.md](references/platform-ui-ios.md) and [platform-ui-android.md](references/platform-ui-android.md).
100
- :::
67
+ > **🚨 critical: platform-specific properties require modifiers**
68
+ > Using `Ti.UI.iOS.*` or `Ti.UI.Android.*` properties without platform modifiers will crash cross-platform compilation.
69
+ >
70
+ > Example of the damage:
71
+ > ```javascript
72
+ > // Wrong: adds Ti.UI.iOS to an Android build
73
+ > const win = Ti.UI.createWindow({
74
+ > statusBarStyle: Ti.UI.iOS.StatusBar.LIGHT_CONTENT
75
+ > })
76
+ > ```
77
+ >
78
+ > Correct approaches:
79
+ >
80
+ > Option 1: TSS modifier (Alloy projects):
81
+ > ```tss
82
+ > "#mainWindow[platform=ios]": {
83
+ > statusBarStyle: Ti.UI.iOS.StatusBar.LIGHT_CONTENT
84
+ > }
85
+ > ```
86
+ >
87
+ > Option 2: Conditional code:
88
+ > ```javascript
89
+ > if (OS_IOS) {
90
+ > $.mainWindow.statusBarStyle = Ti.UI.iOS.StatusBar.LIGHT_CONTENT
91
+ > }
92
+ > ```
93
+ >
94
+ > Properties that always require platform modifiers:
95
+ > - iOS: `statusBarStyle`, `modalStyle`, `modalTransitionStyle`, any `Ti.UI.iOS.*`
96
+ > - Android: `actionBar` config, any `Ti.UI.Android.*` constant
97
+ >
98
+ > For platform-specific UI patterns, see [platform-ui-ios.md](references/platform-ui-ios.md) and [platform-ui-android.md](references/platform-ui-android.md).
101
99
 
102
100
  ### Event management
103
101
  - Remove global listeners (`Ti.App`, `Ti.Gesture`, `Ti.Accelerometer`) on pause to save battery.
@@ -259,7 +259,8 @@ tabGroup.addTab(Ti.UI.createTab({
259
259
 
260
260
  tabGroup.open();
261
261
  ```
262
- ...
262
+
263
+ ```javascript
263
264
  // Window-based app with NavigationWindow (iOS)
264
265
  const navWindow = Ti.UI.createNavigationWindow({
265
266
  window: Ti.UI.createWindow({
@@ -485,7 +486,7 @@ tabGroup.open();
485
486
 
486
487
  SplitWindow (iPad):
487
488
  ```javascript
488
- const splitWin = Ti.UI.iOS.createSplitWindow({
489
+ const splitWin = Ti.UI.iPad.createSplitWindow({
489
490
  masterView: masterWindow,
490
491
  detailView: detailWindow
491
492
  });
@@ -50,12 +50,16 @@ iOS plist iPhone vs iPad keys: You can define separate orientations for iPhone a
50
50
  - `UISupportedInterfaceOrientations~ipad` for iPad (default: all four)
51
51
  - `UISupportedInterfaceOrientations` applies to both if device-specific keys are absent
52
52
 
53
+ The `<activity>` element must include `android:name` and be nested inside `<application>`. Titanium generates the main activity name as `<app-id>.<Appname>Activity`.
54
+
53
55
  ```xml
54
- <android>
56
+ <android xmlns:android="http://schemas.android.com/apk/res/android">
55
57
  <manifest>
56
- <activity>
57
- <android:screenOrientation="portrait"/>
58
- </activity>
58
+ <application>
59
+ <activity
60
+ android:name="com.example.myapp.MyappActivity"
61
+ android:screenOrientation="portrait"/>
62
+ </application>
59
63
  </manifest>
60
64
  </android>
61
65
  ```
@@ -111,9 +115,9 @@ Ti.Gesture.addEventListener('orientationchange', (e) => {
111
115
  adjustForLandscape();
112
116
  }
113
117
 
114
- // Ti.Gesture helper methods - convenience booleans
115
- Ti.API.info(`Is portrait: ${e.source.isPortrait()}`);
116
- Ti.API.info(`Is landscape: ${e.source.isLandscape()}`);
118
+ // Ti.Gesture convenience boolean properties
119
+ Ti.API.info(`Is portrait: ${e.source.portrait}`);
120
+ Ti.API.info(`Is landscape: ${e.source.landscape}`);
117
121
  });
118
122
  ```
119
123
 
@@ -252,9 +256,13 @@ iOS (tiapp.xml):
252
256
 
253
257
  Android (tiapp.xml):
254
258
  ```xml
255
- <android>
259
+ <android xmlns:android="http://schemas.android.com/apk/res/android">
256
260
  <manifest>
257
- <activity android:screenOrientation="portrait"/>
261
+ <application>
262
+ <activity
263
+ android:name="com.example.myapp.MyappActivity"
264
+ android:screenOrientation="portrait"/>
265
+ </application>
258
266
  </manifest>
259
267
  </android>
260
268
  ```
@@ -341,6 +341,69 @@ win2.close();
341
341
  win1.navBarHidden = true;
342
342
  ```
343
343
 
344
+ ## Community-Discovered Patterns
345
+
346
+ ### Large Titles + ScrollView: required property triad (iOS)
347
+
348
+ When using `largeTitleEnabled: true` with a `ScrollView` inside a `NavigationWindow`, three Window properties must be set together. Without all three, the ScrollView content overlaps behind the navigation bar.
349
+
350
+ ```javascript
351
+ const win = Ti.UI.createWindow({
352
+ title: 'My Screen',
353
+ largeTitleEnabled: true,
354
+ largeTitleDisplayMode: Ti.UI.iOS.LARGE_TITLE_DISPLAY_MODE_AUTOMATIC,
355
+ extendEdges: [Ti.UI.EXTEND_EDGE_ALL],
356
+ autoAdjustScrollViewInsets: true,
357
+ barColor: '#1e293b',
358
+ backgroundColor: '#0f172a'
359
+ });
360
+
361
+ const scrollView = Ti.UI.createScrollView({
362
+ layout: 'vertical',
363
+ contentWidth: Ti.UI.FILL,
364
+ contentHeight: Ti.UI.SIZE
365
+ });
366
+
367
+ scrollView.add(Ti.UI.createLabel({ text: 'Content here' }));
368
+ win.add(scrollView);
369
+ navWindow.openWindow(win);
370
+ ```
371
+
372
+ | Property | Purpose | What breaks without it |
373
+ |---|---|---|
374
+ | `largeTitleEnabled: true` | Large title that collapses on scroll | No large title behavior |
375
+ | `extendEdges: [Ti.UI.EXTEND_EDGE_ALL]` | Content renders behind bars (blur/translucent effect) | Large title renders with visible delay (empty nav bar gap appears first, then title draws) |
376
+ | `autoAdjustScrollViewInsets: true` | Automatically adjusts ScrollView insets | Content overlaps behind the nav bar |
377
+
378
+ > **Why all three?** `extendEdges` tells iOS to extend content behind the navigation bar. `autoAdjustScrollViewInsets` tells iOS to compensate by adjusting the ScrollView's content insets so content starts below the bar. Without `extendEdges`, there is nothing to adjust — and the large title renders with a visible delay as iOS cannot calculate the full layout upfront. Without `autoAdjustScrollViewInsets`, the content sits behind the bar. They are interdependent.
379
+
380
+ `largeTitleDisplayMode` controls collapse behavior:
381
+ - `LARGE_TITLE_DISPLAY_MODE_AUTOMATIC` (default) — inherits from previous window; collapses on scroll
382
+ - `LARGE_TITLE_DISPLAY_MODE_ALWAYS` — title stays large regardless of scroll position
383
+ - `LARGE_TITLE_DISPLAY_MODE_NEVER` — always standard title size
384
+
385
+ #### Works with both NavigationWindow and TabGroup
386
+
387
+ On iOS, TabGroup wraps each Tab in an implicit NavigationWindow. The same three properties apply to Windows inside both standalone NavigationWindow and TabGroup Tabs. Child windows opened via `navWindow.openWindow()` or from within a Tab inherit the large title behavior when using `LARGE_TITLE_DISPLAY_MODE_AUTOMATIC`.
388
+
389
+ #### Recommended: global defaults
390
+
391
+ Instead of repeating the properties on every Window, set them as global defaults:
392
+
393
+ ```javascript
394
+ // app.tss (Alloy)
395
+ 'Window[platform=ios]': {
396
+ autoAdjustScrollViewInsets: true,
397
+ extendEdges: [Ti.UI.EXTEND_EDGE_ALL]
398
+ }
399
+ ```
400
+
401
+ Then only add `largeTitleEnabled` and `largeTitleDisplayMode` per-window as needed.
402
+
403
+ > **Note:** The official docs only document the `largeTitleEnabled` + `extendEdges` pair for RefreshControl flicker prevention. The full triad for ScrollView content positioning is not in official documentation.
404
+
405
+ See also: [scrolling-views.md](scrolling-views.md) for ScrollView properties and patterns.
406
+
344
407
  ### Toolbar
345
408
 
346
409
  ```javascript
@@ -241,3 +241,42 @@ scrollView.addEventListener('scroll', (e) => {
241
241
  4. Consider performance with large datasets
242
242
  5. Test on real devices; simulator behavior may differ
243
243
  6. Use paging controls for ScrollableView to improve UX
244
+
245
+ ## Community-Discovered Patterns
246
+
247
+ ### ScrollView inside NavigationWindow with Large Titles (iOS)
248
+
249
+ When placing a ScrollView inside a Window managed by NavigationWindow, configure the Window to ensure proper content positioning — especially when using large titles or translucent bars.
250
+
251
+ Three Window properties must be set together:
252
+
253
+ | Property | Value | Purpose |
254
+ |---|---|---|
255
+ | `extendEdges` | `[Ti.UI.EXTEND_EDGE_ALL]` | Content extends behind bars (enables blur effect) |
256
+ | `autoAdjustScrollViewInsets` | `true` | iOS adjusts ScrollView insets to avoid overlap |
257
+ | `largeTitleEnabled` | `true` | Enables large title that collapses on scroll |
258
+
259
+ Without `autoAdjustScrollViewInsets`, the ScrollView content overlaps behind the navigation bar when `extendEdges` is set. Without `extendEdges`, the large title renders with a visible delay as iOS cannot calculate the full layout upfront.
260
+
261
+ This applies to both standalone NavigationWindow and TabGroup (which wraps each Tab in an implicit NavigationWindow on iOS).
262
+
263
+ ```javascript
264
+ const win = Ti.UI.createWindow({
265
+ title: 'Feed',
266
+ largeTitleEnabled: true,
267
+ extendEdges: [Ti.UI.EXTEND_EDGE_ALL],
268
+ autoAdjustScrollViewInsets: true
269
+ });
270
+
271
+ const scroll = Ti.UI.createScrollView({
272
+ layout: 'vertical',
273
+ contentWidth: Ti.UI.FILL,
274
+ contentHeight: Ti.UI.SIZE
275
+ });
276
+
277
+ // Content starts below the nav bar automatically
278
+ scroll.add(Ti.UI.createView({ height: 200, backgroundColor: 'red' }));
279
+ win.add(scroll);
280
+ ```
281
+
282
+ See [platform-ui-ios.md](platform-ui-ios.md) for the full explanation with `largeTitleDisplayMode` options.