@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.
- package/AGENTS-TEMPLATE.md +173 -0
- package/README.md +867 -0
- package/agents/ti-researcher.md +108 -0
- package/bin/titools.js +53 -0
- package/lib/commands/agents.js +126 -0
- package/lib/commands/install.js +188 -0
- package/lib/commands/uninstall.js +215 -0
- package/lib/commands/update.js +159 -0
- package/lib/config.js +119 -0
- package/lib/downloader.js +153 -0
- package/lib/installer.js +253 -0
- package/lib/platform.js +108 -0
- package/lib/symlink.js +142 -0
- package/lib/utils.js +270 -0
- package/package.json +67 -0
- package/skills/alloy-expert/SKILL.md +247 -0
- package/skills/alloy-expert/assets/ControllerAutoCleanup.js +182 -0
- package/skills/alloy-expert/references/alloy-structure.md +381 -0
- package/skills/alloy-expert/references/anti-patterns.md +133 -0
- package/skills/alloy-expert/references/code-conventions.md +469 -0
- package/skills/alloy-expert/references/contracts.md +280 -0
- package/skills/alloy-expert/references/controller-patterns.md +520 -0
- package/skills/alloy-expert/references/error-handling.md +484 -0
- package/skills/alloy-expert/references/examples.md +735 -0
- package/skills/alloy-expert/references/migration-patterns.md +298 -0
- package/skills/alloy-expert/references/patterns.md +448 -0
- package/skills/alloy-expert/references/performance-patterns.md +855 -0
- package/skills/alloy-expert/references/security-patterns.md +847 -0
- package/skills/alloy-expert/references/state-management.md +779 -0
- package/skills/alloy-expert/references/testing.md +872 -0
- package/skills/alloy-guides/SKILL.md +214 -0
- package/skills/alloy-guides/references/CLI_TASKS.md +243 -0
- package/skills/alloy-guides/references/CONCEPTS.md +191 -0
- package/skills/alloy-guides/references/CONTROLLERS.md +298 -0
- package/skills/alloy-guides/references/MODELS.md +1028 -0
- package/skills/alloy-guides/references/PURGETSS.md +56 -0
- package/skills/alloy-guides/references/VIEWS_DYNAMIC.md +242 -0
- package/skills/alloy-guides/references/VIEWS_STYLES.md +388 -0
- package/skills/alloy-guides/references/VIEWS_WITHOUT_CONTROLLERS.md +109 -0
- package/skills/alloy-guides/references/VIEWS_XML.md +558 -0
- package/skills/alloy-guides/references/WIDGETS.md +176 -0
- package/skills/alloy-howtos/SKILL.md +203 -0
- package/skills/alloy-howtos/references/best_practices.md +138 -0
- package/skills/alloy-howtos/references/cli_reference.md +253 -0
- package/skills/alloy-howtos/references/config_files.md +87 -0
- package/skills/alloy-howtos/references/custom_tags.md +147 -0
- package/skills/alloy-howtos/references/debugging_troubleshooting.md +101 -0
- package/skills/alloy-howtos/references/samples.md +167 -0
- package/skills/purgetss/SKILL.md +442 -0
- package/skills/purgetss/assets/purgetss.config.cjs +17 -0
- package/skills/purgetss/references/EXAMPLES.md +247 -0
- package/skills/purgetss/references/animation-system.md +1294 -0
- package/skills/purgetss/references/apply-directive.md +375 -0
- package/skills/purgetss/references/arbitrary-values.md +612 -0
- package/skills/purgetss/references/class-index.md +1350 -0
- package/skills/purgetss/references/cli-commands.md +948 -0
- package/skills/purgetss/references/configurable-properties.md +654 -0
- package/skills/purgetss/references/custom-rules.md +161 -0
- package/skills/purgetss/references/customization-deep-dive.md +722 -0
- package/skills/purgetss/references/dynamic-component-creation.md +489 -0
- package/skills/purgetss/references/grid-layout.md +455 -0
- package/skills/purgetss/references/icon-fonts.md +609 -0
- package/skills/purgetss/references/installation-setup.md +366 -0
- package/skills/purgetss/references/opacity-modifier.md +291 -0
- package/skills/purgetss/references/platform-modifiers.md +479 -0
- package/skills/purgetss/references/smart-mappings.md +42 -0
- package/skills/purgetss/references/titanium-resets.md +359 -0
- package/skills/purgetss/references/ui-ux-design.md +1526 -0
- package/skills/ti-guides/SKILL.md +94 -0
- package/skills/ti-guides/references/advanced-data-and-images.md +19 -0
- package/skills/ti-guides/references/alloy-cli-advanced.md +84 -0
- package/skills/ti-guides/references/alloy-data-mastery.md +29 -0
- package/skills/ti-guides/references/alloy-widgets-and-themes.md +19 -0
- package/skills/ti-guides/references/android-manifest.md +97 -0
- package/skills/ti-guides/references/app-distribution.md +258 -0
- package/skills/ti-guides/references/application-frameworks.md +377 -0
- package/skills/ti-guides/references/cli-reference.md +402 -0
- package/skills/ti-guides/references/coding-best-practices.md +102 -0
- package/skills/ti-guides/references/commonjs-advanced.md +134 -0
- package/skills/ti-guides/references/hello-world.md +100 -0
- package/skills/ti-guides/references/hyperloop-native-access.md +62 -0
- package/skills/ti-guides/references/javascript-primer.md +411 -0
- package/skills/ti-guides/references/reserved-words.md +36 -0
- package/skills/ti-guides/references/resources.md +183 -0
- package/skills/ti-guides/references/style-and-conventions.md +48 -0
- package/skills/ti-guides/references/tiapp-config.md +609 -0
- package/skills/ti-howtos/SKILL.md +174 -0
- package/skills/ti-howtos/references/android-platform-deep-dives.md +658 -0
- package/skills/ti-howtos/references/automation-fastlane-appium.md +95 -0
- package/skills/ti-howtos/references/buffer-codec-streams.md +140 -0
- package/skills/ti-howtos/references/cross-platform-development.md +348 -0
- package/skills/ti-howtos/references/debugging-profiling.md +543 -0
- package/skills/ti-howtos/references/extending-titanium.md +723 -0
- package/skills/ti-howtos/references/google-maps-v2.md +169 -0
- package/skills/ti-howtos/references/ios-map-kit.md +143 -0
- package/skills/ti-howtos/references/ios-platform-deep-dives.md +783 -0
- package/skills/ti-howtos/references/local-data-sources.md +301 -0
- package/skills/ti-howtos/references/location-and-maps.md +252 -0
- package/skills/ti-howtos/references/media-apis.md +210 -0
- package/skills/ti-howtos/references/notification-services.md +599 -0
- package/skills/ti-howtos/references/remote-data-sources.md +349 -0
- package/skills/ti-howtos/references/tutorials.md +502 -0
- package/skills/ti-howtos/references/using-modules.md +237 -0
- package/skills/ti-howtos/references/web-content-integration.md +307 -0
- package/skills/ti-howtos/references/webpack-build-pipeline.md +78 -0
- package/skills/ti-ui/SKILL.md +179 -0
- package/skills/ti-ui/references/accessibility-deep-dive.md +242 -0
- package/skills/ti-ui/references/animation-and-matrices.md +599 -0
- package/skills/ti-ui/references/application-structures.md +655 -0
- package/skills/ti-ui/references/custom-fonts-styling.md +579 -0
- package/skills/ti-ui/references/event-handling.md +393 -0
- package/skills/ti-ui/references/gestures.md +473 -0
- package/skills/ti-ui/references/icons-and-splash-screens.md +409 -0
- package/skills/ti-ui/references/layouts-and-positioning.md +462 -0
- package/skills/ti-ui/references/listviews-and-performance.md +619 -0
- package/skills/ti-ui/references/orientation.md +362 -0
- package/skills/ti-ui/references/platform-ui-android.md +635 -0
- package/skills/ti-ui/references/platform-ui-ios.md +469 -0
- package/skills/ti-ui/references/scrolling-views.md +252 -0
- package/skills/ti-ui/references/tableviews.md +568 -0
|
@@ -0,0 +1,473 @@
|
|
|
1
|
+
# Gestures
|
|
2
|
+
|
|
3
|
+
## Table of Contents
|
|
4
|
+
|
|
5
|
+
- [Gestures](#gestures)
|
|
6
|
+
- [Table of Contents](#table-of-contents)
|
|
7
|
+
- [1. Overview](#1-overview)
|
|
8
|
+
- [2. Touch Events](#2-touch-events)
|
|
9
|
+
- [Touch Lifecycle](#touch-lifecycle)
|
|
10
|
+
- [Touch Event Properties](#touch-event-properties)
|
|
11
|
+
- [Android Note](#android-note)
|
|
12
|
+
- [3. Swipe Gesture](#3-swipe-gesture)
|
|
13
|
+
- [Basic Swipe](#basic-swipe)
|
|
14
|
+
- [Swipe Direction Detection](#swipe-direction-detection)
|
|
15
|
+
- [Swipe vs Scroll](#swipe-vs-scroll)
|
|
16
|
+
- [4. Pinch Gesture (iOS Only)](#4-pinch-gesture-ios-only)
|
|
17
|
+
- [Pinch to Zoom](#pinch-to-zoom)
|
|
18
|
+
- [5. Long Press Gesture](#5-long-press-gesture)
|
|
19
|
+
- [Basic Long Press](#basic-long-press)
|
|
20
|
+
- [Long Press Duration](#long-press-duration)
|
|
21
|
+
- [Android Long Press Convention](#android-long-press-convention)
|
|
22
|
+
- [6. Shake Gesture](#6-shake-gesture)
|
|
23
|
+
- [Detecting Shake](#detecting-shake)
|
|
24
|
+
- [Shake Example](#shake-example)
|
|
25
|
+
- [Testing Shake](#testing-shake)
|
|
26
|
+
- [7. Accelerometer as Input](#7-accelerometer-as-input)
|
|
27
|
+
- [Basic Accelerometer](#basic-accelerometer)
|
|
28
|
+
- [Accelerometer Properties](#accelerometer-properties)
|
|
29
|
+
- [Using Accelerometer for Control](#using-accelerometer-for-control)
|
|
30
|
+
- [Smoothing Accelerometer Data](#smoothing-accelerometer-data)
|
|
31
|
+
- [8. Gesture Lifecycle Management](#8-gesture-lifecycle-management)
|
|
32
|
+
- [Battery Considerations](#battery-considerations)
|
|
33
|
+
- [9. Platform-Specific Considerations](#9-platform-specific-considerations)
|
|
34
|
+
- [iOS](#ios)
|
|
35
|
+
- [Android](#android)
|
|
36
|
+
- [10. Best Practices](#10-best-practices)
|
|
37
|
+
- [11. Combining Gestures](#11-combining-gestures)
|
|
38
|
+
- [Multiple Gesture Types](#multiple-gesture-types)
|
|
39
|
+
- [Preventing Gesture Conflicts](#preventing-gesture-conflicts)
|
|
40
|
+
|
|
41
|
+
---
|
|
42
|
+
|
|
43
|
+
## 1. Overview
|
|
44
|
+
|
|
45
|
+
Titanium supports various gestures beyond simple taps:
|
|
46
|
+
- **Touch Events** - Low-level touch tracking
|
|
47
|
+
- **Swipe** - Left/right drag gestures
|
|
48
|
+
- **Pinch** - Zoom gestures (iOS only)
|
|
49
|
+
- **Long Press** - Extended press gesture
|
|
50
|
+
- **Shake** - Device shake detection
|
|
51
|
+
- **Accelerometer** - Device orientation/movement
|
|
52
|
+
|
|
53
|
+
## 2. Touch Events
|
|
54
|
+
|
|
55
|
+
### Touch Lifecycle
|
|
56
|
+
|
|
57
|
+
```javascript
|
|
58
|
+
const view = Ti.UI.createView({
|
|
59
|
+
backgroundColor: 'blue',
|
|
60
|
+
width: 200, height: 200
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
view.addEventListener('touchstart', (e) => {
|
|
64
|
+
Ti.API.info(`Touch started at: ${e.x}, ${e.y}`);
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
view.addEventListener('touchmove', (e) => {
|
|
68
|
+
Ti.API.info(`Moving to: ${e.x}, ${e.y}`);
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
view.addEventListener('touchend', (e) => {
|
|
72
|
+
Ti.API.info(`Touch ended at: ${e.x}, ${e.y}`);
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
view.addEventListener('touchcancel', (e) => {
|
|
76
|
+
Ti.API.info('Touch cancelled (incoming call, etc.)');
|
|
77
|
+
});
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
### Touch Event Properties
|
|
81
|
+
|
|
82
|
+
| Property | Description |
|
|
83
|
+
| ------------- | ---------------------------------------- |
|
|
84
|
+
| `x` | X coordinate in view's coordinate system |
|
|
85
|
+
| `y` | Y coordinate in view's coordinate system |
|
|
86
|
+
| `globalPoint` | Screen coordinates (iOS only) |
|
|
87
|
+
|
|
88
|
+
### Android Note
|
|
89
|
+
|
|
90
|
+
On Android, `longpress` and `swipe` cancel touch events - `touchend` may not fire after `touchstart`.
|
|
91
|
+
|
|
92
|
+
## 3. Swipe Gesture
|
|
93
|
+
|
|
94
|
+
### Basic Swipe
|
|
95
|
+
|
|
96
|
+
```javascript
|
|
97
|
+
const view = Ti.UI.createView({
|
|
98
|
+
backgroundColor: 'yellow',
|
|
99
|
+
width: Ti.UI.FILL,
|
|
100
|
+
height: 100
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
view.addEventListener('swipe', (e) => {
|
|
104
|
+
Ti.API.info(`Swiped direction: ${e.direction}`);
|
|
105
|
+
// e.direction can be: 'left', 'right', 'up', 'down'
|
|
106
|
+
});
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
### Swipe Direction Detection
|
|
110
|
+
|
|
111
|
+
```javascript
|
|
112
|
+
view.addEventListener('swipe', (e) => {
|
|
113
|
+
switch(e.direction) {
|
|
114
|
+
case 'left':
|
|
115
|
+
Ti.API.info('Swiped left');
|
|
116
|
+
showPreviousPage();
|
|
117
|
+
break;
|
|
118
|
+
case 'right':
|
|
119
|
+
Ti.API.info('Swiped right');
|
|
120
|
+
showNextPage();
|
|
121
|
+
break;
|
|
122
|
+
case 'up':
|
|
123
|
+
Ti.API.info('Swiped up');
|
|
124
|
+
break;
|
|
125
|
+
case 'down':
|
|
126
|
+
Ti.API.info('Swiped down');
|
|
127
|
+
break;
|
|
128
|
+
}
|
|
129
|
+
});
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
### Swipe vs Scroll
|
|
133
|
+
|
|
134
|
+
- **Swipe**: Quick flick gesture (left/right mainly)
|
|
135
|
+
- **Scroll**: Sustained drag gesture (up/down mainly)
|
|
136
|
+
|
|
137
|
+
## 4. Pinch Gesture (iOS Only)
|
|
138
|
+
|
|
139
|
+
```javascript
|
|
140
|
+
const view = Ti.UI.createView({
|
|
141
|
+
backgroundColor: 'green',
|
|
142
|
+
width: 300, height: 300
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
view.addEventListener('pinch', (e) => {
|
|
146
|
+
Ti.API.info(`Pinch scale: ${e.scale}`);
|
|
147
|
+
// e.scale < 1.0 = pinch together
|
|
148
|
+
// e.scale > 1.0 = pinch apart
|
|
149
|
+
});
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
### Pinch to Zoom
|
|
153
|
+
|
|
154
|
+
```javascript
|
|
155
|
+
const imageView = Ti.UI.createImageView({
|
|
156
|
+
image: 'photo.jpg',
|
|
157
|
+
width: 300, height: 300
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
let currentScale = 1.0;
|
|
161
|
+
|
|
162
|
+
imageView.addEventListener('pinch', (e) => {
|
|
163
|
+
currentScale = e.scale;
|
|
164
|
+
imageView.transform = Ti.UI.create2DMatrix().scale(currentScale);
|
|
165
|
+
});
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
## 5. Long Press Gesture
|
|
169
|
+
|
|
170
|
+
### Basic Long Press
|
|
171
|
+
|
|
172
|
+
```javascript
|
|
173
|
+
const view = Ti.UI.createView({
|
|
174
|
+
backgroundColor: 'orange',
|
|
175
|
+
width: 200, height: 200
|
|
176
|
+
});
|
|
177
|
+
|
|
178
|
+
view.addEventListener('longpress', (e) => {
|
|
179
|
+
Ti.API.info(`Long press at: ${e.x}, ${e.y}`);
|
|
180
|
+
showContextMenu(e);
|
|
181
|
+
});
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
### Long Press Duration
|
|
185
|
+
|
|
186
|
+
Default long press duration varies by platform. Custom handling:
|
|
187
|
+
|
|
188
|
+
```javascript
|
|
189
|
+
let pressTimer = null;
|
|
190
|
+
const PRESS_DURATION = 1000; // 1 second
|
|
191
|
+
|
|
192
|
+
view.addEventListener('touchstart', (e) => {
|
|
193
|
+
pressTimer = setTimeout(() => {
|
|
194
|
+
showContextMenu(e);
|
|
195
|
+
}, PRESS_DURATION);
|
|
196
|
+
});
|
|
197
|
+
|
|
198
|
+
view.addEventListener('touchend', () => {
|
|
199
|
+
if (pressTimer) {
|
|
200
|
+
clearTimeout(pressTimer);
|
|
201
|
+
pressTimer = null;
|
|
202
|
+
}
|
|
203
|
+
});
|
|
204
|
+
|
|
205
|
+
view.addEventListener('touchmove', () => {
|
|
206
|
+
// Cancel long press if moved significantly
|
|
207
|
+
if (pressTimer) {
|
|
208
|
+
clearTimeout(pressTimer);
|
|
209
|
+
pressTimer = null;
|
|
210
|
+
}
|
|
211
|
+
});
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
### Android Long Press Convention
|
|
215
|
+
|
|
216
|
+
On Android, long press typically shows context menu:
|
|
217
|
+
|
|
218
|
+
```javascript
|
|
219
|
+
view.addEventListener('longpress', (e) => {
|
|
220
|
+
const dialog = Ti.UI.createAlertDialog({
|
|
221
|
+
title: 'Options',
|
|
222
|
+
message: 'What would you like to do?',
|
|
223
|
+
buttonNames: ['Edit', 'Delete', 'Share', 'Cancel']
|
|
224
|
+
});
|
|
225
|
+
dialog.addEventListener('click', (e) => {
|
|
226
|
+
switch(e.index) {
|
|
227
|
+
case 0: editItem(); break;
|
|
228
|
+
case 1: deleteItem(); break;
|
|
229
|
+
case 2: shareItem(); break;
|
|
230
|
+
}
|
|
231
|
+
});
|
|
232
|
+
dialog.show();
|
|
233
|
+
});
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
## 6. Shake Gesture
|
|
237
|
+
|
|
238
|
+
### Detecting Shake
|
|
239
|
+
|
|
240
|
+
```javascript
|
|
241
|
+
Ti.Gesture.addEventListener('shake', (e) => {
|
|
242
|
+
Ti.API.info(`Device shaken at ${e.timestamp}`);
|
|
243
|
+
|
|
244
|
+
// Refresh content, undo action, etc.
|
|
245
|
+
refreshData();
|
|
246
|
+
});
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
### Shake Example
|
|
250
|
+
|
|
251
|
+
```javascript
|
|
252
|
+
// Use shake to refresh data
|
|
253
|
+
const scrollView = Ti.UI.createScrollView({
|
|
254
|
+
contentHeight: Ti.UI.SIZE
|
|
255
|
+
});
|
|
256
|
+
|
|
257
|
+
Ti.Gesture.addEventListener('shake', () => {
|
|
258
|
+
// Refresh data
|
|
259
|
+
loadDataFromServer();
|
|
260
|
+
});
|
|
261
|
+
|
|
262
|
+
function loadDataFromServer() {
|
|
263
|
+
// ...
|
|
264
|
+
Ti.API.info('Data refreshed due to shake');
|
|
265
|
+
}
|
|
266
|
+
```
|
|
267
|
+
|
|
268
|
+
### Testing Shake
|
|
269
|
+
|
|
270
|
+
- **iOS Simulator**: Hardware > Shake Device
|
|
271
|
+
- **Android Emulator**: Not supported - test on physical device
|
|
272
|
+
- **Physical Device**: Just shake the device
|
|
273
|
+
|
|
274
|
+
## 7. Accelerometer as Input
|
|
275
|
+
|
|
276
|
+
### Basic Accelerometer
|
|
277
|
+
|
|
278
|
+
```javascript
|
|
279
|
+
const labelX = Ti.UI.createLabel({ text: 'X: 0' });
|
|
280
|
+
const labelY = Ti.UI.createLabel({ text: 'Y: 0', top: 30 });
|
|
281
|
+
const labelZ = Ti.UI.createLabel({ text: 'Z: 0', top: 60 });
|
|
282
|
+
|
|
283
|
+
Ti.Accelerometer.addEventListener('update', (e) => {
|
|
284
|
+
labelX.text = `X: ${e.x.toFixed(2)}`;
|
|
285
|
+
labelY.text = `Y: ${e.y.toFixed(2)}`;
|
|
286
|
+
labelZ.text = `Z: ${e.z.toFixed(2)}`;
|
|
287
|
+
});
|
|
288
|
+
```
|
|
289
|
+
|
|
290
|
+
### Accelerometer Properties
|
|
291
|
+
|
|
292
|
+
| Property | Description | Range |
|
|
293
|
+
| ----------- | ------------------- | -------------------- |
|
|
294
|
+
| `x` | X-axis acceleration | G-force (±9.81 m/s²) |
|
|
295
|
+
| `y` | Y-axis acceleration | G-force |
|
|
296
|
+
| `z` | Z-axis acceleration | G-force |
|
|
297
|
+
| `timestamp` | When event occurred | Timestamp |
|
|
298
|
+
|
|
299
|
+
### Using Accelerometer for Control
|
|
300
|
+
|
|
301
|
+
```javascript
|
|
302
|
+
const sensitivity = 2.0;
|
|
303
|
+
let lastX = 0, lastY = 0;
|
|
304
|
+
|
|
305
|
+
Ti.Accelerometer.addEventListener('update', (e) => {
|
|
306
|
+
const deltaX = e.x - lastX;
|
|
307
|
+
const deltaY = e.y - lastY;
|
|
308
|
+
|
|
309
|
+
if (Math.abs(deltaX) > sensitivity) {
|
|
310
|
+
if (deltaX > 0) {
|
|
311
|
+
moveRight();
|
|
312
|
+
} else {
|
|
313
|
+
moveLeft();
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
lastX = e.x;
|
|
318
|
+
lastY = e.y;
|
|
319
|
+
});
|
|
320
|
+
```
|
|
321
|
+
|
|
322
|
+
### Smoothing Accelerometer Data
|
|
323
|
+
|
|
324
|
+
Accelerometer data is very sensitive. Apply smoothing:
|
|
325
|
+
|
|
326
|
+
```javascript
|
|
327
|
+
let samples = [];
|
|
328
|
+
const SAMPLE_SIZE = 10;
|
|
329
|
+
|
|
330
|
+
Ti.Accelerometer.addEventListener('update', (e) => {
|
|
331
|
+
samples.push({ x: e.x, y: e.y, z: e.z });
|
|
332
|
+
|
|
333
|
+
if (samples.length >= SAMPLE_SIZE) {
|
|
334
|
+
// Calculate average
|
|
335
|
+
const avgX = samples.reduce((sum, s) => sum + s.x, 0) / samples.length;
|
|
336
|
+
const avgY = samples.reduce((sum, s) => sum + s.y, 0) / samples.length;
|
|
337
|
+
const avgZ = samples.reduce((sum, s) => sum + s.z, 0) / samples.length;
|
|
338
|
+
|
|
339
|
+
// Use averaged values
|
|
340
|
+
updatePosition(avgX, avgY, avgZ);
|
|
341
|
+
|
|
342
|
+
// Clear samples
|
|
343
|
+
samples = [];
|
|
344
|
+
}
|
|
345
|
+
});
|
|
346
|
+
```
|
|
347
|
+
|
|
348
|
+
## 8. Gesture Lifecycle Management
|
|
349
|
+
|
|
350
|
+
### Battery Considerations
|
|
351
|
+
|
|
352
|
+
Global gesture events (`Ti.Gesture`, `Ti.Accelerometer`) keep hardware powered and drain battery.
|
|
353
|
+
|
|
354
|
+
**Always remove listeners when not needed:**
|
|
355
|
+
|
|
356
|
+
```javascript
|
|
357
|
+
let accelerometerAdded = false;
|
|
358
|
+
const accelerometerCallback = (e) => {
|
|
359
|
+
// Process accelerometer data
|
|
360
|
+
};
|
|
361
|
+
|
|
362
|
+
function startTracking() {
|
|
363
|
+
if (!accelerometerAdded) {
|
|
364
|
+
Ti.Accelerometer.addEventListener('update', accelerometerCallback);
|
|
365
|
+
accelerometerAdded = true;
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
function stopTracking() {
|
|
370
|
+
if (accelerometerAdded) {
|
|
371
|
+
Ti.Accelerometer.removeEventListener('update', accelerometerCallback);
|
|
372
|
+
accelerometerAdded = false;
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
// Android: Manage with app lifecycle
|
|
377
|
+
if (Ti.Platform.osname === 'android') {
|
|
378
|
+
Ti.Android.currentActivity.addEventListener('pause', () => {
|
|
379
|
+
stopTracking();
|
|
380
|
+
});
|
|
381
|
+
|
|
382
|
+
Ti.Android.currentActivity.addEventListener('resume', () => {
|
|
383
|
+
startTracking();
|
|
384
|
+
});
|
|
385
|
+
}
|
|
386
|
+
```
|
|
387
|
+
|
|
388
|
+
## 9. Platform-Specific Considerations
|
|
389
|
+
|
|
390
|
+
### iOS
|
|
391
|
+
|
|
392
|
+
- **Pinch gesture** fully supported
|
|
393
|
+
- **Simulator shake**: Hardware > Shake Device
|
|
394
|
+
- **More touch events** supported
|
|
395
|
+
- **Smoother gesture recognition**
|
|
396
|
+
|
|
397
|
+
### Android
|
|
398
|
+
|
|
399
|
+
- **Pinch** limited/experimental support
|
|
400
|
+
- **No simulator shake** - must test on device
|
|
401
|
+
- **Long press** for context menus (standard pattern)
|
|
402
|
+
- **Hardware button events** available
|
|
403
|
+
|
|
404
|
+
## 10. Best Practices
|
|
405
|
+
|
|
406
|
+
1. **Test on physical devices** - Simulators don't support all gestures
|
|
407
|
+
2. **Remove global gesture listeners** when not needed to save battery
|
|
408
|
+
3. **Smooth accelerometer data** - Use averaging/rounding
|
|
409
|
+
4. **Use appropriate gesture for context** - Long press for context menus, swipe for navigation
|
|
410
|
+
5. **Consider accessibility** - Ensure gestures don't conflict with screen readers
|
|
411
|
+
6. **Handle edge cases** - Touch cancel, gesture interruptions
|
|
412
|
+
7. **Provide alternatives** - Not all users can perform all gestures
|
|
413
|
+
|
|
414
|
+
## 11. Combining Gestures
|
|
415
|
+
|
|
416
|
+
### Multiple Gesture Types
|
|
417
|
+
|
|
418
|
+
```javascript
|
|
419
|
+
const view = Ti.UI.createView({
|
|
420
|
+
width: 300, height: 300,
|
|
421
|
+
backgroundColor: 'cyan'
|
|
422
|
+
});
|
|
423
|
+
|
|
424
|
+
// Swipe for navigation
|
|
425
|
+
view.addEventListener('swipe', (e) => {
|
|
426
|
+
if (e.direction === 'left') {
|
|
427
|
+
showPrevious();
|
|
428
|
+
} else if (e.direction === 'right') {
|
|
429
|
+
showNext();
|
|
430
|
+
}
|
|
431
|
+
});
|
|
432
|
+
|
|
433
|
+
// Long press for options
|
|
434
|
+
view.addEventListener('longpress', (e) => {
|
|
435
|
+
showOptions();
|
|
436
|
+
});
|
|
437
|
+
|
|
438
|
+
// Double tap for like
|
|
439
|
+
view.addEventListener('doubletap', (e) => {
|
|
440
|
+
likeContent();
|
|
441
|
+
});
|
|
442
|
+
|
|
443
|
+
// Pinch to zoom (iOS)
|
|
444
|
+
view.addEventListener('pinch', (e) => {
|
|
445
|
+
if (e.scale > 1.0) {
|
|
446
|
+
zoomIn();
|
|
447
|
+
} else {
|
|
448
|
+
zoomOut();
|
|
449
|
+
}
|
|
450
|
+
});
|
|
451
|
+
```
|
|
452
|
+
|
|
453
|
+
### Preventing Gesture Conflicts
|
|
454
|
+
|
|
455
|
+
```javascript
|
|
456
|
+
let touchStartTime = 0;
|
|
457
|
+
|
|
458
|
+
view.addEventListener('touchstart', (e) => {
|
|
459
|
+
touchStartTime = Date.now();
|
|
460
|
+
});
|
|
461
|
+
|
|
462
|
+
view.addEventListener('touchend', (e) => {
|
|
463
|
+
const touchDuration = Date.now() - touchStartTime;
|
|
464
|
+
|
|
465
|
+
if (touchDuration < 200) {
|
|
466
|
+
// Short tap - treat as click
|
|
467
|
+
handleClick();
|
|
468
|
+
} else if (touchDuration > 500) {
|
|
469
|
+
// Long touch - already handled by longpress
|
|
470
|
+
// Ignore
|
|
471
|
+
}
|
|
472
|
+
});
|
|
473
|
+
```
|