@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.
- package/CONTRIBUTING.md +1 -1
- package/README.md +31 -60
- package/agents/ti-pro.md +3 -1
- package/commands/ti-audit.md +6 -4
- package/docs/examples.md +9 -0
- package/docs/knowledge-index.md +2 -1
- package/lib/config.js +1 -0
- package/package.json +1 -1
- package/skills/alloy-guides/SKILL.md +18 -179
- package/skills/alloy-guides/references/CLI_TASKS.md +17 -216
- package/skills/alloy-guides/references/CONCEPTS.md +27 -162
- package/skills/alloy-guides/references/CONTROLLERS.md +38 -236
- package/skills/alloy-guides/references/MODELS.md +47 -723
- package/skills/alloy-guides/references/MODELS_ADVANCED.md +21 -482
- package/skills/alloy-guides/references/VIEWS_DYNAMIC.md +12 -222
- package/skills/alloy-guides/references/VIEWS_STYLES.md +39 -358
- package/skills/alloy-guides/references/VIEWS_XML.md +36 -552
- package/skills/alloy-guides/references/WIDGETS.md +49 -127
- package/skills/alloy-howtos/SKILL.md +14 -169
- package/skills/alloy-howtos/references/best_practices.md +9 -113
- package/skills/alloy-howtos/references/cli_reference.md +18 -223
- package/skills/alloy-howtos/references/config_files.md +50 -133
- package/skills/alloy-howtos/references/debugging_troubleshooting.md +19 -63
- package/skills/alloy-howtos/references/samples.md +21 -138
- package/skills/ti-api/SKILL.md +10 -2
- package/skills/ti-api/references/api-android.md +36 -2
- package/skills/ti-api/references/api-app-platform.md +39 -3
- package/skills/ti-api/references/api-core.md +50 -18
- package/skills/ti-api/references/api-data-network.md +49 -35
- package/skills/ti-api/references/api-media.md +45 -27
- package/skills/ti-api/references/api-services.md +39 -9
- package/skills/ti-api/references/api-ui-android.md +33 -13
- package/skills/ti-api/references/api-ui-extras.md +41 -15
- package/skills/ti-api/references/api-ui-ios-animator.md +42 -26
- package/skills/ti-api/references/api-ui-ios.md +74 -2
- package/skills/ti-api/references/api-ui-lists.md +32 -16
- package/skills/ti-api/references/api-ui-text-input.md +34 -17
- package/skills/ti-api/references/api-ui-views.md +27 -1
- package/skills/ti-api/references/api-ui-windows-navigation.md +32 -18
- package/skills/ti-api/references/api-xml-global.md +66 -16
- package/skills/ti-create-release/SKILL.md +98 -0
- package/skills/ti-create-release/references/module-discovery.md +69 -0
- package/skills/ti-expert/references/adaptive-layouts.md +1 -1
- package/skills/ti-guides/SKILL.md +37 -76
- package/skills/ti-guides/references/advanced-data-and-images.md +122 -126
- package/skills/ti-guides/references/android-manifest.md +24 -83
- package/skills/ti-guides/references/app-distribution.md +31 -377
- package/skills/ti-guides/references/application-frameworks.md +127 -335
- package/skills/ti-guides/references/cli-reference.md +184 -633
- package/skills/ti-guides/references/commonjs-advanced.md +81 -231
- package/skills/ti-guides/references/compatibility-matrix.md +36 -75
- package/skills/ti-guides/references/hello-world.md +95 -70
- package/skills/ti-guides/references/hyperloop-native-access.md +52 -448
- package/skills/ti-guides/references/resources.md +174 -142
- package/skills/ti-guides/references/sdk-release-notes.md +28 -71
- package/skills/ti-guides/references/tiapp-config.md +222 -598
- package/skills/ti-howtos/SKILL.md +23 -123
- package/skills/ti-howtos/references/cross-platform-development.md +119 -324
- package/skills/ti-howtos/references/debugging-profiling.md +77 -445
- package/skills/ti-howtos/references/extending-titanium.md +199 -673
- package/skills/ti-howtos/references/local-data-sources.md +87 -300
- package/skills/ti-howtos/references/location-and-maps.md +86 -213
- package/skills/ti-howtos/references/media-apis.md +103 -223
- package/skills/ti-howtos/references/notification-services.md +86 -506
- package/skills/ti-howtos/references/remote-data-sources.md +97 -316
- package/skills/ti-howtos/references/using-modules.md +77 -133
- package/skills/ti-ui/SKILL.md +28 -143
- package/skills/ti-ui/references/icons-and-splash-screens.md +74 -403
- package/skills/ti-ui/references/layouts-and-positioning.md +175 -402
- package/skills/ti-ui/references/listviews-and-performance.md +100 -703
- package/skills/ti-ui/references/platform-conventions.md +180 -0
- package/skills/ti-ui/references/user-interface.md +43 -0
- package/skills/alloy-guides/references/VIEWS_WITHOUT_CONTROLLERS.md +0 -102
- package/skills/alloy-howtos/references/custom_tags.md +0 -148
- package/skills/ti-guides/references/coding-best-practices.md +0 -149
- package/skills/ti-guides/references/javascript-primer.md +0 -414
- package/skills/ti-guides/references/reserved-words.md +0 -36
- package/skills/ti-guides/references/style-and-conventions.md +0 -103
- package/skills/ti-howtos/references/android-platform-deep-dives.md +0 -624
- package/skills/ti-howtos/references/automation-fastlane-appium.md +0 -96
- package/skills/ti-howtos/references/buffer-codec-streams.md +0 -162
- package/skills/ti-howtos/references/google-maps-v2.md +0 -172
- package/skills/ti-howtos/references/ios-map-kit.md +0 -149
- package/skills/ti-howtos/references/ios-platform-deep-dives.md +0 -611
- package/skills/ti-howtos/references/tutorials.md +0 -565
- package/skills/ti-howtos/references/web-content-integration.md +0 -287
- package/skills/ti-howtos/references/webpack-build-pipeline.md +0 -124
- package/skills/ti-ui/references/accessibility-deep-dive.md +0 -288
- package/skills/ti-ui/references/animation-and-matrices.md +0 -569
- package/skills/ti-ui/references/application-structures.md +0 -626
- package/skills/ti-ui/references/custom-fonts-styling.md +0 -549
- package/skills/ti-ui/references/event-handling.md +0 -401
- package/skills/ti-ui/references/gestures.md +0 -448
- package/skills/ti-ui/references/orientation.md +0 -374
- package/skills/ti-ui/references/platform-ui-android.md +0 -727
- package/skills/ti-ui/references/platform-ui-ios.md +0 -576
- package/skills/ti-ui/references/scrolling-views.md +0 -288
- package/skills/ti-ui/references/tableviews.md +0 -542
|
@@ -1,576 +0,0 @@
|
|
|
1
|
-
# iOS UI components and conventions
|
|
2
|
-
|
|
3
|
-
<!-- TOC-START -->
|
|
4
|
-
## Contents
|
|
5
|
-
|
|
6
|
-
- [1. Overview](#1-overview)
|
|
7
|
-
- [2. iPad-only UI components](#2-ipad-only-ui-components)
|
|
8
|
-
- [3. Badges](#3-badges)
|
|
9
|
-
- [4. Settings.bundle integration](#4-settingsbundle-integration)
|
|
10
|
-
- [5. Quick Actions and 3D Touch](#5-quick-actions-and-3d-touch)
|
|
11
|
-
- [6. Navigation bar (iOS)](#6-navigation-bar-ios)
|
|
12
|
-
- [Community-Discovered Patterns](#community-discovered-patterns)
|
|
13
|
-
- [7. Tab bar](#7-tab-bar)
|
|
14
|
-
- [8. Activity indicator](#8-activity-indicator)
|
|
15
|
-
- [9. Platform best practices](#9-platform-best-practices)
|
|
16
|
-
- [10. Common issues](#10-common-issues)
|
|
17
|
-
|
|
18
|
-
<!-- TOC-END -->
|
|
19
|
-
|
|
20
|
-
## 1. Overview
|
|
21
|
-
|
|
22
|
-
iOS has UI components and patterns that differ from Android. This guide covers iPad-only controls, badges, Settings integration, 3D Touch, and iOS navigation patterns.
|
|
23
|
-
|
|
24
|
-
## 2. iPad-only UI components
|
|
25
|
-
|
|
26
|
-
### Popover
|
|
27
|
-
|
|
28
|
-
Popovers show temporary content without taking over the whole screen. Use them for menus, options, or detail views.
|
|
29
|
-
|
|
30
|
-
```javascript
|
|
31
|
-
const button = Ti.UI.createButton({
|
|
32
|
-
title: 'Show popover',
|
|
33
|
-
width: 250,
|
|
34
|
-
height: 50,
|
|
35
|
-
top: 30,
|
|
36
|
-
right: 5
|
|
37
|
-
});
|
|
38
|
-
|
|
39
|
-
const popover = Ti.UI.iPad.createPopover({
|
|
40
|
-
width: 300,
|
|
41
|
-
height: 250,
|
|
42
|
-
title: 'Popover Content',
|
|
43
|
-
arrowDirection: Ti.UI.iPad.POPOVER_ARROW_DIRECTION_RIGHT
|
|
44
|
-
});
|
|
45
|
-
|
|
46
|
-
// Add content to popover
|
|
47
|
-
const popoverContent = Ti.UI.createView({
|
|
48
|
-
backgroundColor: 'white'
|
|
49
|
-
});
|
|
50
|
-
popover.add(popoverContent);
|
|
51
|
-
|
|
52
|
-
button.addEventListener('click', () => {
|
|
53
|
-
popover.show({
|
|
54
|
-
view: button, // Anchor to this view
|
|
55
|
-
animated: true
|
|
56
|
-
});
|
|
57
|
-
});
|
|
58
|
-
|
|
59
|
-
win.add(button);
|
|
60
|
-
```
|
|
61
|
-
|
|
62
|
-
### Popover events
|
|
63
|
-
|
|
64
|
-
```javascript
|
|
65
|
-
popover.addEventListener('hide', () => {
|
|
66
|
-
Ti.API.info('Popover hidden');
|
|
67
|
-
});
|
|
68
|
-
|
|
69
|
-
popover.addEventListener('show', () => {
|
|
70
|
-
Ti.API.info('Popover shown');
|
|
71
|
-
});
|
|
72
|
-
|
|
73
|
-
// Dismiss programmatically
|
|
74
|
-
popover.hide();
|
|
75
|
-
```
|
|
76
|
-
|
|
77
|
-
### SplitWindow
|
|
78
|
-
|
|
79
|
-
SplitWindow manages a master-detail layout (left list, right detail). It is iPad only.
|
|
80
|
-
|
|
81
|
-
```javascript
|
|
82
|
-
// Master (left) window
|
|
83
|
-
const masterWin = Ti.UI.createWindow({
|
|
84
|
-
backgroundColor: '#fff',
|
|
85
|
-
title: 'Master'
|
|
86
|
-
});
|
|
87
|
-
masterWin.add(Ti.UI.createLabel({
|
|
88
|
-
text: 'Master View - Select an item',
|
|
89
|
-
font: { fontWeight: 'bold', fontSize: 16 }
|
|
90
|
-
}));
|
|
91
|
-
|
|
92
|
-
// Detail (right) window
|
|
93
|
-
const detailWin = Ti.UI.createWindow({
|
|
94
|
-
backgroundColor: '#dfdfdf',
|
|
95
|
-
title: 'Detail'
|
|
96
|
-
});
|
|
97
|
-
detailWin.add(Ti.UI.createLabel({
|
|
98
|
-
text: 'Detail View - Item details',
|
|
99
|
-
font: { fontWeight: 'bold', fontSize: 16 }
|
|
100
|
-
}));
|
|
101
|
-
|
|
102
|
-
// Create split window
|
|
103
|
-
const splitwin = Ti.UI.iPad.createSplitWindow({
|
|
104
|
-
detailView: detailWin,
|
|
105
|
-
masterView: masterWin,
|
|
106
|
-
orientationModes: [
|
|
107
|
-
Ti.UI.LANDSCAPE_LEFT,
|
|
108
|
-
Ti.UI.LANDSCAPE_RIGHT
|
|
109
|
-
]
|
|
110
|
-
});
|
|
111
|
-
|
|
112
|
-
splitwin.open();
|
|
113
|
-
```
|
|
114
|
-
|
|
115
|
-
### SplitWindow in portrait
|
|
116
|
-
|
|
117
|
-
By default, the master view is hidden in portrait. To show it:
|
|
118
|
-
|
|
119
|
-
```javascript
|
|
120
|
-
splitwin.addEventListener('visible', (e) => {
|
|
121
|
-
if (e.view === 'master' && !e.visible) {
|
|
122
|
-
// Master is hidden, show it in a popover or navigation
|
|
123
|
-
splitwin.showMasterViewInPopover();
|
|
124
|
-
}
|
|
125
|
-
});
|
|
126
|
-
```
|
|
127
|
-
|
|
128
|
-
## 3. Badges
|
|
129
|
-
|
|
130
|
-
### App icon badge
|
|
131
|
-
|
|
132
|
-
```javascript
|
|
133
|
-
// Set badge to number
|
|
134
|
-
Ti.UI.iOS.appBadge = 23;
|
|
135
|
-
|
|
136
|
-
// Remove badge (set to null, not 0)
|
|
137
|
-
Ti.UI.iOS.appBadge = null;
|
|
138
|
-
|
|
139
|
-
// Note: Setting to 0 still displays "0"
|
|
140
|
-
```
|
|
141
|
-
|
|
142
|
-
### Tab badge
|
|
143
|
-
|
|
144
|
-
```javascript
|
|
145
|
-
const tabGroup = Ti.UI.createTabGroup();
|
|
146
|
-
|
|
147
|
-
const win1 = Ti.UI.createWindow({ title: 'Window 1' });
|
|
148
|
-
|
|
149
|
-
const tab1 = Ti.UI.createTab({
|
|
150
|
-
icon: 'myIcon.png',
|
|
151
|
-
title: 'Tab 1',
|
|
152
|
-
window: win1,
|
|
153
|
-
badge: 10 // Show badge with number
|
|
154
|
-
});
|
|
155
|
-
|
|
156
|
-
// Update badge
|
|
157
|
-
tab1.setBadge(5);
|
|
158
|
-
tab1.badge = 5;
|
|
159
|
-
|
|
160
|
-
// Clear badge
|
|
161
|
-
tab1.setBadge(null);
|
|
162
|
-
tab1.badge = null;
|
|
163
|
-
```
|
|
164
|
-
|
|
165
|
-
## 4. Settings.bundle integration
|
|
166
|
-
|
|
167
|
-
iOS apps can expose user settings in the Settings app using a Settings.bundle.
|
|
168
|
-
|
|
169
|
-
Setup:
|
|
170
|
-
- Place the bundle at `platform/iphone/Settings.bundle/` (SDK 1.8+)
|
|
171
|
-
- The bundle contains `Root.plist`, which defines the settings UI (toggles, text fields, groups, etc.)
|
|
172
|
-
- Edit `Root.plist` using Xcode's Property List editor for a visual interface
|
|
173
|
-
|
|
174
|
-
Key conventions: Settings keys typically use the `_preference` suffix, for example `username_preference` or `enabled_preference`.
|
|
175
|
-
|
|
176
|
-
### Access preferences in the app
|
|
177
|
-
|
|
178
|
-
```javascript
|
|
179
|
-
// Read a preference set in iOS Settings app
|
|
180
|
-
const username = Ti.App.Properties.getString('username_preference');
|
|
181
|
-
|
|
182
|
-
// Must match the "Key" value from Root.plist
|
|
183
|
-
const name = Ti.App.Properties.getString('name_preference');
|
|
184
|
-
const enabled = Ti.App.Properties.getBool('enabled_preference');
|
|
185
|
-
```
|
|
186
|
-
|
|
187
|
-
## 5. Quick Actions and 3D Touch
|
|
188
|
-
|
|
189
|
-
### Static Quick Actions (via tiapp.xml)
|
|
190
|
-
|
|
191
|
-
Static shortcuts are defined in `tiapp.xml` and available immediately after install.
|
|
192
|
-
|
|
193
|
-
- Required keys: `UIApplicationShortcutItemTitle`, `UIApplicationShortcutItemType`
|
|
194
|
-
- Optional keys: `UIApplicationShortcutItemSubtitle`, `UIApplicationShortcutItemIconType`, `UIApplicationShortcutItemIconFile`, `UIApplicationShortcutItemUserInfo`
|
|
195
|
-
|
|
196
|
-
```xml
|
|
197
|
-
<ios>
|
|
198
|
-
<plist>
|
|
199
|
-
<dict>
|
|
200
|
-
<key>UIApplicationShortcutItems</key>
|
|
201
|
-
<array>
|
|
202
|
-
<dict>
|
|
203
|
-
<key>UIApplicationShortcutItemTitle</key>
|
|
204
|
-
<string>New Message</string>
|
|
205
|
-
<key>UIApplicationShortcutItemType</key>
|
|
206
|
-
<string>com.app.newmessage</string>
|
|
207
|
-
<key>UIApplicationShortcutItemIconType</key>
|
|
208
|
-
<string>UIApplicationShortcutIconTypeCompose</string>
|
|
209
|
-
</dict>
|
|
210
|
-
</array>
|
|
211
|
-
</dict>
|
|
212
|
-
</plist>
|
|
213
|
-
</ios>
|
|
214
|
-
```
|
|
215
|
-
|
|
216
|
-
Quick action titles and subtitles can be localized using `i18n/LANG/app.xml` (not `strings.xml`). Use the localized key as the value in `tiapp.xml`.
|
|
217
|
-
|
|
218
|
-
To use custom images for quick action icons, enable app thinning in `tiapp.xml` with `<use-app-thinning>true</use-app-thinning>` inside the `<ios>` element.
|
|
219
|
-
|
|
220
|
-
### Dynamic Quick Actions
|
|
221
|
-
|
|
222
|
-
```javascript
|
|
223
|
-
if (Ti.UI.iOS.forceTouchSupported) {
|
|
224
|
-
const appShortcuts = Ti.UI.iOS.createApplicationShortcuts();
|
|
225
|
-
|
|
226
|
-
appShortcuts.addDynamicShortcut({
|
|
227
|
-
itemtype: 'com.myapp.share',
|
|
228
|
-
title: 'Share Photo',
|
|
229
|
-
subtitle: 'Share last photo',
|
|
230
|
-
icon: Ti.UI.iOS.SHORTCUT_ICON_TYPE_SHARE,
|
|
231
|
-
userInfo: {
|
|
232
|
-
action: 'share_photo',
|
|
233
|
-
photoId: '123'
|
|
234
|
-
}
|
|
235
|
-
});
|
|
236
|
-
|
|
237
|
-
// Remove specific shortcut
|
|
238
|
-
appShortcuts.removeDynamicShortcut('com.myapp.share');
|
|
239
|
-
|
|
240
|
-
// Remove all dynamic shortcuts
|
|
241
|
-
appShortcuts.removeAllDynamicShortcuts();
|
|
242
|
-
}
|
|
243
|
-
```
|
|
244
|
-
|
|
245
|
-
### Handle quick actions
|
|
246
|
-
|
|
247
|
-
```javascript
|
|
248
|
-
Ti.App.iOS.addEventListener('shortcutitemclick', (e) => {
|
|
249
|
-
Ti.API.info(`Shortcut clicked: ${e.itemtype}`);
|
|
250
|
-
|
|
251
|
-
switch (e.itemtype) {
|
|
252
|
-
case 'com.myapp.add':
|
|
253
|
-
addNewItem();
|
|
254
|
-
break;
|
|
255
|
-
case 'com.myapp.recent':
|
|
256
|
-
openRecent();
|
|
257
|
-
break;
|
|
258
|
-
case 'com.myapp.share':
|
|
259
|
-
sharePhoto(e.userInfo.photoId);
|
|
260
|
-
break;
|
|
261
|
-
}
|
|
262
|
-
});
|
|
263
|
-
```
|
|
264
|
-
|
|
265
|
-
### Peek and pop
|
|
266
|
-
|
|
267
|
-
Peek shows a preview, Pop opens the full view.
|
|
268
|
-
|
|
269
|
-
#### Enable peek and pop
|
|
270
|
-
|
|
271
|
-
```javascript
|
|
272
|
-
if (Ti.UI.iOS.forceTouchSupported) {
|
|
273
|
-
|
|
274
|
-
const preview = Alloy.createController('preview').getView();
|
|
275
|
-
const detail = Alloy.createController('detail').getView();
|
|
276
|
-
|
|
277
|
-
const shareAction = Ti.UI.iOS.createPreviewAction({
|
|
278
|
-
title: 'Share',
|
|
279
|
-
style: Ti.UI.iOS.PREVIEW_ACTION_STYLE_DEFAULT
|
|
280
|
-
});
|
|
281
|
-
|
|
282
|
-
shareAction.addEventListener('click', () => {
|
|
283
|
-
// Handle share action
|
|
284
|
-
});
|
|
285
|
-
|
|
286
|
-
const previewContext = Ti.UI.iOS.createPreviewContext({
|
|
287
|
-
preview: preview,
|
|
288
|
-
contentHeight: 400,
|
|
289
|
-
actions: [shareAction]
|
|
290
|
-
});
|
|
291
|
-
|
|
292
|
-
previewContext.addEventListener('peek', () => {
|
|
293
|
-
Ti.API.info('User started peeking');
|
|
294
|
-
});
|
|
295
|
-
|
|
296
|
-
previewContext.addEventListener('pop', () => {
|
|
297
|
-
Ti.API.info('User popped to full view');
|
|
298
|
-
detail.open();
|
|
299
|
-
});
|
|
300
|
-
|
|
301
|
-
// Attach to view
|
|
302
|
-
$.peekView.previewContext = previewContext;
|
|
303
|
-
}
|
|
304
|
-
```
|
|
305
|
-
|
|
306
|
-
#### Preview action styles
|
|
307
|
-
|
|
308
|
-
```javascript
|
|
309
|
-
Ti.UI.iOS.PREVIEW_ACTION_STYLE_DEFAULT
|
|
310
|
-
Ti.UI.iOS.PREVIEW_ACTION_STYLE_SELECTED // Blue background
|
|
311
|
-
Ti.UI.iOS.PREVIEW_ACTION_STYLE_DESTRUCTIVE // Red background
|
|
312
|
-
```
|
|
313
|
-
|
|
314
|
-
#### Peek and pop details
|
|
315
|
-
|
|
316
|
-
- Use `contentHeight` on the preview context to control preview height (for example `contentHeight: 400`).
|
|
317
|
-
- Use `Ti.UI.iOS.createPreviewActionGroup()` to group related preview actions into a submenu:
|
|
318
|
-
|
|
319
|
-
```javascript
|
|
320
|
-
const subAction1 = Ti.UI.iOS.createPreviewAction({ title: 'Copy', style: Ti.UI.iOS.PREVIEW_ACTION_STYLE_DEFAULT });
|
|
321
|
-
const subAction2 = Ti.UI.iOS.createPreviewAction({ title: 'Move', style: Ti.UI.iOS.PREVIEW_ACTION_STYLE_DEFAULT });
|
|
322
|
-
|
|
323
|
-
const actionGroup = Ti.UI.iOS.createPreviewActionGroup({
|
|
324
|
-
title: 'Organize',
|
|
325
|
-
style: Ti.UI.iOS.PREVIEW_ACTION_STYLE_DEFAULT,
|
|
326
|
-
actions: [subAction1, subAction2]
|
|
327
|
-
});
|
|
328
|
-
```
|
|
329
|
-
|
|
330
|
-
Important: 3D Touch features (peek and pop, quick actions with force) can only be tested on physical devices with 3D Touch hardware. The iOS Simulator does not support force touch.
|
|
331
|
-
|
|
332
|
-
## 6. Navigation bar (iOS)
|
|
333
|
-
|
|
334
|
-
### NavigationWindow
|
|
335
|
-
|
|
336
|
-
```javascript
|
|
337
|
-
const win1 = Ti.UI.createWindow({
|
|
338
|
-
backgroundColor: 'white',
|
|
339
|
-
title: 'First Window'
|
|
340
|
-
});
|
|
341
|
-
|
|
342
|
-
const navWindow = Ti.UI.createNavigationWindow({
|
|
343
|
-
window: win1
|
|
344
|
-
});
|
|
345
|
-
|
|
346
|
-
// Open second window
|
|
347
|
-
const win2 = Ti.UI.createWindow({
|
|
348
|
-
backgroundColor: 'gray',
|
|
349
|
-
title: 'Second Window'
|
|
350
|
-
});
|
|
351
|
-
|
|
352
|
-
navWindow.openWindow(win2, { animated: true });
|
|
353
|
-
|
|
354
|
-
// Close to go back
|
|
355
|
-
win2.close();
|
|
356
|
-
|
|
357
|
-
// Hide navigation bar
|
|
358
|
-
win1.navBarHidden = true;
|
|
359
|
-
```
|
|
360
|
-
|
|
361
|
-
## Community-Discovered Patterns
|
|
362
|
-
|
|
363
|
-
### Large Titles + ScrollView: required property triad (iOS)
|
|
364
|
-
|
|
365
|
-
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.
|
|
366
|
-
|
|
367
|
-
```javascript
|
|
368
|
-
const win = Ti.UI.createWindow({
|
|
369
|
-
title: 'My Screen',
|
|
370
|
-
largeTitleEnabled: true,
|
|
371
|
-
largeTitleDisplayMode: Ti.UI.iOS.LARGE_TITLE_DISPLAY_MODE_AUTOMATIC,
|
|
372
|
-
extendEdges: [Ti.UI.EXTEND_EDGE_ALL],
|
|
373
|
-
autoAdjustScrollViewInsets: true,
|
|
374
|
-
barColor: '#1e293b',
|
|
375
|
-
backgroundColor: '#0f172a'
|
|
376
|
-
});
|
|
377
|
-
|
|
378
|
-
const scrollView = Ti.UI.createScrollView({
|
|
379
|
-
layout: 'vertical',
|
|
380
|
-
contentWidth: Ti.UI.FILL,
|
|
381
|
-
contentHeight: Ti.UI.SIZE
|
|
382
|
-
});
|
|
383
|
-
|
|
384
|
-
scrollView.add(Ti.UI.createLabel({ text: 'Content here' }));
|
|
385
|
-
win.add(scrollView);
|
|
386
|
-
navWindow.openWindow(win);
|
|
387
|
-
```
|
|
388
|
-
|
|
389
|
-
| Property | Purpose | What breaks without it |
|
|
390
|
-
|---|---|---|
|
|
391
|
-
| `largeTitleEnabled: true` | Large title that collapses on scroll | No large title behavior |
|
|
392
|
-
| `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) |
|
|
393
|
-
| `autoAdjustScrollViewInsets: true` | Automatically adjusts ScrollView insets | Content overlaps behind the nav bar |
|
|
394
|
-
|
|
395
|
-
> **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.
|
|
396
|
-
|
|
397
|
-
`largeTitleDisplayMode` controls collapse behavior:
|
|
398
|
-
- `LARGE_TITLE_DISPLAY_MODE_AUTOMATIC` (default) — inherits from previous window; collapses on scroll
|
|
399
|
-
- `LARGE_TITLE_DISPLAY_MODE_ALWAYS` — title stays large regardless of scroll position
|
|
400
|
-
- `LARGE_TITLE_DISPLAY_MODE_NEVER` — always standard title size
|
|
401
|
-
|
|
402
|
-
#### Works with both NavigationWindow and TabGroup
|
|
403
|
-
|
|
404
|
-
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`.
|
|
405
|
-
|
|
406
|
-
#### Recommended: global defaults
|
|
407
|
-
|
|
408
|
-
Instead of repeating the properties on every Window, set them as global defaults:
|
|
409
|
-
|
|
410
|
-
```javascript
|
|
411
|
-
// app.tss (Alloy)
|
|
412
|
-
'Window[platform=ios]': {
|
|
413
|
-
autoAdjustScrollViewInsets: true,
|
|
414
|
-
extendEdges: [Ti.UI.EXTEND_EDGE_ALL]
|
|
415
|
-
}
|
|
416
|
-
```
|
|
417
|
-
|
|
418
|
-
Then only add `largeTitleEnabled` and `largeTitleDisplayMode` per-window as needed.
|
|
419
|
-
|
|
420
|
-
> **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.
|
|
421
|
-
|
|
422
|
-
See also: [scrolling-views.md](scrolling-views.md) for ScrollView properties and patterns.
|
|
423
|
-
|
|
424
|
-
### Toolbar
|
|
425
|
-
|
|
426
|
-
```javascript
|
|
427
|
-
const flexSpace = Ti.UI.createButton({
|
|
428
|
-
systemButton: Ti.UI.iOS.SystemButton.FLEXIBLE_SPACE
|
|
429
|
-
});
|
|
430
|
-
|
|
431
|
-
const refreshButton = Ti.UI.createButton({
|
|
432
|
-
title: 'Refresh'
|
|
433
|
-
});
|
|
434
|
-
|
|
435
|
-
const toolbar = Ti.UI.createToolbar({
|
|
436
|
-
items: [refreshButton, flexSpace],
|
|
437
|
-
bottom: 0
|
|
438
|
-
});
|
|
439
|
-
|
|
440
|
-
win.add(toolbar);
|
|
441
|
-
```
|
|
442
|
-
|
|
443
|
-
### System buttons
|
|
444
|
-
|
|
445
|
-
```javascript
|
|
446
|
-
Ti.UI.iOS.SystemButton.DONE
|
|
447
|
-
Ti.UI.iOS.SystemButton.CANCEL
|
|
448
|
-
Ti.UI.iOS.SystemButton.EDIT
|
|
449
|
-
Ti.UI.iOS.SystemButton.SAVE
|
|
450
|
-
Ti.UI.iOS.SystemButton.ADD
|
|
451
|
-
Ti.UI.iOS.SystemButton.FLEXIBLE_SPACE
|
|
452
|
-
Ti.UI.iOS.SystemButton.FIXED_SPACE
|
|
453
|
-
// ... and more
|
|
454
|
-
```
|
|
455
|
-
|
|
456
|
-
## 7. Tab bar
|
|
457
|
-
|
|
458
|
-
### Create a tab bar
|
|
459
|
-
|
|
460
|
-
```javascript
|
|
461
|
-
const tabGroup = Ti.UI.createTabGroup();
|
|
462
|
-
|
|
463
|
-
const tab1 = Ti.UI.createTab({
|
|
464
|
-
icon: 'home.png',
|
|
465
|
-
title: 'Home',
|
|
466
|
-
window: Ti.UI.createWindow({ backgroundColor: 'white' })
|
|
467
|
-
});
|
|
468
|
-
|
|
469
|
-
const tab2 = Ti.UI.createTab({
|
|
470
|
-
icon: 'settings.png',
|
|
471
|
-
title: 'Settings',
|
|
472
|
-
window: Ti.UI.createWindow({ backgroundColor: 'gray' })
|
|
473
|
-
});
|
|
474
|
-
|
|
475
|
-
tabGroup.addTab(tab1);
|
|
476
|
-
tabGroup.addTab(tab2);
|
|
477
|
-
|
|
478
|
-
tabGroup.open();
|
|
479
|
-
```
|
|
480
|
-
|
|
481
|
-
### Tab bar customization (iOS)
|
|
482
|
-
|
|
483
|
-
```javascript
|
|
484
|
-
tabGroup.setActiveTabIconColor('blue');
|
|
485
|
-
tabGroup.setActiveTabColor('#f0f0f0');
|
|
486
|
-
|
|
487
|
-
// Hide tab bar on specific window
|
|
488
|
-
win1.tabBarHidden = true;
|
|
489
|
-
|
|
490
|
-
// Set tab bar style (deprecated in iOS 13+)
|
|
491
|
-
tabGroup.tabsStyle = Ti.UI.iOS.TABS_STYLE_BOTTOM;
|
|
492
|
-
```
|
|
493
|
-
|
|
494
|
-
## 8. Activity indicator
|
|
495
|
-
|
|
496
|
-
```javascript
|
|
497
|
-
const activityIndicator = Ti.UI.createActivityIndicator({
|
|
498
|
-
message: 'Loading...',
|
|
499
|
-
color: 'white',
|
|
500
|
-
backgroundColor: '#333',
|
|
501
|
-
font: { fontSize: 16, fontWeight: 'bold' }
|
|
502
|
-
});
|
|
503
|
-
|
|
504
|
-
activityIndicator.show();
|
|
505
|
-
|
|
506
|
-
// Later
|
|
507
|
-
activityIndicator.hide();
|
|
508
|
-
```
|
|
509
|
-
|
|
510
|
-
### iOS-specific location
|
|
511
|
-
|
|
512
|
-
```javascript
|
|
513
|
-
const activityIndicator = Ti.UI.createActivityIndicator({
|
|
514
|
-
message: 'Loading...',
|
|
515
|
-
location: Ti.UI.iOS.ACTIVITY_INDICATOR_DIALOG,
|
|
516
|
-
opacity: 0.8
|
|
517
|
-
});
|
|
518
|
-
```
|
|
519
|
-
|
|
520
|
-
## 9. Platform best practices
|
|
521
|
-
|
|
522
|
-
### Follow iOS Human Interface Guidelines
|
|
523
|
-
|
|
524
|
-
- Use NavigationWindow for hierarchical navigation
|
|
525
|
-
- Use Tab Bar for top-level categories
|
|
526
|
-
- Present modal views for focused tasks
|
|
527
|
-
- Use Popovers for auxiliary content (iPad)
|
|
528
|
-
- Respect 3D Touch conventions
|
|
529
|
-
|
|
530
|
-
### iOS-specific patterns
|
|
531
|
-
|
|
532
|
-
```javascript
|
|
533
|
-
// Use system buttons for standard actions
|
|
534
|
-
const doneButton = Ti.UI.createButton({
|
|
535
|
-
systemButton: Ti.UI.iOS.SystemButton.DONE
|
|
536
|
-
});
|
|
537
|
-
|
|
538
|
-
// Use NavigationWindow animations
|
|
539
|
-
navWindow.openWindow(win2, {
|
|
540
|
-
animated: true,
|
|
541
|
-
transition: Ti.UI.iOS.NavigationWindowTransitionStyle.NONE
|
|
542
|
-
});
|
|
543
|
-
|
|
544
|
-
// Respect safe area (iPhone X+)
|
|
545
|
-
const view = Ti.UI.createView({
|
|
546
|
-
top: Ti.Platform.displayCaps.platformHeight > 800 ? 44 : 20 // Account for notch
|
|
547
|
-
});
|
|
548
|
-
```
|
|
549
|
-
|
|
550
|
-
## 10. Common issues
|
|
551
|
-
|
|
552
|
-
### Settings not appearing
|
|
553
|
-
|
|
554
|
-
Problem: Settings are not visible in the Settings app.
|
|
555
|
-
|
|
556
|
-
Solutions:
|
|
557
|
-
1. Clean and rebuild the project
|
|
558
|
-
2. Check plist syntax
|
|
559
|
-
3. Ensure Settings.bundle is in `platform/iphone/`
|
|
560
|
-
4. Kill and relaunch the Settings app
|
|
561
|
-
|
|
562
|
-
### 3D Touch not working
|
|
563
|
-
|
|
564
|
-
Problem: 3D Touch features do not respond.
|
|
565
|
-
|
|
566
|
-
Solutions:
|
|
567
|
-
1. Test on a physical device with 3D Touch hardware
|
|
568
|
-
2. Check `Ti.UI.iOS.forceTouchSupported` before using
|
|
569
|
-
3. Ensure iOS 9 or later
|
|
570
|
-
4. Verify `previewContext` is properly attached
|
|
571
|
-
|
|
572
|
-
### SplitWindow issues
|
|
573
|
-
|
|
574
|
-
Problem: Master view is not visible in portrait.
|
|
575
|
-
|
|
576
|
-
Solution: This is default behavior. Use `showMasterViewInPopover()` or handle it via NavigationWindow.
|