1# 自定义输入框 2## 场景介绍 3输入框是一种常见的场景,开发者为了丰富其多样性,在输入框中的占位符、下划线做了相关处理。本文即为大家介绍如何开发自定义输入框。 4## 效果呈现 5效果图如下: 6 7 8 9## 运行环境 10本例基于以下环境开发,开发者也可以基于其他适配的版本进行开发: 11- IDE: DevEco Studio 3.2 Release 12- SDK: Ohos_sdk_public 3.2.12.5 (API Version 9 Release) 13## 实现思路 14- 点击输入框,提示文字向上浮动并同时改变文字颜色,输入框底线进行匀速放缩:通过监听输入框状态(onEditChange)发生变化时,提示文字向上浮动以及底部线进行放缩,同时改变文字和底部线的颜色。 15- 在输入文本时,输入框右侧显示“清除”图标。点击“清空”图标,清空输入文本:通过监听输入框中有文本输入(onChange)时,右侧显示“清除”图标。 16## 开发步骤 171. 封装TextInput组件去监听onEditChange事件(输入状态的变化)和onchange事件(输入内容的变化)。具体代码块如下: 18 ```ts 19 TextInput({text:this.textValue}) 20 .width('100%') 21 .height('100%') 22 .borderRadius(0) 23 .borderColor('#86C7CC') 24 .borderWidth({bottom: 1}) 25 .backgroundColor(Color.Transparent) 26 .type(this.typeInput) 27 .showPasswordIcon(false) 28 // 输入内容发生变化 29 .onEditChange((isEditing)=>{ 30 this.isEditing = isEditing 31 this.isFloatHint = this.isEditing || this.textValue !=='' 32 }) 33 // 输入状态变化时 34 .onChange((value)=>{ 35 this.textValue = value 36 this.isFloatHint = this.isEditing || this.textValue !== '' 37 }) 38 ``` 392. 输入状态发生变化(onEditChange)时,提示文字向上浮动并同时改变颜色;输入框底线匀速放缩并改变颜色。具体代码如下: 40 ```ts 41 // 提示文本(占位符) 42 Text(this.placeholder) 43 .enabled(false) 44 .fontColor(this.isFloatHint ? '#5D7DB3' : '#E1E4EA') 45 .position({x: 0, y: this.isFloatHint ? 0 : '50%'}) 46 .translate({x: 15, y: '-50%'}) 47 .animation({duration:100, curve: Curve.Linear}) 48 49 // 底部线 50 Line() 51 .width('100%') 52 .height(1) 53 .backgroundColor('#5D7DB3') 54 .position({x: 0, y: 44}) 55 .scale({x: this.isFloatHint ? 1 : 0, centerX: 0}) 56 .animation({duration: 300, curve: Curve.Linear}) 57 ``` 583. 输入内容发生变化(onChange)时,输入框右侧显示“清除”图标,点击该图标清空输入框内容。具体代码块如下: 59 ```ts 60 if (this.textValue){ 61 Image($r("app.media.canel")) 62 .width(15) 63 .height(15) 64 .border({width: 1, radius: 15, color: '#fffffff'}) 65 .position({x: '90%', y: '50%'}) 66 .translate({y: '-50%'}) 67 .onClick(()=>{ 68 this.textValue = '' 69 }) 70 } 71 ``` 724. 构建界面UI。具体代码块如下: 73 ```ts 74 @Entry 75 @Component 76 struct InputFloatHintPage{ 77 build(){ 78 Column(){ 79 Text('欢迎使用') 80 .fontSize(50) 81 .fontColor('#91B5A9') 82 Column(){ 83 InputFloatHint({placeholder: '请输入用户名'}) 84 Blank().height(30) 85 InputFloatHint({placeholder: '请输入密码'}) 86 Column() { 87 Row() { 88 Checkbox() 89 .select(false) 90 .selectedColor(0x39a2db) 91 .padding({left:1}) 92 Text('免密登录') 93 Blank().width(150) 94 Text('忘记密码') 95 .fontColor('#5C9DBA') 96 } 97 }.justifyContent(FlexAlign.SpaceBetween) 98 Blank().height(50) 99 Button('登录').width(150) 100 } 101 .width('90%') 102 .padding(30) 103 .backgroundColor(Color.White) 104 .border({radius: 10}) 105 .shadow({radius: 10, color: '#5C9DBA' }) 106 }.width('100%') 107 .height('100%') 108 .justifyContent(FlexAlign.Center) 109 } 110 } 111 ``` 112## 完整代码 113完整示例代码如下: 114```ts 115@Component 116struct InputFloatHint{ 117 @State isFloatHint: boolean = false 118 @State textValue: string = '' 119 isEditing = false 120 placeholder: string 121 typeInput:InputType = InputType.Normal 122 123 build(){ 124 Stack(){ 125 TextInput({text:this.textValue}) 126 .width('100%') 127 .height('100%') 128 .borderRadius(0) 129 .borderColor('#86C7CC') 130 .borderWidth({bottom: 1}) 131 .backgroundColor(Color.Transparent) 132 .type(this.typeInput) 133 .showPasswordIcon(false) 134 .onEditChange((isEditing)=>{ 135 this.isEditing = isEditing 136 this.isFloatHint = this.isEditing || this.textValue !=='' 137 }) 138 .onChange((value)=>{ 139 this.textValue = value 140 this.isFloatHint = this.isEditing || this.textValue !== '' 141 }) 142 Text(this.placeholder) 143 .enabled(false) 144 .fontColor(this.isFloatHint ? '#5D7DB3' : '#E1E4EA') 145 .position({x: 0, y: this.isFloatHint ? 0 : '50%'}) 146 .translate({x: 15, y: '-50%'}) 147 .animation({duration:100, curve: Curve.Linear}) 148 149 Line() 150 .width('100%') 151 .height(1) 152 .backgroundColor('#5D7DB3') 153 .position({x: 0, y: 44}) 154 .scale({x: this.isFloatHint ? 1 : 0, centerX: 0}) 155 .animation({duration: 300, curve: Curve.Linear}) 156 157 if (this.textValue){ 158 Image($r("app.media.canel")) 159 .width(15) 160 .height(15) 161 .border({width: 1, radius: 15, color: '#fffffff'}) 162 .position({x: '90%', y: '50%'}) 163 .translate({y: '-50%'}) 164 .onClick(()=>{ 165 this.textValue = '' 166 }) 167 } 168 }.width('100%').height(45) 169 } 170} 171 172@Entry 173@Component 174struct InputFloatHintPage{ 175 build(){ 176 Column(){ 177 Text('欢迎使用') 178 .fontSize(50) 179 .fontColor('#91B5A9') 180 Column(){ 181 InputFloatHint({placeholder: '账号'}) 182 Blank().height(30) 183 InputFloatHint({placeholder: '密码'}) 184 Blank().height(50) 185 Button('登录').width(150) 186 } 187 .width('90%') 188 .padding(30) 189 .backgroundColor(Color.White) 190 .border({radius: 10}) 191 .shadow({radius: 10, color: '#5C9DBA' }) 192 }.width('100%') 193 .height('100%') 194 .justifyContent(FlexAlign.Center) 195 } 196} 197``` 198 199## 参考 200[图形变换](../application-dev/reference/apis-arkui/arkui-ts/ts-universal-attributes-transformation.md) 201 202[TextInput](../application-dev/reference/apis-arkui/arkui-ts/ts-basic-components-textinput.md) 203