Android/Java 实现
创建布局文件 activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<com.java.clear.widget.ClearEditText
android:id="@+id/etUserName"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="10dp"
android:layout_marginTop="60dp"
android:layout_marginRight="10dp"
android:background="@drawable/edit_round_corner_bg"
android:drawableLeft="@drawable/icon_user"
android:drawableRight="@drawable/delete_selector"
android:hint="输入用户名"
android:inputType="number"
android:maxLength="11"
android:padding="10dp"
android:singleLine="true"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<com.java.clear.widget.ClearEditText
android:id="@+id/etPwd"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="10dp"
android:layout_marginTop="10dp"
android:layout_marginRight="10dp"
android:background="@drawable/edit_round_corner_bg"
android:drawableLeft="@drawable/icon_user"
android:drawableRight="@drawable/delete_selector"
android:hint="请输入密码"
android:inputType="textPassword"
android:maxLength="11"
android:padding="10dp"
android:singleLine="true"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@+id/etUserName" />
<com.java.clear.widget.ClearEditText
android:id="@+id/etInvCode"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="10dp"
android:layout_marginTop="10dp"
android:layout_marginRight="10dp"
android:background="@drawable/edit_round_corner_bg"
android:drawableLeft="@drawable/icon_user"
android:drawableRight="@drawable/delete_selector"
android:hint="请输入邀请码"
android:inputType="text"
android:maxLength="11"
android:padding="10dp"
android:singleLine="true"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@+id/etPwd" />
<com.java.clear.widget.ClearEditText
android:id="@+id/etRemark"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="10dp"
android:layout_marginTop="10dp"
android:layout_marginRight="10dp"
android:background="@drawable/edit_round_corner_bg"
android:drawableLeft="@drawable/icon_user"
android:drawableRight="@drawable/delete_selector"
android:hint="请输入备注"
android:inputType="text"
android:maxLength="30"
android:padding="10dp"
android:singleLine="true"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@+id/etInvCode" />
<androidx.appcompat.widget.AppCompatButton
android:id="@+id/btnSubmit"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:layout_marginLeft="20dp"
android:layout_marginRight="20dp"
android:text="提交"
android:alpha="0.3"
android:textColor="@color/white"
android:background="@drawable/button_round_corner_bg"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@+id/etRemark" />
</androidx.constraintlayout.widget.ConstraintLayout>
通过TextWatcher监听编辑框变化
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.AppCompatButton;
import android.os.Bundle;
import android.text.Editable;
import android.text.TextWatcher;
import com.java.clear.widget.ClearEditText;
public class MainActivity extends AppCompatActivity {
// 用户名、密码、邀请码、备注
private ClearEditText etUserName, etPwd, etInvCode, etRemark;
// 提交按钮
private AppCompatButton btnSubmit;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();
}
private void initView() {
etUserName = findViewById(R.id.etUserName);
etPwd = findViewById(R.id.etPwd);
etInvCode = findViewById(R.id.etInvCode);
etRemark = findViewById(R.id.etRemark);
btnSubmit = findViewById(R.id.btnSubmit);
etUserName.addTextChangedListener(textWatcher);
etPwd.addTextChangedListener(textWatcher);
etInvCode.addTextChangedListener(textWatcher);
etRemark.addTextChangedListener(textWatcher);
}
final TextWatcher textWatcher = new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
// 在文本改变之前不需要做什么
}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
// 文本改变时也不需要做什么
}
@Override
public void afterTextChanged(Editable s) {
changeBtnStatus();
}
};
private void changeBtnStatus() {
boolean etUserNameIsEmpty = editIsEmpty(etUserName);
boolean etPwdIsEmpty = editIsEmpty(etPwd);
boolean etInvCodeIsEmpty = editIsEmpty(etInvCode);
boolean etRemarkIsEmpty = editIsEmpty(etRemark);
// 当文本改变之后,检查所有EditText是否都不为空,并更改按钮颜色和可点击状态
if (!etUserNameIsEmpty && !etPwdIsEmpty && !etInvCodeIsEmpty && !etRemarkIsEmpty) {
btnSubmit.setAlpha(1.0f); // 表示可以点击
btnSubmit.setEnabled(false);
} else {
btnSubmit.setAlpha(0.3f); // 表示不可点击
btnSubmit.setEnabled(true);
}
}
// 判断编辑框是否为空
private boolean editIsEmpty(ClearEditText editText) {
return editText.getText().toString().trim().isEmpty();
}
}
预览效果
Android Kotlin 实现
创建布局文件 activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<com.kotlin.clear.widget.ClearEditText
android:id="@+id/etUserName"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="10dp"
android:layout_marginTop="60dp"
android:layout_marginRight="10dp"
android:background="@drawable/edit_round_corner_bg"
android:drawableLeft="@drawable/icon_user"
android:drawableRight="@drawable/delete_selector"
android:hint="输入用户名"
android:inputType="number"
android:maxLength="11"
android:padding="10dp"
android:singleLine="true"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<com.kotlin.clear.widget.ClearEditText
android:id="@+id/etPwd"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="10dp"
android:layout_marginTop="10dp"
android:layout_marginRight="10dp"
android:background="@drawable/edit_round_corner_bg"
android:drawableLeft="@drawable/icon_user"
android:drawableRight="@drawable/delete_selector"
android:hint="请输入密码"
android:inputType="textPassword"
android:maxLength="11"
android:padding="10dp"
android:singleLine="true"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@+id/etUserName" />
<com.kotlin.clear.widget.ClearEditText
android:id="@+id/etInvCode"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="10dp"
android:layout_marginTop="10dp"
android:layout_marginRight="10dp"
android:background="@drawable/edit_round_corner_bg"
android:drawableLeft="@drawable/icon_user"
android:drawableRight="@drawable/delete_selector"
android:hint="请输入邀请码"
android:inputType="text"
android:maxLength="11"
android:padding="10dp"
android:singleLine="true"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@+id/etPwd" />
<com.kotlin.clear.widget.ClearEditText
android:id="@+id/etRemark"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="10dp"
android:layout_marginTop="10dp"
android:layout_marginRight="10dp"
android:background="@drawable/edit_round_corner_bg"
android:drawableLeft="@drawable/icon_user"
android:drawableRight="@drawable/delete_selector"
android:hint="请输入备注"
android:inputType="text"
android:maxLength="30"
android:padding="10dp"
android:singleLine="true"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@+id/etInvCode" />
<androidx.appcompat.widget.AppCompatButton
android:id="@+id/btnSubmit"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:layout_marginLeft="20dp"
android:layout_marginRight="20dp"
android:text="提交"
android:alpha="0.3"
android:textColor="@color/white"
android:background="@drawable/button_round_corner_bg"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@+id/etRemark" />
</androidx.constraintlayout.widget.ConstraintLayout>
通过TextWatcher监听编辑框变化
import android.os.Bundle
import android.text.Editable
import android.text.TextWatcher
import android.util.Log
import androidx.appcompat.app.AppCompatActivity
import androidx.appcompat.widget.AppCompatButton
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.repeatOnLifecycle
import com.kotlin.clear.widget.ClearEditText
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.launch
enum class Number(var num: Int) {
userName(1),
pwd(2),
invCode(3),
reamrk(4)
}
class MainActivity : AppCompatActivity() {
private val userNameState = MutableStateFlow(false)
private val pwdState = MutableStateFlow(false)
private val invCodeState = MutableStateFlow(false)
private val remarkState = MutableStateFlow(false)
// 用户名、密码、邀请码、备注
private var etUserName: ClearEditText? = null
private var etPwd: ClearEditText? = null
private var etInvCode: ClearEditText? = null
private var etRemark: ClearEditText? = null
// 提交按钮
private var btnSubmit: AppCompatButton? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
initView()
lifecycleScopeLaunch()
}
private fun lifecycleScopeLaunch() {
lifecycleScope.launch {
//androidx.fragment:fragment-ktx:1.5.6
repeatOnLifecycle(Lifecycle.State.STARTED) {
combine(
userNameState,
pwdState,
invCodeState,
remarkState,
) {booleans ->
}.collectLatest {
val isEnabled = (userNameState.value
&& pwdState.value && invCodeState.value &&
remarkState.value);
btnSubmit?.isEnabled = isEnabled;
btnSubmit?.alpha = if (isEnabled) 1.0f else 0.3f
Log.i("MainActivity", "collectLatest $isEnabled")
}
}
}
}
private fun initView() {
etUserName = findViewById(R.id.etUserName)
etPwd = findViewById(R.id.etPwd)
etInvCode = findViewById(R.id.etInvCode)
etRemark = findViewById(R.id.etRemark)
btnSubmit = findViewById(R.id.btnSubmit)
etUserName?.addTextChangedListener(textWatcher(Number.userName))
etPwd?.addTextChangedListener(textWatcher(Number.pwd))
etInvCode?.addTextChangedListener(textWatcher(Number.invCode))
etRemark?.addTextChangedListener(textWatcher(Number.reamrk))
btnSubmit?.setOnClickListener {
Log.i("MainActivity", "按钮可点击。。。。。。")
}
}
private fun textWatcher(num: Number): TextWatcher {
return object : TextWatcher {
override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {
// 在文本改变之前不需要做什么
}
override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {
// 文本改变时也不需要做什么
}
override fun afterTextChanged(s: Editable) {
//Log.i("MainActivity","afterTextChanged $num");
when (num) {
Number.userName -> {
val value = etUserName?.text.toString().trim().isEmpty()
userNameState.value = !value
}
Number.pwd -> {
val value = etPwd?.text.toString().trim().isEmpty()
pwdState.value = !value
}
Number.invCode -> {
val value = etInvCode?.text.toString().trim().isEmpty()
invCodeState.value = !value
}
Number.reamrk -> {
val value = etRemark?.text.toString().trim().isEmpty()
remarkState.value = !value
}
}
}
}
}
}
预览效果
IOS Object-c 实现
自定义MyTextField
创建 用户 编辑框视图
创建 密码 编辑框视图
实现 监听编辑框的代理 UITextFieldDelegate
实现 函数 shouldChangeCharactersInRange 限制编辑框的文本格式和登录按钮的点击状态:
实现 函数 textFieldShouldClear监听编辑框一键删除时改变登录按钮点击状态:
实现显示和隐藏密码
预览效果
IOS Swift 实现
自定义MyTextField
创建 用户 编辑框视图
创建 密码 编辑框视图
实现 监听编辑框的代理 UITextFieldDelegate
实现 函数 shouldChangeCharactersInRange 限制编辑框的文本格式和登录按钮的点击状态:
实现 函数 textFieldShouldClear监听编辑框一键删除时改变登录按钮点击状态:
实现显示和隐藏密码
预览效果
Android Compose 实现编辑框
创建 compose ComponentActivity
配置插件依赖版本
创建用户名 编辑框
创建 密码 编辑框
创建 登录 点击按钮
使用 用户名、密码 编辑框
编辑框 实现代码
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.animation.core.LinearOutSlowInEasing
import androidx.compose.animation.core.animateDp
import androidx.compose.animation.core.keyframes
import androidx.compose.animation.core.updateTransition
import androidx.compose.foundation.border
import androidx.compose.foundation.clickable
import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.offset
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.foundation.text.BasicTextField
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.AccountCircle
import androidx.compose.material.icons.filled.Close
import androidx.compose.material3.Button
import androidx.compose.material3.ButtonDefaults
import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.MutableState
import androidx.compose.runtime.Stable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.SolidColor
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import com.kotlin.edittext.ui.theme.AndroidComposeClearEditTextTheme
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
AndroidComposeClearEditTextTheme {
Surface(
modifier = Modifier.fillMaxSize(),
color = MaterialTheme.colorScheme.background
) {
// todo 登录 按钮是否可以点击
val buttonEnabled = remember { mutableStateOf(false) }
var shake by remember { mutableStateOf(false) }
// todo 输入用户名
val userNameState = rememberSaveable { mutableStateOf("") }
// todo 输入密码
val passWordState = rememberSaveable { mutableStateOf("") }
val transition = updateTransition(targetState = shake, label = "shake")
val shakeOffset by transition.animateDp(label = "",
transitionSpec = {
keyframes {
durationMillis = 300
0.dp at 0
(-10).dp at 25 with LinearOutSlowInEasing
0.dp at 50
10.dp at 75
0.dp at 100
(-8).dp at 125
0.dp at 150
8.dp at 175
0.dp at 200
(-5).dp at 225
0.dp at 250
5.dp at 275
0.dp at 300
}
}) {
if (it) 0.dp else 0.dp
}
Column {
DecorateUserNameTextField(
shakeOffset = shakeOffset,
userNameState = userNameState,
passWordState = passWordState,
buttonEnabled = buttonEnabled
)
DecoratePassWordTextField(
shakeOffset = shakeOffset,
userNameState = userNameState,
passWordState = passWordState,
buttonEnabled = buttonEnabled
)
RoundedCornerClickText(onClick = {
shake = !shake
}, buttonEnabled = buttonEnabled)
}
}
}
}
}
}
@Composable
fun DecorateUserNameTextField(
shakeOffset: Dp, userNameState: MutableState<String>, passWordState: MutableState<String>,
buttonEnabled: MutableState<Boolean>
) {
Box(
Modifier
.padding(start = 10.dp, end = 10.dp, top = 20.dp)
.fillMaxWidth()
.offset(x = shakeOffset),
contentAlignment = Alignment.TopCenter
) {
BasicTextField(
value = userNameState.value,
onValueChange = {
userNameState.value = it
//todo 通过输入用户名、密码 控制点击按钮颜色
buttonEnabled.value =
(userNameState.value.isNotEmpty() && passWordState.value.isNotEmpty())
},
textStyle = TextStyle(color = Color.Black),
cursorBrush = SolidColor(Color.Blue),
decorationBox = { innerTextField ->//decorationBox内部负责编写输入框样式
Row(
Modifier
.fillMaxWidth()
.height(50.dp)
.border(0.3.dp, Color.Blue, RoundedCornerShape(10.dp)),
verticalAlignment = Alignment.CenterVertically
) {
Spacer(Modifier.width(5.dp))
Icon(
Icons.Default.AccountCircle,
tint = Color.Black,
contentDescription = null
)
Spacer(Modifier.width(5.dp))
Box(modifier = Modifier.padding(top = 7.dp, bottom = 7.dp, end = 7.dp)) {
// 判断是否输入文本,如果输入则清空隐藏提示
if (userNameState.value.isEmpty()) {
Text(
text = "请输入用户名",
style = TextStyle(
color = Color(0, 0, 0, 128),
fontSize = 16.sp,
)
)
}
//自定义样式这行代码是关键,没有这一行输入文字后无法展示,光标也看不到
innerTextField()
}
}
}
)
// 编辑框存在文本值
if (userNameState.value.isNotEmpty()) {
// 添加一个清除按钮,点击时清除文本
val interactionSource = remember { MutableInteractionSource() }
Box(
modifier = Modifier
.align(Alignment.CenterEnd)
.clickable(
interactionSource = interactionSource,
indication = null
) {
userNameState.value = ""
//todo 通过输入用户名、密码 控制点击按钮颜色
buttonEnabled.value =
(userNameState.value.isNotEmpty() && passWordState.value.isNotEmpty())
}
.padding(end = 8.dp) // 根据需要调整内边距
) {
Icon(
imageVector = Icons.Default.Close, // 使用合适的图标
contentDescription = "clear",
modifier = Modifier.size(24.dp), // 根据需要调整图标大小
tint = Color.Unspecified // 根据需要调整颜色
)
}
}
}
}
@Composable
fun DecoratePassWordTextField(
shakeOffset: Dp, userNameState: MutableState<String>, passWordState: MutableState<String>,
buttonEnabled: MutableState<Boolean>
) {
Box(
Modifier
.padding(start = 10.dp, end = 10.dp, top = 20.dp)
.fillMaxWidth()
.offset(x = shakeOffset),
contentAlignment = Alignment.TopCenter
) {
BasicTextField(
value = passWordState.value,
onValueChange = {
passWordState.value = it
//todo 通过输入用户名、密码 控制点击按钮颜色
buttonEnabled.value =
(userNameState.value.isNotEmpty() && passWordState.value.isNotEmpty())
},
textStyle = TextStyle(color = Color.Black),
cursorBrush = SolidColor(Color.Blue),
decorationBox = { innerTextField ->//decorationBox内部负责编写输入框样式
Row(
Modifier
.fillMaxWidth()
.height(50.dp)
.border(0.3.dp, Color.Blue, RoundedCornerShape(10.dp)),
verticalAlignment = Alignment.CenterVertically
) {
Spacer(Modifier.width(5.dp))
Icon(
Icons.Default.AccountCircle,
tint = Color.Black,
contentDescription = null
)
Spacer(Modifier.width(5.dp))
Box(modifier = Modifier.padding(top = 7.dp, bottom = 7.dp, end = 7.dp)) {
// 判断是否输入文本,如果输入则清空隐藏提示
if (passWordState.value.isEmpty()) {
Text(
text = "请输入密码",
style = TextStyle(
color = Color(0, 0, 0, 128),
fontSize = 16.sp,
)
)
}
//自定义样式这行代码是关键,没有这一行输入文字后无法展示,光标也看不到
innerTextField()
}
}
}
)
// 编辑框存在文本值
if (passWordState.value.isNotEmpty()) {
// 添加一个清除按钮,点击时清除文本
val interactionSource = remember { MutableInteractionSource() }
Box(
modifier = Modifier
.align(Alignment.CenterEnd)
.clickable(
interactionSource = interactionSource,
indication = null
) {
passWordState.value = ""
//todo 通过输入用户名、密码 控制点击按钮颜色
buttonEnabled.value =
(userNameState.value.isNotEmpty() && passWordState.value.isNotEmpty())
}
.padding(end = 8.dp) // 根据需要调整内边距
) {
Icon(
imageVector = Icons.Default.Close, // 使用合适的图标
contentDescription = "clear",
modifier = Modifier.size(24.dp), // 根据需要调整图标大小
tint = Color.Unspecified // 根据需要调整颜色
)
}
}
}
}
@Composable
fun RoundedCornerClickText(onClick: () -> Unit, buttonEnabled: MutableState<Boolean>) {
Box(modifier = Modifier.padding(start = 10.dp, end = 10.dp, top = 40.dp)) {
// todo 点击按钮的颜色
var buttonColor = if (buttonEnabled.value) {
Color.Green
} else {
Color.Green.copy(alpha = 0.3f)
}
Button(
modifier = Modifier
.fillMaxWidth()
.height(50.dp),
onClick = onClick,
enabled = buttonEnabled.value,
shape = RoundedCornerShape(5.dp),
colors = ButtonDefaults.buttonColors(buttonColor)
) {
Text(text = "登录", style = TextStyle(color = Color.White))
}
}
}
预览效果
鸿蒙实现 编辑框输入改变 登录按钮颜色
自定义编辑框 InputFloatHint
@Component
export struct InputFloatHint {
@State isFloatHint: boolean = false
@State textValue: string = ''
isEditing = false
placeholder: string
typeInput: InputType = InputType.Normal
maxLength: number=10 // todo 文本长度
callback: (value: string) => void // 编辑框输入 接口 回调
build() {
Stack() {
TextInput({ text: this.textValue,placeholder: this.placeholder, })
.width('100%')
.height('100%')
.borderRadius(22.5)
.borderColor('#86C7CC')
.maxLength(this.maxLength)
.borderWidth({ bottom: 1, top: 1, left: 1, right: 1 })
.backgroundColor(Color.Transparent)
.type(this.typeInput)
.showPasswordIcon(false)
.onEditChange((isEditing) => {
this.isEditing = isEditing
this.isFloatHint = this.isEditing || this.textValue !== ''
})
.onChange((value) => {
this.callback(value);
this.textValue = value
this.isFloatHint = this.isEditing || this.textValue !== ''
})
.borderColor(Color.Red)
if (this.textValue) {
Image($r("app.media.clear"))
.width(15)
.height(15)
.border({ width: 1, radius: 15, color: '#fffffff' })
.position({ x: '90%', y: '50%' })
.translate({ y: '-50%' })
.onClick(() => {
this.textValue = ''
})
}
}
.width('100%')
.height(45)
}
}
通过编辑框输入控制登录按钮点击状态
import { InputFloatHint } from './InputFloatHint'
@Entry
@Component
struct Index {
@State accountV: string = "" // todo 账号
@State passWordV: string = "" // todo 密码
// todo 判断编辑框输入的账号和密码是否为空
validate() {
return this.accountV !== "" && this.passWordV !== ""
}
build() {
Column() {
Column() {
InputFloatHint({
placeholder: '账号',
typeInput: InputType.Normal,
maxLength: 10,
callback: ((value) => {
console.log("编辑框输入用户名:"+value)
this.accountV = value
})
})
Blank().height(30)
InputFloatHint({
placeholder: '密码',
typeInput: InputType.Password,
maxLength: 6,
callback: ((value) => {
console.log("编辑框输入密码:"+value)
this.passWordV = value
})
})
Blank().height(50)
Button('登录')
.enabled(this.validate())
.width(150).onClick(() => {
// todo 处理点击事件逻辑
console.log("登录按钮点击事件......")
})
}
.width('90%')
}.width('100%')
.height('100%')
.justifyContent(FlexAlign.Center)
}
}
预览编辑框
ReactNative 实现 编辑框输入改变登录按钮颜色
import React, {Component,useRef,useEffect,useState,} from 'react';
import { AppRegistry,TextInput, Button,View,
StyleSheet,Image,TouchableOpacity,
Text,Animated,Easing} from 'react-native';
import {name as appName} from './app.json';
export default class TextInputComponent extends Component {
constructor(props) {
super(props);
this.state = {
inputAccountValue:'', // 用户名 编辑框 初始化值
inputPwdValue:''// 密码 编辑框 初始化值
}
// 绑定方法,确保this指向当前组件实例
this.clearAccountText = this.clearAccountText.bind(this);
}
// 清空 用户名 文本
clearAccountText=()=> {
this.setState({inputAccountValue:''});
}
// 清空 密码 文本
clearPasswordText=()=> {
this.setState({inputPwdValue:''});
}
render() {
// 用户名、密码 使用接口回调函数
this.props.onAccountPwdValueChange(this.state.inputAccountValue,this.state.inputPwdValue);
return (
<View>
<View style={styles.editView}>
<Image source={require('./assets/user_logo.png')} style={styles.editViewImage}/>
<TextInput
style={styles.input}
value={this.state.inputAccountValue}
onChangeText={(text)=>{this.setState({inputAccountValue:text})}}
placeholder="请输入编辑框用户名"
/>
{this.state.inputAccountValue && (<TouchableOpacity onPress={this.clearAccountText}>
<Image source={require('./assets/edit_delete.png')}
style={styles.deleteViewImage}
/>
</TouchableOpacity>
)}
</View>
<View style={styles.editView}>
<Image source={require('./assets/user_logo.png')} style={styles.editViewImage}/>
<TextInput
style={styles.input}
value={this.state.inputPwdValue}
onChangeText={(text)=>{this.setState({inputPwdValue:text})}}
placeholder="请输入编辑框密码"
/>
{this.state.inputPwdValue && (<TouchableOpacity onPress={this.clearPasswordText}>
<Image source={require('./assets/edit_delete.png')}
style={styles.deleteViewImage}
/>
</TouchableOpacity>
)}
</View>
</View>
)
}
}
// 抖动动画
const ShakeAnimation = () => {
const shakeAnimation = useRef(new Animated.Value(0)).current;
shake = () => {
// 定义动画:在X轴左右抖动
Animated.sequence([
Animated.timing(shakeAnimation, {
toValue: 3,
duration: 100,//毫秒
useNativeDriver: true,//使用原生动画驱动,默认不启用(false)
}),
Animated.timing(shakeAnimation, {
toValue: -3,
duration: 100,//毫秒
useNativeDriver: true,
}),
Animated.spring(shakeAnimation, {
toValue: 0,
useNativeDriver: true,
}),
]).start(); // 开始动画
};
const [buttonClicked, setButtonClicked] = useState(true);
// 应用动画值
const shakeStyle = {
transform: [
{
translateX: shakeAnimation.interpolate({
inputRange: [0, 1],
outputRange: [0, 3], // 抖动的幅度
}),
},
],
};
return (<View style={styles.container}>
<Animated.View style={shakeStyle}>
<TextInputComponent onAccountPwdValueChange={(accountValue,pwdValue)=>{
console.log('用户名称:', accountValue);
console.log('密码:', pwdValue);
if(accountValue&&pwdValue){
setButtonClicked(false);
}else{
setButtonClicked(true);
}
}}
/>
</Animated.View>
<Button
title="登录"
color="blue"
onPress={this.shake}
disabled={buttonClicked}/>
</View>);
};
const styles = StyleSheet.create({
editViewImage:{
width:25,
height:25,
marginLeft:10,
},
deleteViewImage:{
width:25,
height:25,
marginRight:10,
},
editView:{
flexDirection: 'row',
alignItems: 'center',
marginBottom: 40,
borderWidth: 1,
borderColor: 'gray',
borderRadius: 10,
},
container: {
flex: 1,
justifyContent: 'top',
padding: 20,
},
input: {
height: 45,
padding: 5,
flex: 1,
},
});
AppRegistry.registerComponent(appName, () => ShakeAnimation);
预览布局
案例
切换分支 edit_change_button_bgcolor_2024_0629