
在HarmonyOS Next开发中实现自定义键盘 原创
大家好,今天要和大家分享的是在鸿蒙开发中实现自定义键盘。
接触鸿蒙开发时间越长,越感觉到它的人性化和便利性,像自定义键盘这种在其他平台极具难度和复杂性的事情,在鸿蒙开发中只需要一句代码就能实现。
只需要在TextInput的customKeyboard属性传入自己的键盘组件,就能替换掉系统的键盘,简直不要太方便:
TextInput({ controller: this.controller, text: this.inputValue })
.customKeyboard(this.CustomKeyboardBuilder())
所以接下来的工作就只有搭建自己的键盘样式,看似只是简单的按钮排列,其实有不少的坑要踩。
首先做一个字母键盘,排列布局方式大家随心所欲,只要能实现就好,我这里就使用最简单的方式,Column和Row的组合使用,简单结构如下:
Column({space:8}){
Row(){
//q、w、e、r。。。
}
Row(){
//a、s、d。。。
}
Row(){
//z、x、c。。。
}
Row(){
//空格。。。
}
}
.padding({top:20,bottom:20})
其中最后两行有些特殊尺寸的按键需要单独计算,算术问题这里不再赘述。
接下来要为键盘添加一些样式,比如阴影:
.shadow({
offsetX:0,
offsetY:5,
color:Color.Black,
radius:3
})
还要实现按压的效果,stateStyles属性可以设置组件在不同状态下的样式:
.stateStyles({ normal: {.backgroundColor(this.backColor)}, pressed: {.backgroundColor($r('app.color.state_styles_pressed'))}})
这样字母键盘的页面就做好了。接下来要为按键添加点击事件,也就是点击的时候将按键上的内容传回即可,通常来说使用onClick就可以实现,但是还可以再完美一点。
因为键盘中的删除按钮长按的话应该要有一个持续的删除效果,这样的话简单的使用onClick就无法满足要求。所以这里要使用组合手势,既要识别单击也要识别长按:
.gesture(
GestureGroup(GestureMode.Parallel,
TapGesture({ count: 1 })
.onAction(() => {
console.log('点击事件')
this.clickAction()
}),
LongPressGesture({ repeat: true })
.onAction((event: GestureEvent|undefined) => {
if(event){
if (event.repeat) {
}
}
console.info('长按事件');
if(this.longClickAction){
this.longClickAction()
}
})
)
这里使用的是并行组合手势,互不影响。
然后要实现大小写的转换,比较简单,大写是toUpperCase(),小写就是toLowerCase()。
最后实现删除功能,无论是单击还是长按都删除输入框内容的最后一个字符,长按事件会持续调用,这里不用理会:
this.inputValue = this.inputValue.slice(0,-1);
这样一个纯字母键盘就基本实现了,接下来再开发一个数字键盘,数字键盘看起来布局就比较简单,所有按键大小一致。
那这里能不能使用Grid?布局肯定是可以实现,而且是最简单快捷的方式,但是我发现stateStyles的按压效果在
Grid组件中不能及时响应,会顿一下,这个暂时不去研究,换一种布局方式就好了,还是采用跟字母键盘一样的组合布局方式。
最后再实现字母键盘和数字键盘的点击切换,一个非常好看的自定义键盘就实现了。
现在回过头去,对代码做一些优化。既然所有的按键都有阴影,都有点击事件,我们就把封装一下:
@Component
export struct KeyBoardPack{
@Prop packWidth:number
@Prop packHeight:number
@Prop backColor:string = '#ffffff'
@Builder customBuilder() {};
@BuilderParam customBuilderParam: () => void = this.customBuilder;
clickAction:()=>void=()=>{}
longClickAction?:()=>void=()=>{}
@Styles
pressedStyles() {
.backgroundColor($r('app.color.state_styles_pressed'))
}
@Styles
normalStyles() {
.backgroundColor(Color.White)
}
build() {
Row(){
this.customBuilderParam()
}
.justifyContent(FlexAlign.Center)
.width(this.packWidth)
.height(this.packHeight)
.shadow({
offsetX:0,
offsetY:5,
color:Color.Black,
radius:3
})
.stateStyles({ normal: {.backgroundColor(this.backColor)}, pressed: {.backgroundColor($r('app.color.state_styles_pressed'))}})
.gesture(
GestureGroup(GestureMode.Parallel,
TapGesture({ count: 1 })
.onAction(() => {
console.log('点击事件')
this.clickAction()
}),
LongPressGesture({ repeat: true })
.onAction((event: GestureEvent|undefined) => {
if(event){
if (event.repeat) {
}
}
console.info('长按事件');
if(this.longClickAction){
this.longClickAction()
}
})
)
)
}
}
这样再添加按键的时候就直接使用封装好的组件:
KeyBoardPack({packWidth:this.keyItemWidth,packHeight:this.keyItemHeight,clickAction:()=>{
this.keyInputAction(KeyBoardType.normal,this.Upper?item.toUpperCase():item.toLowerCase())
}}){
Text(this.Upper?item.toUpperCase():item.toLowerCase())
.fontColor(Color.Black)
.fontSize(15)
.fontWeight(FontWeight.Bold)
}
以上就是今天的案例分享,感谢阅读。本文项目源码地址:
https://gitee.com/the-blue-plan/cuskeyboard
