diff --git a/README.en.md b/README.en.md
new file mode 100644
index 0000000000000000000000000000000000000000..12de1d5f1a9497f789c63371f3b1dbe5f4560fb2
--- /dev/null
+++ b/README.en.md
@@ -0,0 +1,68 @@
+# Implementing a Custom Keyboard
+
+### Overview
+
+This sample introduces how to implement a custom keyboard. The custom keyboard can be bound to the system keyboard so that they can switch to each other. The **onAreaChange** function can be used to obtain the custom keyboard height and set layout avoidance. This sample also describes technical scenarios such as keyboard switching, custom keyboard cursor, and custom keyboard layout avoidance.
+
+### Preview
+| Layout avoidance | Keyboard Switching | Common functions |
+|:-----------------------------------------:|:------------------------------------------:|:---------------------------------------:|
+|  |  |  |
+
+
+How to Use
+
+1. On the home page, tap the text box for binding a custom keyboard. The custom keyboard is displayed, with layout avoidance upwards.
+
+2. Tap the 123, ABC, and Chinese tabs on the keyboard to switch between the numeric keypad, English keyboard, and system keyboard. In this way, a text box can be bound to both the custom keyboard and system keyboard.
+
+3. Common keyboard operations are supported, including text input, cursor setting, uppercase/lowercase change, copy, paste, and deletion.
+
+
+### Project Directory
+
+```
+├──entry/src/main/ets // Code area
+│ ├──constants
+│ │ └──Constants.ets // Common constants
+│ ├──entryability
+│ │ └──EntryAbility.ets // Entry ability
+│ ├──model
+│ │ └──KeyboardController.ets // Custom keyboard controller
+│ ├──pages
+│ │ └──MainPage.ets // Main page
+│ ├──view
+│ │ ├──CustomKeyboard.ets // Custom keyboard
+│ │ ├──EnglishKeyboard.ets // English keyboard
+│ │ ├──NumberKeyboard.ets // Numeric keyboard
+│ │ ├──TabButton.ets // Tab button on the top of the keyboard
+│ │ ├──TabView.ets // Tab component on the top of the keyboard
+│ │ └──TextInputComponent.ets // TextInput component bound to the custom keyboard
+│ └──viewmodel
+│ └──MenuModel.ets // Keyboard button data
+└──entry/src/main/resources // App resource directory
+```
+
+### How to Implement
+
+1. To implement a custom keyboard, the **customKeyboard** attribute of the **TextInput** component is bound to **builder**.
+2. To switch between the custom keyboard and the system keyboard, the **customKeyboard** attribute of the **TextInput** component is set to **null** and is bound to the system keyboard.
+3. To set the cursor position, the system listens for the **onTextSelectionChange** and **onChange** events of the **TextInput** component.
+4. To implement the copy and paste functions, the system listens for the **onPaste** and **onCut** events of the **TextInput** component.
+5. To implement layout avoidance, the **keyboardHeightChange** event of the window module is used to obtain the system keyboard height, and the **onAreaChange** event is used to obtain the custom keyboard height.
+
+### Permissions
+N/A
+
+### Dependencies
+N/A
+
+### Constraints
+
+1. The sample is only supported on Huawei phones with standard systems.
+
+2. The HarmonyOS version must be HarmonyOS 5.0.0 Release or later.
+
+3. The DevEco Studio version must be DevEco Studio 5.0.0 Release or later.
+
+4. The HarmonyOS SDK version must be HarmonyOS 5.0.0 Release SDK or later.
\ No newline at end of file
diff --git a/entry/src/main/ets/constants/Constants.ets b/entry/src/main/ets/constants/Constants.ets
index e33bcea6ddec538ecf3fdb23ba473702a8675ebf..ff677cddffdafd1da4c85a8574a0e3464955243f 100644
--- a/entry/src/main/ets/constants/Constants.ets
+++ b/entry/src/main/ets/constants/Constants.ets
@@ -62,4 +62,9 @@ export class Constants {
* the default space in column.
*/
static readonly DEFAULT_COLUMN_SPACE: number = 12;
+
+ /**
+ * Resource type media.
+ */
+ static readonly RESOURCE_TYPE_MEDIA: number = 20000;
}
\ No newline at end of file
diff --git a/entry/src/main/ets/model/KeyboardController.ets b/entry/src/main/ets/model/KeyboardController.ets
index 62290591907b5795776970d7c3e0bdde2b17c43a..806388556c1a6c8435080234f3db3cfc206b0a78 100644
--- a/entry/src/main/ets/model/KeyboardController.ets
+++ b/entry/src/main/ets/model/KeyboardController.ets
@@ -57,8 +57,8 @@ export class KeyboardController {
this.text = this.text.substring(0, this.leftCaretPos) + ' ' + this.text.substring(this.rightCaretPos);
this.targetCaretPos = this.leftCaretPos + 1;
break;
- case $r('app.string.keyboardButton_uppercase').id:
- case $r('app.string.keyboardButton_lowercase').id:
+ case $r('app.media.arrowshape_up').id:
+ case $r('app.media.arrowshape_up_fill').id:
this.isUpperCase = !this.isUpperCase;
break;
}
diff --git a/entry/src/main/ets/view/EnglishKeyboard.ets b/entry/src/main/ets/view/EnglishKeyboard.ets
index be7ab1eb25b0d74a21a0123e9f8d4931179da975..f2bc1d4109d07aa57c397ddec0d9f89dc3d9df64 100644
--- a/entry/src/main/ets/view/EnglishKeyboard.ets
+++ b/entry/src/main/ets/view/EnglishKeyboard.ets
@@ -76,16 +76,25 @@ struct EnglishButton {
}
build() {
- Button(this.getEnglishText(this.item), { type: ButtonType.Normal })
- .fontColor(Color.Black)
- .backgroundColor(this.item.backgroundColor)
- .borderRadius(Constants.KEYBOARD_BUTTON_RADIUS)
- .fontSize(Constants.KEYBOARD_BUTTON_FONTSIZE_18)
- .padding(0)
- .width(this.item.width)
- .height(this.item.height)
- .onClick(() => {
- this.inputText = this.keyBoardController.onInput(this.getEnglishText(this.item));
- })
+ Button({ type: ButtonType.Normal }) {
+ if (typeof this.getEnglishText(this.item) === 'string' ||
+ (this.getEnglishText(this.item) as Resource).type !== Constants.RESOURCE_TYPE_MEDIA) {
+ Text(this.getEnglishText(this.item))
+ } else {
+ Image(this.getEnglishText(this.item))
+ .width(Constants.KEYBOARD_BUTTON_FONTSIZE_18)
+ .height(Constants.KEYBOARD_BUTTON_FONTSIZE_18)
+ }
+ }
+ .fontColor(Color.Black)
+ .backgroundColor(this.item.backgroundColor)
+ .borderRadius(Constants.KEYBOARD_BUTTON_RADIUS)
+ .fontSize(Constants.KEYBOARD_BUTTON_FONTSIZE_18)
+ .padding(0)
+ .width(this.item.width)
+ .height(this.item.height)
+ .onClick(() => {
+ this.inputText = this.keyBoardController.onInput(this.getEnglishText(this.item));
+ })
}
}
\ No newline at end of file
diff --git a/entry/src/main/ets/viewmodel/MenuModel.ets b/entry/src/main/ets/viewmodel/MenuModel.ets
index a7033ed1aed94ca74ca024d088075db76cf8b80c..f2bef13800ce04727827d904df9f2c8886fbadcd 100644
--- a/entry/src/main/ets/viewmodel/MenuModel.ets
+++ b/entry/src/main/ets/viewmodel/MenuModel.ets
@@ -264,8 +264,8 @@ export let EnglishKeyboardData: Menu[][] = [
],
[
{
- text: $r('app.string.keyboardButton_uppercase'),
- upperText: $r('app.string.keyboardButton_lowercase'),
+ text: $r('app.media.arrowshape_up'),
+ upperText: $r('app.media.arrowshape_up_fill'),
backgroundColor: $r('app.color.menu_color_gray'),
width: 49 + px2vp(6) + 'vp',
height: '43vp'
diff --git a/entry/src/main/resources/base/media/arrowshape_up.svg b/entry/src/main/resources/base/media/arrowshape_up.svg
new file mode 100644
index 0000000000000000000000000000000000000000..2ea19f8c878a6b7fad4d39c4a95c81ab66f74a2a
--- /dev/null
+++ b/entry/src/main/resources/base/media/arrowshape_up.svg
@@ -0,0 +1,2 @@
+
+
\ No newline at end of file
diff --git a/entry/src/main/resources/base/media/arrowshape_up_fill.svg b/entry/src/main/resources/base/media/arrowshape_up_fill.svg
new file mode 100644
index 0000000000000000000000000000000000000000..09c2402dc2f2b68485de57aafbcb173c2f02fe3a
--- /dev/null
+++ b/entry/src/main/resources/base/media/arrowshape_up_fill.svg
@@ -0,0 +1,2 @@
+
+
\ No newline at end of file
diff --git a/entry/src/main/resources/en_US/element/string.json b/entry/src/main/resources/en_US/element/string.json
index 8963a456a3839884c970df84596034d3265f5f31..6d88be3e03cb9d8bfcae3fbd1d17fb844696e566 100644
--- a/entry/src/main/resources/en_US/element/string.json
+++ b/entry/src/main/resources/en_US/element/string.json
@@ -34,27 +34,27 @@
},
{
"name": "keyboardButton_delete",
- "value": "删除"
+ "value": "Del"
},
{
"name": "keyboardButton_clear",
- "value": "清空"
+ "value": "Clear"
},
{
"name": "keyboardButton_finish",
- "value": "确认"
+ "value": "Done"
},
{
"name": "keyboardButton_space",
- "value": "空格"
+ "value": "Space"
},
{
"name": "keyboardButton_uppercase",
- "value": "大写"
+ "value": "Up"
},
{
"name": "keyboardButton_lowercase",
- "value": "小写"
+ "value": "Low"
}
]
}
\ No newline at end of file
diff --git a/screenshots/device/avoid.en.gif b/screenshots/device/avoid.en.gif
new file mode 100644
index 0000000000000000000000000000000000000000..070cf1a3f309c69c90cb5c9c14d9f02c2fcb767e
Binary files /dev/null and b/screenshots/device/avoid.en.gif differ
diff --git a/screenshots/device/avoid.gif b/screenshots/device/avoid.gif
index cc2e114884aa59bcd9a2b57b8ccfa9d8931348fb..cdcc88a1c16567585711dccc2238d06efc571b20 100644
Binary files a/screenshots/device/avoid.gif and b/screenshots/device/avoid.gif differ
diff --git a/screenshots/device/switch.en.gif b/screenshots/device/switch.en.gif
new file mode 100644
index 0000000000000000000000000000000000000000..f1685a12fd663f684bdd2dab1fe829a247dab3a3
Binary files /dev/null and b/screenshots/device/switch.en.gif differ
diff --git a/screenshots/device/switch.gif b/screenshots/device/switch.gif
index 9bd3dddb955e5381ee03fa2351809524a9274459..a7bee9ca32ce42d30c2f095fd3744b10858e2104 100644
Binary files a/screenshots/device/switch.gif and b/screenshots/device/switch.gif differ
diff --git a/screenshots/device/use.en.gif b/screenshots/device/use.en.gif
new file mode 100644
index 0000000000000000000000000000000000000000..cca1324ec69424268c4f141bb5b681f75df20391
Binary files /dev/null and b/screenshots/device/use.en.gif differ
diff --git a/screenshots/device/use.gif b/screenshots/device/use.gif
index d02d8ce39cb1b9a1549fa1d1a9e623772077cbbb..a3ddd50f080aea6170561a03fe9e0997108b0f07 100644
Binary files a/screenshots/device/use.gif and b/screenshots/device/use.gif differ