基于TextInput的常见自定义效果解决方案
场景描述
输入框一般用于来承载用户的信息录入,常用于搜索框、表单、对话框等场景。
场景一:TextInput实现输入框热搜词自动滚动及文字内容颜色渐变
输入框未获焦时热搜词自动滚动,输入框获焦时输入框热搜词暂停滚动,热搜词文字到输入框右侧时文字内容会渐变显示。
方案
1、用Stack组件堆叠Swiper和TextInput,让Swiper在TextInput中间显示核心代码。
Row() {
Stack() {
// 使用Stack堆叠Swiper和TextInput组件。
Swiper() {
// 使用ForEach组件循环搜索关键字数据
ForEach(SEARCH_TEXT, (item: SearchTextModel) => {
Text(item.searchText)
.opacity(TEXT_OPACITY)
.fontColor('#000000')
.fontSize(14)
.textAlign(TextAlign.Start)
.width('100%')
}, (item: SearchTextModel) => item.id.toString())
}
...
TextInput({ text: this.textData, controller: this.controller })
}
.width('80%')
.height(100)
}
2、使用Swiper组件显示热搜关键字并自动切换,将Swiper设置为纵向滑动.vertical(true),通过判断输入框是否有内容来控制Swiper的显示隐藏。
Swiper() {
// 使用ForEach组件循环搜索关键字数据
ForEach(SEARCH_TEXT, (item: SearchTextModel) => {
Text(item.searchText)
.opacity(TEXT_OPACITY)
.fontColor('#000000')
.fontSize(14)
.textAlign(TextAlign.Start)
.width('100%')
}, (item: SearchTextModel) => item.id.toString())
}
.displayMode(SwiperDisplayMode.STRETCH)
// 根据搜索框是否有内容控制显示隐藏
.visibility(this.textData ? Visibility.Hidden : Visibility.Visible)
.loop(true)
// 通过状态变量控制是否自动轮播
.autoPlay(this.isAutoPlay)
// 垂直方向
.vertical(true)
// 去掉指示器
.indicator(false)
.interval(SWIPER_INTERVAL)
.margin(16)
.onChange((index) => {
this.swiperIndex = index;
})
3、使用TextInput搜索框组件,根据搜索框是否处于编辑态控制Swiper组件开始和暂停滚动,设置搜索框最大行数为1。
TextInput({ text: this.textData, controller: this.controller })
.onChange((data) => {
this.textData = data;
})
.onEditChange((isEditing) => {
// 通过判断编辑态控制Swiper组件开始和暂停滚动
if (!isEditing) {
this.isAutoPlay = true;
} else {
this.isAutoPlay = false;
}
})
.maxLines(MAX_LINE)
.width('100%')
.height(40)
4、点击搜索按钮时,退出编辑状态,如果搜索框没有内容提交当前热搜词。
Button('搜索')
.layoutWeight(1)
.margin({ left: 10 })
.height(40)
.onClick(() => {
// 可选择在此时通过判断搜索框是否有内容来选择提交搜索框内容或当前热搜关键字。
// 没有内容时提交当前热搜关键字
if (!this.textData) {
this.swiperText = SearchText[this.swiperIndex].searchText.toString();
}
// 退出编辑态
this.controller.stopEditing()
})
5、当输入框热搜词文字过长时,设置输入框右边内容显示区域渐显效果,主要是用blendMode图像效果,将当前控件的内容与下方画布已有内容进行混合。.blendMode(BlendMode.SRC_IN, BlendApplyType.OFFSCREEN),SRC_IN只显示源像素中与目标像素重叠的部分,然后通过通用属性linearGradient设置颜色渐变效果
// 使用Stack堆叠Swiper和TextInput组件。
Swiper() {
// 使用ForEach组件循环搜索关键字数据
ForEach(SearchText, (item: SearchTextModel) => {
Row() {
Text(item.searchText)
...
}
.blendMode(BlendMode.SRC_IN, BlendApplyType.OFFSCREEN)
.backgroundColor(Color.Transparent)
}, (item: SearchTextModel) => item.id.toString())
}
// 设置文字右端显隐
.linearGradient({
angle: 90,
colors: [['rgba(0, 0, 0, 0)', 0], ['rgba(0, 0, 0, 1)', 0], ['rgba(0, 0, 0, 1)', 0.85],
['rgba(0, 0, 0, 0)', 1]]
})
.blendMode(BlendMode.SRC_OVER, BlendApplyType.OFFSCREEN)
场景二:TextInput修改placeholder提示文字的大小
给placeholder提示文字设置颜色以及文字大小
效果图
方案
使用TextInput的属性placeholderFont设置placeholder文本样式,包括字体大小,字体粗细,字体族,字体风格。目前仅支持默认字体族;placeholderColor属性设置颜色。
TextInput({ text: this.textOne, placeholder: 'placeholder', controller: this.controller })
.placeholderColor(Color.Pink)
.placeholderFont({ size: 18, weight: 400 })
场景三:TextInput输入的时候,当文字达到一定数量的时候,自动失去焦点,收起键盘
当输入框内容字符达到一定数量时,自动失去焦点,收起键盘
效果图
方案
主要是在onChange中通过判断输入的字符长度大于某个数量时,利用TextInputController.stopEditing方法控制键盘关闭。
Text('场景3:当输入框字符超过20个自动失去焦点,收起键盘').fontSize(9).fontColor('#ff5d5252')
TextInput({ text: this.textThree, placeholder: 'input...', controller: this.controller })
.placeholderColor(Color.Grey)
.placeholderFont({ size: 18, weight: 400 })
.caretColor(Color.Blue)
.height(40)
.margin({ bottom: 30 })
.fontSize(14)
.fontColor(Color.Black)
.maxLength(20)
.onChange((value: string) => {
this.textThree = value
if (this.textThree.length >= 20) {
// 退出编辑状态
this.controller.stopEditing();
}
})
场景四:TextInput输入手机号码可以分段展示
正常输入手机号码时显示效果如:XXX XXXX XXXX当有特殊字符如+,*特殊字符时,不加空格显示,一般情况无需我们手动输入国际代码。
方案
1、设置输入框类型为PhoneNumber类型TextInput({ text:${this.text} }).type(InputType.PhoneNumber).height('48vp'),电话号码输入模式。支持输入数字、空格、+ 、-、*、#,长度不限。
2、判断输入的是否为空格,当输入空格的时候去除空格,自定义一个判断方法如下:
// 判断是否有空字符
isEmpty(str?: string): boolean {
return str == 'undefined' || !str || !new RegExp('[^\\s]').test(str);
}
// 移除空格
removeSpace(str: string): string {
// 判断输入是否为空
if (this.isEmpty(str)) {
return '';
}
// 当输入非空的时候去除之前的多余空格
return str.replace(new RegExp('[\\s]', 'g'), '');
}
3、判断是否有特殊字符,当有特殊字符的时候不加空格,自定义判断方法如下:
// 电话号码输入模式。支持输入数字、空格、+ 、-、*、#,长度不限。
// 校验是否需要空格,具体匹配规则可以由业务需求自己设置 .*代表匹配除换行符之外的所有字符
checkNeedNumberSpace(numText: string) {
let isSpace: RegExp = new RegExp('[\\+;,#\\*]', 'g');
let isRule: RegExp = new RegExp('^\\+.*,\\+');
// 如果全局有特殊符号
if (isSpace.test(numText)) {
// 如果电话号码里有特殊字符,就不加空格
if (isRule.test(numText)) {
return true;
} else {
return false;
}
}
return true;
}
4、关于输入框内容分段显示主要是在onChange回调中实现,首先给输入的文字去除空格,然后通过判断是否有特殊字符来显示输入框效果,当有特殊字符时不展示分段效果,当没有特殊字符时分段展示手机号,核心代码如下:
TextInput({ text: `${this.text}` }).type(InputType.PhoneNumber).height('48vp')
.onChange((number: string) => {
let teleNumberNoSpace: string = this.removeSpace(number);
if (teleNumberNoSpace.length > this.NUM_TEXT_MAXSIZE_LENGTH - 2) {
// 如果超过了电话号码数字就直接为去空格的输入字符
this.text = teleNumberNoSpace;
} else if (this.checkNeedNumberSpace(number)) {
if (teleNumberNoSpace.length <= 3) {
this.text = teleNumberNoSpace;
} else {
let split1: string = teleNumberNoSpace.substring(0, 3);
let split2: string = teleNumberNoSpace.substring(3);
this.text = split1 + ' ' + split2;
// 输入号码长度大于3时
// String 的 substring() 方法返回该字符串从起始索引到结束索引(不包括)的部分,如果未提供结束索引,则返回到字符串末尾的部分。
// 输入号码长度大于3小于7时,截取前三位+后四位
if (teleNumberNoSpace.length > 7) {
split2 = teleNumberNoSpace.substring(3, 7);
let split3: string = teleNumberNoSpace.substring(7);
this.text = split1 + ' ' + split2 + ' ' + split3;
}
}
} else {
this.text = number;
}
})
场景五:输入框右边清除内容按钮
当输入框又内容显示时会显示右侧小图标,点击右侧图标会清空输入框内容,图标可以根据实际情况自行更改。
效果图
方案
当输入框输入文字时,右侧显示删除清空内容按钮,主要利用textInput属性cancelButton,该属性设置右侧清除按钮样式,不支持内联模式。
TextInput({ text: this.textThree, placeholder: 'clear input ...', controller: this.controller })
.height(40)
.margin({ bottom: 20 })
.cancelButton({
style: CancelButtonStyle.INPUT, // 清除按钮输入样式
icon: {
size: 22,
src: $r('app.media.clear'),
color: Color.Blue
}
})
.onChange((value: string) => {
this.textThree = value
})
场景六:自定义密码图标的样式
点击眼睛图标动态切换图标样式以及设置密码的显隐状态
效果图
方案
通过状态变量动态改变图标样式,然后给输入框设置不显示默认的密码图标 .showPasswordIcon(false),图标动态切换接合密码的显隐状态.showPassword(this.changeState)来达到自定义密码图标的效果。
Row({
Image(this.imgRes).width(35).height(35).onClick(() => {
this.changeState = !this.changeState;
// 点击图标动态改变图片
if (this.changeState) {
this.imgRes = this.openEye;
} else {
this.imgRes = this.closeEys;
}
})
TextInput({ text: this.textSix, controller: this.TextInputController })
.type(this.changeType)
.placeholderFont({ size: 16, weight: 400 })
// 不显示密码模式下的输入框末尾的图标
.showPasswordIcon(false)
.height(40)
.width(300)
.borderRadius(20)
.margin(2)
.border({ width: 1 })
.onChange((value: string) => {
this.textSix = value;
})
// 设置密码的显隐状态
.showPassword(this.changeState)
}
.alignItems(VerticalAlign.Center)
.justifyContent(FlexAlign.Center)
.height(50)
.width(350)