react-native-external-keyboard 0.5.6 → 0.6.1-rc
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/README.md +277 -14
- package/android/src/main/java/com/externalkeyboard/delegates/FocusOrderDelegate.java +213 -0
- package/android/src/main/java/com/externalkeyboard/helper/FocusHelper.java +44 -0
- package/android/src/main/java/com/externalkeyboard/helper/Linking/A11yOrderLinking.java +81 -0
- package/android/src/main/java/com/externalkeyboard/helper/Linking/LinkingQueue.java +94 -0
- package/android/src/main/java/com/externalkeyboard/helper/ReactNativeVersionChecker.java +24 -0
- package/android/src/main/java/com/externalkeyboard/services/FocusLinkObserver/FocusLinkObserver.java +131 -0
- package/android/src/main/java/com/externalkeyboard/services/FocusLinkObserver/FocusLinkObserverSingleton.java +20 -0
- package/android/src/main/java/com/externalkeyboard/views/ExternalKeyboardView/ExternalKeyboardView.java +144 -0
- package/android/src/main/java/com/externalkeyboard/views/ExternalKeyboardView/ExternalKeyboardViewManager.java +128 -8
- package/android/src/main/java/com/externalkeyboard/views/KeyboardFocusGroup/KeyboardFocusGroupManager.java +7 -3
- package/android/src/main/java/com/externalkeyboard/views/TextInputFocusWrapper/TextInputFocusWrapper.java +2 -13
- package/android/src/oldarch/ExternalKeyboardViewManagerSpec.java +25 -0
- package/android/src/oldarch/KeyboardFocusGroupManagerSpec.java +8 -1
- package/ios/Delegates/RNCEKVFocusOrderDelegate/RNCEKVFocusOrderDelegate.h +33 -0
- package/ios/Delegates/RNCEKVFocusOrderDelegate/RNCEKVFocusOrderDelegate.mm +577 -0
- package/ios/Delegates/RNCEKVFocusOrderDelegate/RNCEKVFocusOrderProtocol.h +34 -0
- package/ios/Delegates/RNCEKVGroupIdentifierDelegate/RNCEKVGroupIdentifierDelegate.h +1 -0
- package/ios/Delegates/RNCEKVGroupIdentifierDelegate/RNCEKVGroupIdentifierDelegate.mm +9 -0
- package/ios/Helpers/RNCEKVPropHelper/RNCEKVPropHelper.h +22 -0
- package/ios/Helpers/RNCEKVPropHelper/RNCEKVPropHelper.mm +48 -0
- package/ios/Services/RNCEKVFocusLinkObserver.h +27 -0
- package/ios/Services/RNCEKVFocusLinkObserver.mm +101 -0
- package/ios/Services/RNCEKVFocusLinkObserverManager.h +23 -0
- package/ios/Services/RNCEKVFocusLinkObserverManager.mm +30 -0
- package/ios/Services/RNCEKVOrderLinking.h +33 -0
- package/ios/Services/RNCEKVOrderLinking.mm +143 -0
- package/ios/Services/RNCEKVOrderSubscriber.h +24 -0
- package/ios/Services/RNCEKVOrderSubscriber.mm +23 -0
- package/ios/Services/RNCEKVRelashioship.h +28 -0
- package/ios/Services/RNCEKVRelashioship.mm +61 -0
- package/ios/Services/RNCEKVSortedMap.h +22 -0
- package/ios/Services/RNCEKVSortedMap.mm +112 -0
- package/ios/Views/RNCEKVExternalKeyboardView/RNCEKVExternalKeyboardView.h +34 -3
- package/ios/Views/RNCEKVExternalKeyboardView/RNCEKVExternalKeyboardView.mm +214 -54
- package/ios/Views/RNCEKVExternalKeyboardView/RNCEKVExternalKeyboardViewManager.h +9 -0
- package/ios/Views/RNCEKVExternalKeyboardView/RNCEKVExternalKeyboardViewManager.mm +80 -55
- package/ios/Views/RNCEKVKeyboardFocusGroupView/RNCEKVKeyboardFocusGroup.h +2 -0
- package/ios/Views/RNCEKVKeyboardFocusGroupView/RNCEKVKeyboardFocusGroup.mm +161 -3
- package/ios/Views/RNCEKVKeyboardFocusGroupView/RNCEKVKeyboardFocusGroupManager.mm +6 -0
- package/lib/commonjs/components/BaseKeyboardView/BaseKeyboardView.js +56 -3
- package/lib/commonjs/components/BaseKeyboardView/BaseKeyboardView.js.map +1 -1
- package/lib/commonjs/components/KeyboardFocusGroup/KeyboardFocusGroup.android.js +30 -0
- package/lib/commonjs/components/KeyboardFocusGroup/KeyboardFocusGroup.android.js.map +1 -0
- package/lib/commonjs/components/KeyboardFocusGroup/KeyboardFocusGroup.ios.js.map +1 -1
- package/lib/commonjs/components/KeyboardFocusGroup/KeyboardFocusGroup.js.map +1 -1
- package/lib/commonjs/context/OrderFocusContext.js +23 -0
- package/lib/commonjs/context/OrderFocusContext.js.map +1 -0
- package/lib/commonjs/index.js +19 -0
- package/lib/commonjs/index.js.map +1 -1
- package/lib/commonjs/nativeSpec/ExternalKeyboardViewNativeComponent.js.map +1 -1
- package/lib/commonjs/nativeSpec/KeyboardFocusGroupNativeComponent.js.map +1 -1
- package/lib/commonjs/types/BaseKeyboardView.js +12 -0
- package/lib/commonjs/types/BaseKeyboardView.js.map +1 -1
- package/lib/commonjs/utils/withKeyboardFocus.js +25 -1
- package/lib/commonjs/utils/withKeyboardFocus.js.map +1 -1
- package/lib/module/components/BaseKeyboardView/BaseKeyboardView.js +55 -2
- package/lib/module/components/BaseKeyboardView/BaseKeyboardView.js.map +1 -1
- package/lib/module/components/KeyboardFocusGroup/KeyboardFocusGroup.android.js +23 -0
- package/lib/module/components/KeyboardFocusGroup/KeyboardFocusGroup.android.js.map +1 -0
- package/lib/module/components/KeyboardFocusGroup/KeyboardFocusGroup.ios.js.map +1 -1
- package/lib/module/components/KeyboardFocusGroup/KeyboardFocusGroup.js.map +1 -1
- package/lib/module/context/OrderFocusContext.js +14 -0
- package/lib/module/context/OrderFocusContext.js.map +1 -0
- package/lib/module/index.js +1 -0
- package/lib/module/index.js.map +1 -1
- package/lib/module/nativeSpec/ExternalKeyboardViewNativeComponent.js.map +1 -1
- package/lib/module/nativeSpec/KeyboardFocusGroupNativeComponent.js.map +1 -1
- package/lib/module/types/BaseKeyboardView.js +11 -1
- package/lib/module/types/BaseKeyboardView.js.map +1 -1
- package/lib/module/utils/withKeyboardFocus.js +25 -1
- package/lib/module/utils/withKeyboardFocus.js.map +1 -1
- package/lib/typescript/src/components/BaseKeyboardView/BaseKeyboardView.d.ts +1 -1
- package/lib/typescript/src/components/BaseKeyboardView/BaseKeyboardView.d.ts.map +1 -1
- package/lib/typescript/src/components/KeyboardFocusGroup/KeyboardFocusGroup.android.d.ts +24 -0
- package/lib/typescript/src/components/KeyboardFocusGroup/KeyboardFocusGroup.android.d.ts.map +1 -0
- package/lib/typescript/src/components/KeyboardFocusGroup/KeyboardFocusGroup.d.ts +1 -0
- package/lib/typescript/src/components/KeyboardFocusGroup/KeyboardFocusGroup.d.ts.map +1 -1
- package/lib/typescript/src/components/KeyboardFocusGroup/KeyboardFocusGroup.ios.d.ts +2 -0
- package/lib/typescript/src/components/KeyboardFocusGroup/KeyboardFocusGroup.ios.d.ts.map +1 -1
- package/lib/typescript/src/context/OrderFocusContext.d.ts +10 -0
- package/lib/typescript/src/context/OrderFocusContext.d.ts.map +1 -0
- package/lib/typescript/src/index.d.ts +1 -0
- package/lib/typescript/src/index.d.ts.map +1 -1
- package/lib/typescript/src/nativeSpec/ExternalKeyboardViewNativeComponent.d.ts +12 -0
- package/lib/typescript/src/nativeSpec/ExternalKeyboardViewNativeComponent.d.ts.map +1 -1
- package/lib/typescript/src/nativeSpec/KeyboardFocusGroupNativeComponent.d.ts +1 -0
- package/lib/typescript/src/nativeSpec/KeyboardFocusGroupNativeComponent.d.ts.map +1 -1
- package/lib/typescript/src/types/BaseKeyboardView.d.ts +24 -0
- package/lib/typescript/src/types/BaseKeyboardView.d.ts.map +1 -1
- package/lib/typescript/src/utils/withKeyboardFocus.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/components/BaseKeyboardView/BaseKeyboardView.tsx +77 -4
- package/src/components/KeyboardFocusGroup/KeyboardFocusGroup.android.tsx +39 -0
- package/src/components/KeyboardFocusGroup/KeyboardFocusGroup.ios.tsx +1 -0
- package/src/components/KeyboardFocusGroup/KeyboardFocusGroup.tsx +1 -0
- package/src/context/OrderFocusContext.tsx +25 -0
- package/src/index.tsx +5 -0
- package/src/nativeSpec/ExternalKeyboardViewNativeComponent.ts +12 -0
- package/src/nativeSpec/KeyboardFocusGroupNativeComponent.ts +1 -0
- package/src/types/BaseKeyboardView.ts +26 -0
- package/src/utils/withKeyboardFocus.tsx +24 -0
package/README.md
CHANGED
|
@@ -5,17 +5,139 @@ React Native library for enhanced external keyboard support.
|
|
|
5
5
|
- ⚡️ The New Architecture is supported
|
|
6
6
|
- ⚡️ Bridgeless
|
|
7
7
|
|
|
8
|
+
> [!NOTE]
|
|
9
|
+
> React Native `0.80.0` includes a fix for `TextInput` focus on Android.
|
|
10
|
+
> `TextInput`: Can now focus TextInput with keyboard ([e00028f6bb](https://github.com/facebook/react-native/commit/e00028f6bb6c19de861f9a25f377295755f3671b) by [@joevilches](https://github.com/joevilches))
|
|
11
|
+
>
|
|
12
|
+
> This means that there is no need to use the workaround with `KeyboardExtendedInput`, and it is recommended to use the default `TextInput` instead. Additionally, because of changes in `TextInput`, `focusType="press"` for `KeyboardExtendedInput` no longer works on Android.
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
## New Release: Focus Lock and Focus Order
|
|
16
|
+
Improved keyboard focus control with features like focus order, ordered links, and focus lock.
|
|
17
|
+
|
|
18
|
+
|Android| iOS|
|
|
19
|
+
|-|-|
|
|
20
|
+
| <image alt="Android Focus Order Example" src="https://github.com/user-attachments/assets/8bae353e-cf4b-41f7-8796-fd1cceae5df5" height="400" />| <image alt="iOS Focus Order Example" src="https://github.com/user-attachments/assets/51850cc6-9573-4ccb-b69c-14deefbb4b65" height="400"/> |
|
|
21
|
+
|
|
22
|
+
<details>
|
|
23
|
+
<summary>More Information</summary>
|
|
24
|
+
|
|
25
|
+
Advanced focus order functionality for Android and iOS, plus focus lock!
|
|
26
|
+
|
|
27
|
+
It can be really challenging to manage focus in React Native, but fortunately, there are tools available to simplify the process.
|
|
28
|
+
|
|
29
|
+
## Link Focus Order
|
|
30
|
+
|
|
31
|
+
`Linking` components could be the most logical way to define focus order. By using properties such as `orderId` and `orderBackward`, `orderForward`, `orderLeft`, `orderRight`, `orderUp`, and `orderDown`, you can customize the focus order according to your needs.
|
|
32
|
+
|
|
33
|
+
```tsx
|
|
34
|
+
<View>
|
|
35
|
+
<Pressable
|
|
36
|
+
onPress={onPress}
|
|
37
|
+
orderId="0_0"
|
|
38
|
+
orderForward="0_2"
|
|
39
|
+
>
|
|
40
|
+
<Text>1</Text>
|
|
41
|
+
</Pressable>
|
|
42
|
+
<Pressable
|
|
43
|
+
onPress={onPress}
|
|
44
|
+
orderId="0_2"
|
|
45
|
+
orderBackward="0_1"
|
|
46
|
+
>
|
|
47
|
+
<Text>3</Text>
|
|
48
|
+
</Pressable>
|
|
49
|
+
<Pressable
|
|
50
|
+
onPress={onPress}
|
|
51
|
+
orderId="0_1"
|
|
52
|
+
orderForward="0_2"
|
|
53
|
+
orderBackward="0_0"
|
|
54
|
+
>
|
|
55
|
+
<Text>2</Text>
|
|
56
|
+
</Pressable>
|
|
57
|
+
</View>
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
You can find more examples here: [Focus Link Order](https://github.com/ArturKalach/react-native-external-keyboard/blob/release/0.6.0-rc/example/src/components/FocusOrderExample/FocusLinkOrder.tsx), [DPad Order](https://github.com/ArturKalach/react-native-external-keyboard/blob/release/0.6.0-rc/example/src/components/FocusOrderExample/FocusDPadOrder.tsx)
|
|
61
|
+
|
|
62
|
+
| Props | Description | Type |
|
|
63
|
+
| :-- | :-- | :-- |
|
|
64
|
+
| orderId? | A unique ID used for link target identification. | `string` |
|
|
65
|
+
| orderBackward? | ID of the target for backward navigation with "Tab + Shift". | `string` |
|
|
66
|
+
| orderForward? | ID of the target for forward navigation with "Tab". | `string` |
|
|
67
|
+
| orderLeft? | ID of the target for navigation to the left. | `string` |
|
|
68
|
+
| orderRight? | ID of the target for navigation to the right. | `string` |
|
|
69
|
+
| orderUp? | ID of the target for navigation upward. | `string` |
|
|
70
|
+
| orderDown? | ID of the target for navigation downward. | `string` |
|
|
71
|
+
|
|
72
|
+
## Indexes Focus Order
|
|
73
|
+
|
|
74
|
+
Linking is one of the best ways to set up focus order. However, there may be cases where you need to define the order of multiple elements, such as groups. As an alternative solution, you can use Indexes.
|
|
75
|
+
|
|
76
|
+
```tsx
|
|
77
|
+
<KeyboardOrderFocusGroup>
|
|
78
|
+
<View>
|
|
79
|
+
<Pressable
|
|
80
|
+
onPress={onPress}
|
|
81
|
+
orderIndex={0}
|
|
82
|
+
>
|
|
83
|
+
<Text>First</Text>
|
|
84
|
+
</Pressable>
|
|
85
|
+
<Pressable
|
|
86
|
+
onPress={onPress}
|
|
87
|
+
orderIndex={2}
|
|
88
|
+
>
|
|
89
|
+
<Text>Third</Text>
|
|
90
|
+
</Pressable>
|
|
91
|
+
<Pressable
|
|
92
|
+
onPress={onPress}
|
|
93
|
+
orderIndex={1}
|
|
94
|
+
>
|
|
95
|
+
<Text>Second</Text>
|
|
96
|
+
</Pressable>
|
|
97
|
+
</View>
|
|
98
|
+
</KeyboardOrderFocusGroup>
|
|
99
|
+
```
|
|
100
|
+
Indexing requres `orderGroup` param for proper order set, you can use `KeyboardOrderFocusGroup` or provide `orderGroup` to the component.
|
|
101
|
+
|
|
102
|
+
```tsx
|
|
103
|
+
<Pressable
|
|
104
|
+
orderGroup="main"
|
|
105
|
+
onPress={onPress}
|
|
106
|
+
orderIndex={2}
|
|
107
|
+
>
|
|
108
|
+
<Text>Back</Text>
|
|
109
|
+
</Pressable>
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
| Props | Description | Type |
|
|
113
|
+
| :-- | :-- | :-- |
|
|
114
|
+
| orderGroup? | The name of the group containing ordered elements. | `string` |
|
|
115
|
+
| orderIndex? | The order index of the element within the group. | `number` |
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
You can find more examples here: [Focus Order via indexes](https://github.com/ArturKalach/react-native-external-keyboard/blob/release/0.6.0-rc/example/src/components/FocusOrderExample/FocusOrder.tsx)
|
|
119
|
+
|
|
120
|
+
## Focus Lock
|
|
121
|
+
|
|
122
|
+
Finally, you can lock focus to specific directions.
|
|
123
|
+
|
|
124
|
+
```tsx
|
|
125
|
+
<Pressable
|
|
126
|
+
lockFocus={['down', 'right']}
|
|
127
|
+
>
|
|
128
|
+
<Text>Lock Example</Text>
|
|
129
|
+
</Pressable>
|
|
130
|
+
```
|
|
8
131
|
|
|
9
|
-
## Breaking Changes !!!
|
|
10
|
-
> The Keyboard Module (`A11yModule`, `KeyboardExtendedModule`) has been removed. This API was deprecated and did not work properly with the new architecture. You can refer to the migration guide to update it.
|
|
11
132
|
|
|
133
|
+
| Props | Description | Type |
|
|
134
|
+
| :-- | :-- | :-- |
|
|
135
|
+
| lockFocus? | An array of directions to lock focus. | Array of 'left' | 'right' | 'up' | 'down' | 'forward' | 'backward' | 'first' | 'last' |
|
|
136
|
+
|
|
137
|
+
> [!NOTE]
|
|
138
|
+
> `first` and `last` are specific to `iOS`. When focus is blocked for `forward` and `backward` on iOS, it checks for the `last` and `first` elements to focus.
|
|
139
|
+
</details>
|
|
12
140
|
|
|
13
|
-
## New Release Features
|
|
14
|
-
- Added `Keyboard.dismiss` functionality for Android.
|
|
15
|
-
- Introduced an iOS-specific component: `KeyboardFocusGroup`, a component for managing the `tintColor`, `focusGroupIdentifier`, and group focus.
|
|
16
|
-
- Enhanced `KeyboardExtendedBaseView` with `haloCornerRadius`, `haloExpandX`, and `haloExpandY` properties for customizing the appearance of the `Halo Effect`.
|
|
17
|
-
- Enhanced `KeyboardExtendedBaseView` with `onBubbledContextMenuPress`, key press functionality has been also enhanced. Key presses can be listened to for a group of components, screens, or pages.
|
|
18
|
-
- Added the `ignoreGroupFocusHint` prop to `KeyboardExtendedBaseView` to support key press listening without focusing the container.
|
|
19
141
|
|
|
20
142
|
iOS | Android
|
|
21
143
|
-- | --
|
|
@@ -27,6 +149,7 @@ iOS | Android
|
|
|
27
149
|
- Key press event handling.
|
|
28
150
|
- Focus management for `TextInput` and `Pressable` components.
|
|
29
151
|
- Customization of the `Halo Effect` and `tintColor` for iOS.
|
|
152
|
+
- Keyboard focus order.
|
|
30
153
|
|
|
31
154
|
## Installation
|
|
32
155
|
|
|
@@ -102,6 +225,14 @@ enableA11yFocus?: | Can be used to move the screen reader focus within the keybo
|
|
|
102
225
|
screenAutoA11yFocus?: | Enables screen reader auto-focus functionality. | `boolean \| undefined`
|
|
103
226
|
`screenAutoA11yFocusDelay?:` | **Android only:** Delay for screen reader autofocus. On Android, focus can only be applied after the component has rendered, which may take 300–500 milliseconds. | `number \| undefined`, default: 300
|
|
104
227
|
`exposeMethods?:` | List of exposed view methods | `string[] \| undefined`, by default the following methods are exposed: `'blur', 'measure', 'measureInWindow', 'measureLayout', and 'setNativeProps'`.
|
|
228
|
+
orderId? | A unique ID used for link target identification. | `string`
|
|
229
|
+
orderBackward? | ID of the target for backward navigation with "Tab + Shift". | `string`
|
|
230
|
+
orderForward? | ID of the target for forward navigation with "Tab". | `string`
|
|
231
|
+
orderLeft? | ID of the target for navigation to the left. | `string`
|
|
232
|
+
orderRight? | ID of the target for navigation to the right. | `string`
|
|
233
|
+
orderUp? | ID of the target for navigation upward. | `string`
|
|
234
|
+
orderDown? | ID of the target for navigation downward. | `string`
|
|
235
|
+
lockFocus? | An array of directions to lock focus. | Array of 'left' \| 'right' \| 'up' \| 'down' \| 'forward' \| 'backward' \| 'first' \| 'last'
|
|
105
236
|
...rest | Remaining component props | `Type of Component`
|
|
106
237
|
|
|
107
238
|
|
|
@@ -153,6 +284,14 @@ enableA11yFocus?: | Can be used to move the screen reader focus within the keybo
|
|
|
153
284
|
screenAutoA11yFocus?: | Enables screen reader auto-focus functionality. | `boolean \| undefined`
|
|
154
285
|
`screenAutoA11yFocusDelay?:` | **Android only:** Delay for screen reader autofocus. On Android, focus can only be applied after the component has rendered, which may take 300–500 milliseconds. | `number \| undefined`, default: 300
|
|
155
286
|
`exposeMethods?:` | List of exposed view methods | `string[] \| undefined`, by default the following methods are exposed: `'blur', 'measure', 'measureInWindow', 'measureLayout', and 'setNativeProps'`.
|
|
287
|
+
orderId? | A unique ID used for link target identification. | `string`
|
|
288
|
+
orderBackward? | ID of the target for backward navigation with "Tab + Shift". | `string`
|
|
289
|
+
orderForward? | ID of the target for forward navigation with "Tab". | `string`
|
|
290
|
+
orderLeft? | ID of the target for navigation to the left. | `string`
|
|
291
|
+
orderRight? | ID of the target for navigation to the right. | `string`
|
|
292
|
+
orderUp? | ID of the target for navigation upward. | `string`
|
|
293
|
+
orderDown? | ID of the target for navigation downward. | `string`
|
|
294
|
+
lockFocus? | An array of directions to lock focus. | Array of 'left' \| 'right' \| 'up' \| 'down' \| 'forward' \| 'backward' \| 'first' \| 'last'
|
|
156
295
|
...rest | Remaining View props | `View`
|
|
157
296
|
|
|
158
297
|
|
|
@@ -219,6 +358,14 @@ haloEffect | Enables halo effect on focus (iOS only) | `boolean \| undefined`
|
|
|
219
358
|
autoFocus | Indicates if the component should automatically gain focus | `boolean \| undefined`
|
|
220
359
|
tintColor | Color used for tinting the component | `string`
|
|
221
360
|
ref->focus | Command to programmatically focus the component | () => void;
|
|
361
|
+
orderId? | A unique ID used for link target identification. | `string`
|
|
362
|
+
orderBackward? | ID of the target for backward navigation with "Tab + Shift". | `string`
|
|
363
|
+
orderForward? | ID of the target for forward navigation with "Tab". | `string`
|
|
364
|
+
orderLeft? | ID of the target for navigation to the left. | `string`
|
|
365
|
+
orderRight? | ID of the target for navigation to the right. | `string`
|
|
366
|
+
orderUp? | ID of the target for navigation upward. | `string`
|
|
367
|
+
orderDown? | ID of the target for navigation downward. | `string`
|
|
368
|
+
lockFocus? | An array of directions to lock focus. | Array of 'left' \| 'right' \| 'up' \| 'down' \| 'forward' \| 'backward' \| 'first' \| 'last'
|
|
222
369
|
...rest | Remaining View props | `View`
|
|
223
370
|
|
|
224
371
|
### KeyboardFocusGroup
|
|
@@ -273,6 +420,120 @@ import { Keyboard } from 'react-native-external-keyboard';
|
|
|
273
420
|
|
|
274
421
|
This is needed for hiding the soft keyboard using a hardware keyboard. Additionally, the soft keyboard can be hidden from the settings or by pressing `Alt + K`.
|
|
275
422
|
|
|
423
|
+
## Focus order features
|
|
424
|
+
|
|
425
|
+
## Link Focus Order
|
|
426
|
+
|
|
427
|
+
`Linking` components could be the most logical way to define focus order. By using properties such as `orderId` and `orderBackward`, `orderForward`, `orderLeft`, `orderRight`, `orderUp`, and `orderDown`, you can customize the focus order according to your needs.
|
|
428
|
+
|
|
429
|
+
```tsx
|
|
430
|
+
<View>
|
|
431
|
+
<Pressable
|
|
432
|
+
onPress={onPress}
|
|
433
|
+
orderId="0_0"
|
|
434
|
+
orderForward="0_2"
|
|
435
|
+
>
|
|
436
|
+
<Text>1</Text>
|
|
437
|
+
</Pressable>
|
|
438
|
+
<Pressable
|
|
439
|
+
onPress={onPress}
|
|
440
|
+
orderId="0_2"
|
|
441
|
+
orderBackward="0_1"
|
|
442
|
+
>
|
|
443
|
+
<Text>3</Text>
|
|
444
|
+
</Pressable>
|
|
445
|
+
<Pressable
|
|
446
|
+
onPress={onPress}
|
|
447
|
+
orderId="0_1"
|
|
448
|
+
orderForward="0_2"
|
|
449
|
+
orderBackward="0_0"
|
|
450
|
+
>
|
|
451
|
+
<Text>2</Text>
|
|
452
|
+
</Pressable>
|
|
453
|
+
</View>
|
|
454
|
+
```
|
|
455
|
+
|
|
456
|
+
You can find more examples here: [Focus Link Order](https://github.com/ArturKalach/react-native-external-keyboard/blob/release/0.6.0-rc/example/src/components/FocusOrderExample/FocusLinkOrder.tsx), [DPad Order](https://github.com/ArturKalach/react-native-external-keyboard/blob/release/0.6.0-rc/example/src/components/FocusOrderExample/FocusDPadOrder.tsx)
|
|
457
|
+
|
|
458
|
+
| Props | Description | Type |
|
|
459
|
+
| :-- | :-- | :-- |
|
|
460
|
+
| orderId? | A unique ID used for link target identification. | `string` |
|
|
461
|
+
| orderBackward? | ID of the target for backward navigation with "Tab + Shift". | `string` |
|
|
462
|
+
| orderForward? | ID of the target for forward navigation with "Tab". | `string` |
|
|
463
|
+
| orderLeft? | ID of the target for navigation to the left. | `string` |
|
|
464
|
+
| orderRight? | ID of the target for navigation to the right. | `string` |
|
|
465
|
+
| orderUp? | ID of the target for navigation upward. | `string` |
|
|
466
|
+
| orderDown? | ID of the target for navigation downward. | `string` |
|
|
467
|
+
|
|
468
|
+
## Indexes Focus Order
|
|
469
|
+
|
|
470
|
+
Linking is one of the best ways to set up focus order. However, there may be cases where you need to define the order of multiple elements, such as groups. As an alternative solution, you can use Indexes.
|
|
471
|
+
|
|
472
|
+
```tsx
|
|
473
|
+
<KeyboardOrderFocusGroup>
|
|
474
|
+
<View>
|
|
475
|
+
<Pressable
|
|
476
|
+
onPress={onPress}
|
|
477
|
+
orderIndex={0}
|
|
478
|
+
>
|
|
479
|
+
<Text>First</Text>
|
|
480
|
+
</Pressable>
|
|
481
|
+
<Pressable
|
|
482
|
+
onPress={onPress}
|
|
483
|
+
orderIndex={2}
|
|
484
|
+
>
|
|
485
|
+
<Text>Third</Text>
|
|
486
|
+
</Pressable>
|
|
487
|
+
<Pressable
|
|
488
|
+
onPress={onPress}
|
|
489
|
+
orderIndex={1}
|
|
490
|
+
>
|
|
491
|
+
<Text>Second</Text>
|
|
492
|
+
</Pressable>
|
|
493
|
+
</View>
|
|
494
|
+
</KeyboardOrderFocusGroup>
|
|
495
|
+
```
|
|
496
|
+
Indexing requres `orderGroup` param for proper order set, you can use `KeyboardOrderFocusGroup` or provide `orderGroup` to the component.
|
|
497
|
+
|
|
498
|
+
```tsx
|
|
499
|
+
<Pressable
|
|
500
|
+
orderGroup="main"
|
|
501
|
+
onPress={onPress}
|
|
502
|
+
orderIndex={2}
|
|
503
|
+
>
|
|
504
|
+
<Text>Back</Text>
|
|
505
|
+
</Pressable>
|
|
506
|
+
```
|
|
507
|
+
|
|
508
|
+
| Props | Description | Type |
|
|
509
|
+
| :-- | :-- | :-- |
|
|
510
|
+
| orderGroup? | The name of the group containing ordered elements. | `string` |
|
|
511
|
+
| orderIndex? | The order index of the element within the group. | `number` |
|
|
512
|
+
|
|
513
|
+
|
|
514
|
+
You can find more examples here: [Focus Order via indexes](https://github.com/ArturKalach/react-native-external-keyboard/blob/release/0.6.0-rc/example/src/components/FocusOrderExample/FocusOrder.tsx)
|
|
515
|
+
|
|
516
|
+
## Focus Lock
|
|
517
|
+
|
|
518
|
+
Finally, you can lock focus to specific directions.
|
|
519
|
+
|
|
520
|
+
```tsx
|
|
521
|
+
<Pressable
|
|
522
|
+
lockFocus={['down', 'right']}
|
|
523
|
+
>
|
|
524
|
+
<Text>Lock Example</Text>
|
|
525
|
+
</Pressable>
|
|
526
|
+
```
|
|
527
|
+
|
|
528
|
+
|
|
529
|
+
| Props | Description | Type |
|
|
530
|
+
| :-- | :-- | :-- |
|
|
531
|
+
| lockFocus? | An array of directions to lock focus. | Array of 'left' \| 'right' \| 'up' \| 'down' \| 'forward' \| 'backward' \| 'first' \| 'last' |
|
|
532
|
+
|
|
533
|
+
> [!NOTE]
|
|
534
|
+
> `first` and `last` are specific to `iOS`. When focus is blocked for `forward` and `backward` on iOS, it checks for the `last` and `first` elements to focus.
|
|
535
|
+
|
|
536
|
+
|
|
276
537
|
# Migration 0.3.x to 0.4.0
|
|
277
538
|
|
|
278
539
|
## Module (A11yModule, KeyboardExtendedModule)
|
|
@@ -356,12 +617,14 @@ export type OnKeyPress = NativeSyntheticEvent<{
|
|
|
356
617
|
```
|
|
357
618
|
|
|
358
619
|
## Roadmap
|
|
359
|
-
-
|
|
360
|
-
-
|
|
361
|
-
-
|
|
362
|
-
-
|
|
363
|
-
-
|
|
364
|
-
-
|
|
620
|
+
- [ ] Refactor and Performance optimization
|
|
621
|
+
- [ ] Update `focusGroupIdentifier` and implement `KeyboardNavigationCluster` functionality
|
|
622
|
+
- [ ] Update `onPress` and `onLongPress` for `withKeyboardFocus`
|
|
623
|
+
- [x] Add functionality to control keyboard focus order.
|
|
624
|
+
- [ ] Verify and update `focusable` and `disabled` states for iOS and Android.
|
|
625
|
+
- [ ] Update `Readme.md`.
|
|
626
|
+
- [ ] Create the documentation.
|
|
627
|
+
|
|
365
628
|
|
|
366
629
|
## Contributing
|
|
367
630
|
Any type of contribution is highly appreciated. Feel free to create PRs, raise issues, or share ideas.
|
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
package com.externalkeyboard.delegates;
|
|
2
|
+
|
|
3
|
+
import android.view.View;
|
|
4
|
+
|
|
5
|
+
import com.externalkeyboard.helper.Linking.A11yOrderLinking;
|
|
6
|
+
import com.externalkeyboard.services.FocusLinkObserver.FocusLinkObserver;
|
|
7
|
+
import com.externalkeyboard.services.FocusLinkObserver.FocusLinkObserverSingleton;
|
|
8
|
+
import com.externalkeyboard.views.ExternalKeyboardView.ExternalKeyboardView;
|
|
9
|
+
|
|
10
|
+
public class FocusOrderDelegate {
|
|
11
|
+
private final ExternalKeyboardView delegate;
|
|
12
|
+
|
|
13
|
+
FocusLinkObserver.LinkUpdatedCallback leftUpdated = null;
|
|
14
|
+
FocusLinkObserver.LinkRemovedCallback leftRemoved = null;
|
|
15
|
+
FocusLinkObserver.LinkUpdatedCallback rightUpdated = null;
|
|
16
|
+
FocusLinkObserver.LinkRemovedCallback rightRemoved = null;
|
|
17
|
+
FocusLinkObserver.LinkUpdatedCallback upUpdated = null;
|
|
18
|
+
FocusLinkObserver.LinkRemovedCallback upRemoved = null;
|
|
19
|
+
FocusLinkObserver.LinkUpdatedCallback downUpdated = null;
|
|
20
|
+
FocusLinkObserver.LinkRemovedCallback downRemoved = null;
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
public FocusOrderDelegate(ExternalKeyboardView delegate) {
|
|
24
|
+
super();
|
|
25
|
+
this.delegate = delegate;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
public void link() {
|
|
29
|
+
View child = delegate.getFirstChild();
|
|
30
|
+
String orderGroup = delegate.getOrderGroup();
|
|
31
|
+
Integer orderIndex = delegate.getOrderIndex();
|
|
32
|
+
String orderId = delegate.getOrderId();
|
|
33
|
+
|
|
34
|
+
if (child != null && orderGroup != null && orderIndex != null) {
|
|
35
|
+
A11yOrderLinking.getInstance().addViewRelationship(child, orderGroup, orderIndex);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
FocusLinkObserver observer = FocusLinkObserverSingleton.getInstance();
|
|
39
|
+
if (orderId != null && child != null) {
|
|
40
|
+
observer.emit(orderId, child);
|
|
41
|
+
A11yOrderLinking.getInstance().addOrderLink(child, orderId);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
if (delegate.getOrderLeft() != null && child != null) {
|
|
45
|
+
leftUpdated = link -> child.setNextFocusLeftId(link.getId());
|
|
46
|
+
leftRemoved = () -> child.setNextFocusLeftId(View.NO_ID);
|
|
47
|
+
observer.subscribe(delegate.getOrderLeft(), leftUpdated, leftRemoved);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
if (delegate.getOrderRight() != null && child != null) {
|
|
51
|
+
rightUpdated = link -> child.setNextFocusRightId(link.getId());
|
|
52
|
+
rightRemoved = () -> child.setNextFocusRightId(View.NO_ID);
|
|
53
|
+
observer.subscribe(delegate.getOrderRight(), rightUpdated, rightRemoved);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
if (delegate.getOrderUp() != null && child != null) {
|
|
57
|
+
upUpdated = link -> child.setNextFocusUpId(link.getId());
|
|
58
|
+
upRemoved = () -> child.setNextFocusUpId(View.NO_ID);
|
|
59
|
+
observer.subscribe(delegate.getOrderUp(), upUpdated, upRemoved);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
if (delegate.getOrderDown() != null && child != null) {
|
|
63
|
+
downUpdated = link -> child.setNextFocusDownId(link.getId());
|
|
64
|
+
downRemoved = () -> child.setNextFocusDownId(View.NO_ID);
|
|
65
|
+
observer.subscribe(delegate.getOrderDown(), downUpdated, downRemoved);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
public void refreshOrder() {
|
|
70
|
+
View child = delegate.getFirstChild();
|
|
71
|
+
String orderGroup = delegate.getOrderGroup();
|
|
72
|
+
Integer orderIndex = delegate.getOrderIndex();
|
|
73
|
+
|
|
74
|
+
if (child != null && orderGroup != null) {
|
|
75
|
+
A11yOrderLinking.getInstance().refreshIndexes(child, orderGroup, orderIndex);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
public void refreshLeft(String prev, String next) {
|
|
80
|
+
FocusLinkObserver observer = FocusLinkObserverSingleton.getInstance();
|
|
81
|
+
if (prev != null && leftUpdated != null && leftRemoved != null) {
|
|
82
|
+
observer.unsubscribe(prev, leftUpdated, leftRemoved);
|
|
83
|
+
View child = delegate.getFirstChild();
|
|
84
|
+
if(child != null) {
|
|
85
|
+
child.setNextFocusLeftId(View.NO_ID);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
View child = delegate.getFirstChild();
|
|
90
|
+
if (next != null && child != null) {
|
|
91
|
+
leftUpdated = link -> child.setNextFocusLeftId(link.getId());
|
|
92
|
+
leftRemoved = () -> child.setNextFocusLeftId(View.NO_ID);
|
|
93
|
+
observer.subscribe(next, leftUpdated, leftRemoved);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
public void refreshRight(String prev, String next) {
|
|
98
|
+
FocusLinkObserver observer = FocusLinkObserverSingleton.getInstance();
|
|
99
|
+
if (rightUpdated != null && rightRemoved != null) {
|
|
100
|
+
observer.unsubscribe(prev, rightUpdated, rightRemoved);
|
|
101
|
+
View child = delegate.getFirstChild();
|
|
102
|
+
if(child != null) {
|
|
103
|
+
child.setNextFocusRightId(View.NO_ID);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
View child = delegate.getFirstChild();
|
|
108
|
+
if (next != null && child != null) {
|
|
109
|
+
rightUpdated = link -> child.setNextFocusRightId(link.getId());
|
|
110
|
+
rightRemoved = () -> child.setNextFocusRightId(View.NO_ID);
|
|
111
|
+
observer.subscribe(next, rightUpdated, rightRemoved);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
public void refreshUp(String prev, String next) {
|
|
116
|
+
FocusLinkObserver observer = FocusLinkObserverSingleton.getInstance();
|
|
117
|
+
if (prev != null && upUpdated != null && upRemoved != null) {
|
|
118
|
+
observer.unsubscribe(prev, upUpdated, upRemoved);
|
|
119
|
+
|
|
120
|
+
View child = delegate.getFirstChild();
|
|
121
|
+
if(child != null) {
|
|
122
|
+
child.setNextFocusUpId(View.NO_ID);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
View child = delegate.getFirstChild();
|
|
127
|
+
if (next != null && child != null) {
|
|
128
|
+
upUpdated = link -> child.setNextFocusUpId(link.getId());
|
|
129
|
+
upRemoved = () -> child.setNextFocusUpId(View.NO_ID);
|
|
130
|
+
observer.subscribe(next, upUpdated, upRemoved);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
public void updateOrderGroup(String prev, String next) {
|
|
135
|
+
View child = delegate.getFirstChild();
|
|
136
|
+
Integer position = delegate.getOrderIndex();
|
|
137
|
+
|
|
138
|
+
if (child != null && position != null) {
|
|
139
|
+
A11yOrderLinking.getInstance().updateGroup(prev, next, position, child);
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
public void refreshDown(String prev, String next) {
|
|
144
|
+
FocusLinkObserver observer = FocusLinkObserverSingleton.getInstance();
|
|
145
|
+
if (prev != null && downUpdated != null && downRemoved != null) {
|
|
146
|
+
observer.unsubscribe(prev, downUpdated, downRemoved);
|
|
147
|
+
|
|
148
|
+
View child = delegate.getFirstChild();
|
|
149
|
+
if(child != null) {
|
|
150
|
+
child.setNextFocusDownId(View.NO_ID);
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
View child = delegate.getFirstChild();
|
|
155
|
+
if (next != null && child != null) {
|
|
156
|
+
downUpdated = link -> child.setNextFocusDownId(link.getId());
|
|
157
|
+
downRemoved = () -> child.setNextFocusDownId(View.NO_ID);
|
|
158
|
+
observer.subscribe(next, downUpdated, downRemoved);
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
|
|
163
|
+
public void unlink(View unlinkView) {
|
|
164
|
+
String orderGroup = delegate.getOrderGroup();
|
|
165
|
+
Integer orderIndex = delegate.getOrderIndex();
|
|
166
|
+
String orderId = delegate.getOrderId();
|
|
167
|
+
|
|
168
|
+
if (orderGroup != null && orderIndex != null) {
|
|
169
|
+
A11yOrderLinking.getInstance().removeRelationship(orderGroup, orderIndex);
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
if (orderId != null) {
|
|
173
|
+
FocusLinkObserver observer = FocusLinkObserverSingleton.getInstance();
|
|
174
|
+
View storedView = A11yOrderLinking.getInstance().getOrderLink(orderId);
|
|
175
|
+
if(storedView == unlinkView) {
|
|
176
|
+
observer.emitRemove(orderId);
|
|
177
|
+
A11yOrderLinking.getInstance().removeOrderLink(orderId);
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
|
|
182
|
+
if (delegate.getOrderLeft() != null) {
|
|
183
|
+
FocusLinkObserver observer = FocusLinkObserverSingleton.getInstance();
|
|
184
|
+
observer.unsubscribe(delegate.getOrderLeft(), leftUpdated, leftRemoved);
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
if (delegate.getOrderRight() != null) {
|
|
188
|
+
FocusLinkObserver observer = FocusLinkObserverSingleton.getInstance();
|
|
189
|
+
observer.unsubscribe(delegate.getOrderRight(), rightUpdated, rightRemoved);
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
if (delegate.getOrderUp() != null) {
|
|
193
|
+
FocusLinkObserver observer = FocusLinkObserverSingleton.getInstance();
|
|
194
|
+
observer.unsubscribe(delegate.getOrderUp(), upUpdated, upRemoved);
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
if (delegate.getOrderDown() != null) {
|
|
198
|
+
FocusLinkObserver observer = FocusLinkObserverSingleton.getInstance();
|
|
199
|
+
observer.unsubscribe(delegate.getOrderDown(), downUpdated, downRemoved);
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
public View getLink(String linkId) {
|
|
204
|
+
return A11yOrderLinking.getInstance().getOrderLink(linkId);
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
public void clear(View view) {
|
|
208
|
+
if(view != null) {
|
|
209
|
+
unlink(view);
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
}
|
|
@@ -1,9 +1,53 @@
|
|
|
1
1
|
package com.externalkeyboard.helper;
|
|
2
2
|
|
|
3
|
+
import android.view.KeyEvent;
|
|
3
4
|
import android.view.View;
|
|
4
5
|
import android.view.ViewGroup;
|
|
5
6
|
|
|
7
|
+
import java.util.HashMap;
|
|
8
|
+
import java.util.Map;
|
|
9
|
+
|
|
6
10
|
public class FocusHelper {
|
|
11
|
+
private static final int MASK_FOCUS_UP = 0b1;
|
|
12
|
+
private static final int MASK_FOCUS_DOWN = 0b10;
|
|
13
|
+
private static final int MASK_FOCUS_LEFT = 0b100;
|
|
14
|
+
private static final int MASK_FOCUS_RIGHT = 0b1000;
|
|
15
|
+
private static final int MASK_FOCUS_FORWARD = 0b10000;
|
|
16
|
+
private static final int MASK_FOCUS_BACKWARD = 0b100000;
|
|
17
|
+
|
|
18
|
+
private static final Map<Integer, Integer> DIRECTION_MASK_MAP = new HashMap<>();
|
|
19
|
+
private static final Map<Integer, Integer> DIRECTION_KEY_MASK_MAP = new HashMap<>();
|
|
20
|
+
|
|
21
|
+
static {
|
|
22
|
+
DIRECTION_MASK_MAP.put(View.FOCUS_UP, MASK_FOCUS_UP);
|
|
23
|
+
DIRECTION_MASK_MAP.put(View.FOCUS_DOWN, MASK_FOCUS_DOWN);
|
|
24
|
+
DIRECTION_MASK_MAP.put(View.FOCUS_LEFT, MASK_FOCUS_LEFT);
|
|
25
|
+
DIRECTION_MASK_MAP.put(View.FOCUS_RIGHT, MASK_FOCUS_RIGHT);
|
|
26
|
+
DIRECTION_MASK_MAP.put(View.FOCUS_FORWARD, MASK_FOCUS_FORWARD);
|
|
27
|
+
DIRECTION_MASK_MAP.put(View.FOCUS_BACKWARD, MASK_FOCUS_BACKWARD);
|
|
28
|
+
|
|
29
|
+
DIRECTION_KEY_MASK_MAP.put(KeyEvent.KEYCODE_DPAD_LEFT, MASK_FOCUS_LEFT);
|
|
30
|
+
DIRECTION_KEY_MASK_MAP.put(KeyEvent.KEYCODE_DPAD_RIGHT, MASK_FOCUS_RIGHT);
|
|
31
|
+
DIRECTION_KEY_MASK_MAP.put(KeyEvent.KEYCODE_DPAD_UP, MASK_FOCUS_UP);
|
|
32
|
+
DIRECTION_KEY_MASK_MAP.put(KeyEvent.KEYCODE_DPAD_DOWN, MASK_FOCUS_DOWN);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
public static boolean isLocked(int direction, int lockFocus) {
|
|
36
|
+
Integer mask = DIRECTION_MASK_MAP.get(direction);
|
|
37
|
+
if (mask != null) {
|
|
38
|
+
return (lockFocus & mask) != 0;
|
|
39
|
+
}
|
|
40
|
+
return false;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
public static boolean isKeyLocked(int direction, int lockFocus) {
|
|
44
|
+
Integer mask = DIRECTION_KEY_MASK_MAP.get(direction);
|
|
45
|
+
if (mask != null) {
|
|
46
|
+
return (lockFocus & mask) != 0;
|
|
47
|
+
}
|
|
48
|
+
return false;
|
|
49
|
+
}
|
|
50
|
+
|
|
7
51
|
public static View getFocusableView(ViewGroup viewGroup) {
|
|
8
52
|
if (viewGroup.getChildCount() > 0) {
|
|
9
53
|
View subView = viewGroup.getChildAt(0);
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
package com.externalkeyboard.helper.Linking;
|
|
2
|
+
|
|
3
|
+
import android.view.View;
|
|
4
|
+
|
|
5
|
+
import java.util.HashMap;
|
|
6
|
+
import java.util.Map;
|
|
7
|
+
import java.util.WeakHashMap;
|
|
8
|
+
|
|
9
|
+
public class A11yOrderLinking {
|
|
10
|
+
|
|
11
|
+
private static A11yOrderLinking instance;
|
|
12
|
+
private final Map<String, LinkingQueue> relationships;
|
|
13
|
+
private final Map<String, View> weakMap;
|
|
14
|
+
|
|
15
|
+
private A11yOrderLinking() {
|
|
16
|
+
relationships = new HashMap<>();
|
|
17
|
+
weakMap = new WeakHashMap<>();
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
public static synchronized A11yOrderLinking getInstance() {
|
|
21
|
+
if (instance == null) {
|
|
22
|
+
instance = new A11yOrderLinking();
|
|
23
|
+
}
|
|
24
|
+
return instance;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
public void addOrderLink(View view, String key) {
|
|
28
|
+
this.weakMap.put(key, view);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
public void removeOrderLink(String key) {
|
|
32
|
+
this.weakMap.remove(key);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
public View getOrderLink(String key) {
|
|
36
|
+
return this.weakMap.get(key);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
public void refreshIndexes(View view, String key, int position) {
|
|
40
|
+
LinkingQueue queue = relationships.get(key);
|
|
41
|
+
if (queue != null) {
|
|
42
|
+
queue.refreshIndexes(view, position);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
public void addViewRelationship(View view, String key, int position) {
|
|
47
|
+
LinkingQueue queue = relationships.get(key);
|
|
48
|
+
if (queue == null) {
|
|
49
|
+
queue = new LinkingQueue();
|
|
50
|
+
relationships.put(key, queue);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
queue.addPosition(view, position);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
public void removeRelationship(String key, int index) {
|
|
58
|
+
LinkingQueue queue = relationships.get(key);
|
|
59
|
+
if (queue == null) return;
|
|
60
|
+
|
|
61
|
+
queue.removeFromOrder(index);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
public void updateGroup(String prev, String next, Integer position, View child) {
|
|
65
|
+
if (prev != null && prev.equals(next)) return;
|
|
66
|
+
if (prev != null) {
|
|
67
|
+
LinkingQueue queue = relationships.get(prev);
|
|
68
|
+
if (queue != null) {
|
|
69
|
+
queue.removeFromOrder(position);
|
|
70
|
+
|
|
71
|
+
if (queue.isEmpty()) {
|
|
72
|
+
relationships.remove(prev);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
if (next != null && position != null && child != null) {
|
|
78
|
+
this.addViewRelationship(child, next, position);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|