[Daily HarmonyOS Next Knowledge] Custom Keyboard Cursor, Canvas Drawing, XComponent Triggering Keyboard Release, etc.
1. How to set the cursor position based on a custom keyboard?
Refer to the following code:
class MyKeyboardController {
public onInputChanged?: (value: string) => void
public inputController = new TextInputController()
public carePosition = -1
private inputValue = ''
onKeyClicked(key: string) {
const index = this.inputController.getCaretOffset().index
if (key === 'A' || key === 'B') {
this.setInputValue(this.inputValue.substring(0, index) + key + this.inputValue.substring(index))
this.carePosition = index + 1
} else if (key === '<') {
if (index > 0) {
this.setInputValue(this.inputValue.substring(0, index - 1) + this.inputValue.substring(index))
this.carePosition = index - 1
}
}
}
setInputValue(value: string) {
if (this.carePosition >= 0) {
this.inputController.caretPosition(this.carePosition)
this.carePosition = -1
}
if (this.inputValue === value) {
return;
}
this.inputValue = value
if (this.onInputChanged) {
this.onInputChanged(value)
}
}
}
@Component
struct MyKeyboardA {
controller?: MyKeyboardController
private keys = ['A', 'B', '<']
build() {
Row() {
ForEach(this.keys, (v: string) => {
Text(v)
.layoutWeight(1)
.height(44)
.borderWidth(1)
.borderColor(Color.Gray)
.borderRadius(4)
.onClick(() => {
this.controller?.onKeyClicked(v)
})
})
}
.height(300)
.backgroundColor(Color.Gray)
}
}
@Entry
@Component
export struct RichKeyPage {
keyboardController = new MyKeyboardController()
@State text: string = ''
aboutToAppear(): void {
this.keyboardController.onInputChanged = (value) => {
this.text = value
}
}
build() {
Column({ space: 20 }) {
TextInput({ text: this.text, controller: this.keyboardController.inputController })
.width('100%')
.height(44)
.customKeyboard(this.myKeyboardA())
.onChange((value) => {
this.keyboardController.setInputValue(value)
})
Button('Click to directly change the input box content')
.width('100%')
.height(44)
.onClick(() => {
this.text = '12345678'
})
}
}
@Builder
myKeyboardA() {
MyKeyboardA({ controller: this.keyboardController })
}
}
2. How to achieve a hollow effect?
Use Canvas to draw a hollow circle and overlay it on the area that needs to be transparent using a Stack component. Refer to the following code:
@Entry
@Component
struct Page {
@State message: string = 'Hello World';
private settings: RenderingContextSettings = new RenderingContextSettings(true)
private context: CanvasRenderingContext2D = new CanvasRenderingContext2D(this.settings)
@State circleCenterX: number = 0
@State circleCenterY: number = 0
@State circleRadius: number = 100
build() {
Row() {
Column() {
Stack() {
Image($r('app.media.startIcon')).height(300)
// Use Canvas to draw a mask over images, cameras, etc.
Canvas(this.context)
.width('100%')
.height('100%')
.backgroundColor('#00000000')
.onReady(() => {
this.circleCenterX = this.context.width / 2
this.circleCenterY = this.context.height / 2
this.context.fillStyle = '#aa000000'
// Draw a circular path for semi-transparent filling
this.context.beginPath()
this.context.moveTo(0, 0)
this.context.lineTo(0, this.context.height)
this.context.lineTo(this.context.width, this.context.height)
this.context.lineTo(this.context.width, 0)
this.context.lineTo(0, 0)
this.context.arc(this.circleCenterX, this.circleCenterY, this.circleRadius, 0, Math.PI * 2)
this.context.fill()
this.context.closePath()
})
}.width('1456px')
.height('1456px')
}
.width('100%')
}
.height('100%')
}
}
3. How to draw a rounded rectangle using Canvas?
Use the arc
method of the CanvasRenderingContext2D
object to draw arc paths and combine it with the lineTo
method to draw straight lines. Refer to the following code:
@Entry
@Component
struct Page {
@State message: string = 'Hello World';
private readonly settings: RenderingContextSettings = new RenderingContextSettings(true);
private readonly ctx: CanvasRenderingContext2D = new CanvasRenderingContext2D(this.settings);
/**
* Draw a rounded rectangle
* @param {* Required} x x-coordinate
* @param {* Required} y y-coordinate
* @param {* Required} width Width
* @param {* Required} height Height
* @param {* Required} radius Radius of the rounded corner
* @param {* Optional, default: '#456'} strokeColor Border color
* @param {* Optional, no default} fillColor Fill color
* @param {* Optional, default: [] solid line} lineDash Border style
*/
drawRoundRect(x: number, y: number, width: number, height: number, radius: number, strokeColor?: string, fillColor?: string, lineDash?: []) {
strokeColor = strokeColor || '#333';
lineDash = lineDash || [];
this.ctx.beginPath();
// Set line dash if specified
this.ctx.setLineDash(lineDash);
// Draw the first arc path
this.ctx.arc(x + radius, y + radius, radius, Math.PI, Math.PI * 3 / 2);
// Draw the first straight line path
this.ctx.lineTo(width - radius + x, y);
// Draw the second arc path
this.ctx.arc(width - radius + x, radius + y, radius, Math.PI * 3 / 2, Math.PI * 2);
// Draw the second straight line path
this.ctx.lineTo(width + x, height + y - radius);
// Draw the third arc path
this.ctx.arc(width - radius + x, height - radius + y, radius, 0, Math.PI / 2);
// Draw the third straight line path
this.ctx.lineTo(radius + x, height + y);
// Draw the fourth arc path
this.ctx.arc(radius + x, height - radius + y, radius, Math.PI / 2, Math.PI);
// Draw the fourth straight line path
this.ctx.lineTo(x, y + radius);
// Set the stroke color
this.ctx.strokeStyle = strokeColor;
// Stroke the path
this.ctx.stroke();
if (fillColor) {
// Fill the path if fill color is specified
this.ctx.fillStyle = fillColor;
this.ctx.fill();
}
this.ctx.closePath();
}
build() {
Row() {
Column() {
Canvas(this.ctx)
.width('100%')
.height('100%')
.onReady(() => {
this.drawRoundRect(50, 50, 100, 100, 10)
})
}
.width('100%')
}
.height('100%')
}
}
4. Why does XComponent sometimes fail to trigger the keyboard release event?
Problem description:
- When using Native XComponent's keyboard event interface, the release state of the Alt key cannot be obtained.
- When launching another application or switching to another application via shortcut keys, the window loses focus, causing the XComponent to fail to receive the key release event, resulting in abnormal key behavior within the application.
Solution:
- You can observe all subscribed keys using
hdc shell hidumper -s 3101 -a -s
, and see that Alt is subscribed. In this case, the Alt release event will be consumed by other subscribed applications. - When the window loses focus, the application cannot perceive keyboard events, which is a specification. A new interface capability will be released in the future. The new interface will return parameters indicating the currently pressed keys/buttons on the keyboard/mouse when keyboard/mouse events are triggered, allowing the application to handle the logic accordingly.
5. What is the correct way to use bound-type components with ForEach?
Problem description:
When using bindSheet
with ForEach
, $$this.isShow
triggers the semi-modal twice. If using this.isShow
, the semi-modal pops up as many times as the length of the array. How to ensure only one pop-up is triggered when clicking an item in ForEach?
Solution:
Key code: Bind each pop-up with a @State
-decorated variable. An array is convenient when there are multiple pop-ups.
Top comments (0)