来吧 先看效果
需求是输入一位后 将其设置为 也就是加密展示,并将焦点自动转移到下一个框中 当输入至最后一个框时 执行一定逻辑*
原理: 我们写一个recyclerView 并在recyclerView上面放一个EditText ,这里要注意: 要让EditText覆盖recyclerView ,当我们进行输入时 ,时刻监听EditText内容变化, 一有变化时 ,将当前输入的字符设置给recyclerView的适配器 , 刷新就好
在此 我将这个逻辑代码写成了自定义属性格式 ,扩展性比较高, 使用的话也是非常简单 ,一起来看下吧!
public class CustomEditText extends FrameLayout {
/**
* 输入是否明文显示
*/
private boolean showEncryptionText;
/**
* 框数量
*/
private int num;
/**
* 当前输入的是否加粗边框
*/
private boolean sel_show_frame;
/**
* 输入至最后一个元素时是否执行跳转等行为
*/
private boolean input_ok_jump;
/**
* 框的背景图 长度为2 0为默认 1为选中
*/
private List<Integer> input_back = new ArrayList<>();
/**
* 监听输入到末尾时的监听
*/
public endJumpCLick endJumpCLick;
/**
* 框的样式(不设置就使用默认样式)
*/
private int input_adapter_layout = R.layout.input_adapter_layout;
/**
* 框的内容集合
*/
private List<InputBean> textList = new ArrayList<>();
/**
* 控制之前已经输入过的框是否添加背景
*/
private boolean ageSelectBack;
/**
* 框适配器
*/
private InputAdapter inputAdapter = new InputAdapter(textList);
public void setEndJumpCLick(CustomEditText.endJumpCLick endJumpCLick) {
this.endJumpCLick = endJumpCLick;
}
public CustomEditText(@NonNull Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
init(attrs);
}
private void init(AttributeSet attrs) {
TypedArray typedArray = getContext().obtainStyledAttributes(attrs, R.styleable.CustomEditText);
showEncryptionText = typedArray.getBoolean(R.styleable.CustomEditText_ce_show_encryption_Text, true);
ageSelectBack = typedArray.getBoolean(R.styleable.CustomEditText_agoSelectBack, false);
num = typedArray.getInteger(R.styleable.CustomEditText_ce_Num, 6);
sel_show_frame = typedArray.getBoolean(R.styleable.CustomEditText_ce_sel_show_frame, true);
input_ok_jump = typedArray.getBoolean(R.styleable.CustomEditText_ce_input_ok_jump, true);
typedArray.recycle();
LayoutParams params = new LayoutParams(GridLayout.LayoutParams.MATCH_PARENT, GridLayout.LayoutParams.MATCH_PARENT);
RecyclerView recyclerView = new RecyclerView(getContext());
recyclerView.setLayoutParams(params);
addView(recyclerView);
EditText editText = new EditText(getContext());
editText.setBackground(null);
editText.setMaxLines(num);
editText.setCursorVisible(false);
editText.setKeyListener(new DigitsKeyListener(false, false));
editText.setTextColor(Color.WHITE);
editText.setTextSize(1);
editText.setLayoutParams(params);
addView(editText);
initAdapter(recyclerView);
et_custom_editTextListener(editText);
}
private void et_custom_editTextListener(EditText et_custom_editText) {
et_custom_editText.addTextChangedListener(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) {
for (int i = 0; i < textList.size(); i++) {
textList.get(i).text = i < s.length() ? showEncryptionText ? String.valueOf(s.charAt(i)) : "*" : "";
if (!ageSelectBack) {
textList.get(i).isSelect = false;
} else {
if (textList.get(i).text.equals("")) {
textList.get(i).isSelect = false;
}
}
}
if (s.length() < num) textList.get(s.length()).isSelect = true;
if (input_ok_jump && s.length() == num && endJumpCLick != null) {
endJumpCLick.onJumpClick(s.toString());
}
inputAdapter.notifyDataSetChanged();
}
@Override
public void afterTextChanged(Editable s) {
}
});
}
private void initAdapter(RecyclerView rv_custom_editText) {
textList.clear();
for (int i = 0; i < num; i++) textList.add(new InputBean("", i == 0 ? true : false));
rv_custom_editText.setLayoutManager(new GridLayoutManager(getContext(), textList.size()));
rv_custom_editText.setAdapter(inputAdapter);
inputAdapter.notifyDataSetChanged();
}
public CustomEditText setInput_backList(List<Integer> data) {
if (sel_show_frame) {
if (data.size() == 2) {
input_back.clear();
input_back.add(data.get(0));
input_back.add(data.get(1));
} else {
Toast.makeText(getContext(), "数量不符, 添加失败!", Toast.LENGTH_SHORT).show();
}
}
return this;
}
public CustomEditText setInputAdapterLayout(int layoutId) {
input_adapter_layout = layoutId;
return this;
}
class InputBean {
public String text;
public boolean isSelect;
public InputBean(String text, boolean isSelect) {
this.text = text;
this.isSelect = isSelect;
}
}
class InputAdapter extends RecyclerView.Adapter {
public List<InputBean> list;
public InputAdapter(List<InputBean> list) {
this.list = list;
}
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
return new ViewHolder(LayoutInflater.from(parent.getContext()).inflate(input_adapter_layout, parent, false));
}
@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
ViewHolder holder1 = (ViewHolder) holder;
if (sel_show_frame && input_back.size() == 2) {
holder1.textView.setBackgroundResource(list.get(position).isSelect ? input_back.get(0) : input_back.get(1));
}
holder1.textView.setText(list.get(position).text);
}
@Override
public int getItemCount() {
return list.size();
}
class ViewHolder extends RecyclerView.ViewHolder {
public TextView textView;
public ViewHolder(View itemView) {
super(itemView);
textView = itemView.findViewById(R.id.itemEdit);
}
}
}
public interface endJumpCLick {
void onJumpClick(String s);
}
}
属性如下:
<declare-styleable name="CustomEditText">
//输入是否明文显示
<attr name="ce_show_encryption_Text" format="boolean" />
//框的数量
<attr name="ce_Num" format="integer" />
//当前输入的框是否有加粗效果
<attr name="ce_sel_show_frame" format="boolean" />
//当输入至最后一位时 ,是否执行逻辑 比如调接口等等
<attr name="ce_input_ok_jump" format="boolean" />
//已经输入过的需不需要添加背景
<attr name="agoSelectBack" format="boolean" />
</declare-styleable>
框的背景样式布局 默认为此样式布局 如果需要更改 则替换布局即可
<?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"
android:layout_width="match_parent"
android:layout_height="60dp">
<TextView
android:id="@+id/itemEdit"
android:layout_width="50dp"
android:layout_height="match_parent"
android:background="@drawable/input_default_back_view"
android:gravity="center"
android:textColor="#000000"
android:textSize="24sp"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
具体用法: 在activity中:
<?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=".DemoActivity">
<com.example.text_1.utils.CustomEditText
android:id="@+id/ce_input"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:ce_sel_show_frame="false"
app:ce_Num="4"
app:ce_show_encryption_Text="true"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
此外如果设置了加粗边框 则需要在代码中动态设置背景样式 以数组格式进行设置 下标0为当前存在焦点的样式 1为失去焦点的样式 不可以多传或少传 数组长度只能为2
加粗边框/不加粗xml如下:
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<stroke
android:width="2dp"
android:color="@color/black_tran30" />
<corners android:radius="3dp" />
</shape>
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<stroke
android:width="0.5dp"
android:color="#A3A3A3" />
<corners android:radius="3dp" />
</shape>
public class DemoActivity extends BaseActivity {
@BindView(R.id.ce_input)
CustomEditText ceInput;
@Override
public void initView() {
ceInput.setInput_backList(inputListData());
ceInput.setEndJumpCLick(s -> showToast(s));
}
/**
* 背景框
*
* @return 返回集合
*/
private List<Integer> inputListData() {
ArrayList<Integer> integers = new ArrayList<>();
integers.add(R.drawable.edit_shape_focus);
integers.add(R.drawable.edit_shape_not_focus);
return integers;
}
@Override
public int getLayout() {
return R.layout.activity_demo;
}
}
最终 效果如下:
希望对你有所帮助