HarmonyOS鸿蒙Next中如何解决TextArea的默认提示语与新输入的文本重叠问题
HarmonyOS鸿蒙Next中如何解决TextArea的默认提示语与新输入的文本重叠问题
【问题现象】
期望在文本输入时,默认提示语一直保持显示在新文本输入前面;默认提示语使用Text组件放置,其位置固定,当新输入文本字数过多可以上下滑动时,默认提示语和新输入文本重叠,如下图:
问题代码如下:
Stack({ alignContent: Alignment.TopStart }) {
Text('占位文本')
.margin({ top: 8, left: 14 })
.fontColor(Color.Red)
.fontSize(15)
.onAreaChange((oldValue: Area, newValue: Area) => {
this.txtWidth = newValue.width as number
})
TextArea({ text: "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" })
.width(300)
.textIndent(this.txtWidth)
}
【背景知识】
- 显示一段文本的组件Text;
- 多行文本输入框组件TextArea;
- UI容器组件的特性:例如使用堆叠容器Stack,子组件按照顺序依次入栈,后一个子组件覆盖前一个子组件。
【定位思路】
当输入文本内容过多、超出最大显示行数时,新输入文本可滚动显示;但由于默认提示语Text和新输入文本TextArea同包在stack之中,当涉及位置滑动时,默认提示语 Text 位置不随文本输入框移动。
因此想要解决这个问题,需要在滑动新输入文本的同时移动默认提示语Text的位置。
【解决方案】
通过新输入文本TextArea的onContentScroll属性,获取文本超出最大显示行数时文本滚动的距离,将其传给默认提示语Text的offset属性,使得默认提示语随输入文本滚动。
修改结果:
在文本输入框中加入默认提示语,该文字在文本首行中持续显示,随文本下滑而滑出界面,如下图所示:
代码示例如下:
@Entry
@Component
struct Page240911220842047 {
@State txt: string = '占位文本'
@State text: string = ' '
@State textValue: string = ''
@State txtWidth: number = 0
@State offsetY: number = 0
controller: TextAreaController = new TextAreaController()
build() {
Row() {
Column() {
Stack({ alignContent: Alignment.TopStart }) {
Column() {
Text(this.txt)
.margin({ left: 14 })
.fontSize(15)
.fontColor(Color.Red)
.onAreaChange((oldValue: Area, newValue: Area) => {
this.txtWidth = newValue.width as number
})
.offset({ x: 0, y: this.offsetY })
}
.width(300)
.height(92)
.alignItems(HorizontalAlign.Start)
.border({ width: 1 })
.margin({ top: 8 })
.clip(true)
TextArea({ text: this.text, controller: this.controller })
.width(300)
.height(100)
.textIndent(this.txtWidth)
.onChange((info) => {
this.text = info
this.textValue = this.text.trim()
})
.onContentScroll((totalOffsetX: number, totalOffsetY: number) => {
if ((px2vp(totalOffsetY) - 8) > 0) {
this.offsetY = 0
} else if ((px2vp(totalOffsetY) - 8) < -16) {
this.offsetY = -16
} else {
this.offsetY = (px2vp(totalOffsetY) - 8)
}
})
.onWillDelete((info: DeleteValue) => {
if (info.deleteOffset === 1 || this.text === ' ') {
return false
}
return true;
})
.onDidDelete((info: DeleteValue) => {
if (info.deleteOffset === 0) {
this.text = ' '
}
})
.onTextSelectionChange((selectionStart: number, selectionEnd: number) => {
if (selectionStart === 0) {
selectionStart === selectionEnd ? this.controller.caretPosition(1) : this.controller.setTextSelection(1, selectionEnd)
}
})
}
}
.width('100%')
}
.height('100%')
}
}
【总结】
前文提供了默认提示语和新输入文本同时存在场景下的文本输入方案,常见的默认提示语和文本输入方案还有:默认提示语和输入文本不属于同一个文本,占位文字独立于输入框文字并保持显示,用于实现某种类型的文案输入。这是通过设置padding属性使得文本输入TextArea之后,效果如图:
代码示例如下:
Stack({
Text(this.txt)
.margin({ top: 8, left: 14 })
.fontColor(Color.Red)
.fontSize(15)
.onAreaChange((oldValue: Area, newValue: Area) => {
this.txtWidth = newValue.width as number
})
TextArea({ text: "我是TextArea我是TextArea我是TextArea我是TextArea" })
.width(300)
.padding({ left: this.txtWidth + 15 })
}
如果是无输入时显示默认提示语,有输入时默认提示语消除的场景,可以使用多行输入文本组件TextArea的已有属性placeholder:设置无输入时的提示文本。输入内容后,提示文本不显示。如图:
代码示例如下:
TextArea({
text: this.text,
placeholder: 'The text area can hold an unlimited amount of text. input your word...',
controller: this.controller
})
.placeholderFont({ size: 16, weight: 400 })
该属性无法满足时刻显示默认提示语,这时需要根据组件的事件及整体 UI 容器组件的特性完成定制化场景设计。
更多关于HarmonyOS鸿蒙Next中如何解决TextArea的默认提示语与新输入的文本重叠问题的实战教程也可以访问 https://www.itying.com/category-93-b0.html
更多关于HarmonyOS鸿蒙Next中如何解决TextArea的默认提示语与新输入的文本重叠问题的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html
通过TextArea的onContentScroll属性获取文本滚动的距离
通过TextArea的onContentScroll
属性获取文本滚动的距离,将其传给默认提示语Text的offset
属性,使默认提示语随输入文本滚动。代码示例如下:
@Entry
@Component
struct Page240911220842047 {
@State txt: string = '占位文本'
@State text: string = ' '
@State textValue: string = ''
@State txtWidth: number = 0
@State offsetY: number = 0
controller: TextAreaController = new TextAreaController()
build() {
Row() {
Column() {
Stack({ alignContent: Alignment.TopStart }) {
Column() {
Text(this.txt)
.margin({ left: 14 })
.fontSize(15)
.fontColor(Color.Red)
.onAreaChange((oldValue: Area, newValue: Area) => {
this.txtWidth = newValue.width as number
})
.offset({ x: 0, y: this.offsetY })
}
.width(300)
.height(92)
.alignItems(HorizontalAlign.Start)
.border({ width: 1 })
.margin({ top: 8 })
.clip(true)
TextArea({ text: this.text, controller: this.controller })
.width(300)
.height(100)
.textIndent(this.txtWidth)
.onChange((info) => {
this.text = info
this.textValue = this.text.trim()
})
.onContentScroll((totalOffsetX: number, totalOffsetY: number) => {
if ((px2vp(totalOffsetY) - 8) > 0) {
this.offsetY = 0
} else if ((px2vp(totalOffsetY) - 8) < -16) {
this.offsetY = -16
} else {
this.offsetY = (px2vp(totalOffsetY) - 8)
}
})
}
}
.width('100%')
}
.height('100%')
}
}