原理:
自定義佈局,包含一個EditText 和多個 TextView ,EditText隱藏看不見,可以判斷是否達到指定位數。
通過for循環取值EditText中的字符,再new出新的TextView對象,並填入對應數值即可。
核心代碼入下:
CodeEditView
public class CodeEditView extends LinearLayout implements TextWatcher, View.OnClickListener, View.OnLongClickListener {
private int editViewNum = 6; //默認輸入框數量
private ArrayList<TextView> mTextViewsList = new ArrayList<>(); //存儲EditText對象
private Context mContext;
private EditText mEditText;
private int borderSize = 35; //方格邊框大小
private int borderMargin = 10; //方格間距
private int textSize = 8; //字體大小
private int textColor = 0xff; //字體顏色
private int inputType = InputType.TYPE_CLASS_NUMBER;
private inputEndListener callBack;
public CodeEditView(Context context) {
super(context);
init(context);
}
public CodeEditView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
initData(context, attrs);
init(context);
}
public CodeEditView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initData(context, attrs);
init(context);
}
private void initData(Context context, AttributeSet attrs) {
TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.CodeEditView);
borderSize = array.getInteger(R.styleable.CodeEditView_borderSize, 35);
borderMargin = array.getInteger(R.styleable.CodeEditView_borderMargin, 10);
textSize = array.getInteger(R.styleable.CodeEditView_textSize, 8);
textColor = array.getColor(R.styleable.CodeEditView_textColor, Color.BLACK);
editViewNum = array.getInteger(R.styleable.CodeEditView_borderNum, 6);
}
/**
* 獲取輸入框內容
*/
public String getText() {
return mEditText.getText().toString();
}
public void setOnInputEndCallBack(inputEndListener onInputEndCallBack) {
callBack = onInputEndCallBack;
}
/**
* 長按彈出PopupWindow,用來粘貼文本
*/
@Override
public boolean onLongClick(View v) {
showPopupWindow();
return true;
}
private void showPopupWindow() {
View popupwindow = LayoutInflater.from(mContext).inflate(R.layout.popupwindow_view, null);
final PopupWindow popupWindow = new PopupWindow(popupwindow, LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT, true);
popupWindow.showAsDropDown(this, getWidth() / 2, DensityUtil.dip2px(mContext, 5));
popupwindow.findViewById(R.id.paste).setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
popupWindow.dismiss();
pasteTextToView();
}
});
}
/**
* 粘貼內容到文本框
*/
private void pasteTextToView() {
if (getPasetText() != null && !TextUtils.isEmpty(getPasetText()) && isInteger(getPasetText())) {
//純數字
char[] chars = getPasetText().substring(0, editViewNum).toCharArray();
mEditText.setText(getPasetText().substring(0, editViewNum));
for (int i = 0; i < chars.length; i++) {
mTextViewsList.get(i).setText(String.valueOf(chars[i]));
}
} else {
Toast.makeText(mContext, "粘貼的文本必須爲純數字", Toast.LENGTH_SHORT).show();
}
}
public static boolean isInteger(String str) {
Pattern pattern = Pattern.compile("^[-\\+]?[\\d]*$");
return pattern.matcher(str).matches();
}
public String getPasetText() {
ClipboardManager clipboard = (ClipboardManager) mContext.getSystemService(Context.CLIPBOARD_SERVICE);
ClipData clipData = clipboard.getPrimaryClip();
if (clipData != null && clipData.getItemCount() > 0) {
CharSequence text = clipData.getItemAt(0).getText();
return text.toString().trim();
}
return "";
}
public interface inputEndListener {
void input(String text);
void afterTextChanged(String text);
}
private void init(final Context context) {
mContext = context;
initEditText(context);
//設置方格間距
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(
DensityUtil.dip2px(mContext, borderSize), DensityUtil.dip2px(mContext, borderSize));
params.setMargins(DensityUtil.dip2px(mContext, borderMargin), 0, 0, 0);
//設置方格文字
for (int i = 0; i < editViewNum; i++) {
TextView textView = new TextView(mContext);
textView.setBackgroundResource(R.drawable.shape_border_normal);
textView.setGravity(Gravity.CENTER);
textView.setTextSize(DensityUtil.sp2px(mContext, textSize));
textView.getPaint().setFakeBoldText(true);
textView.setLayoutParams(params);
textView.setInputType(inputType);
textView.setTextColor(textColor);
textView.setOnClickListener(this);
textView.setOnLongClickListener(this);
mTextViewsList.add(textView);
addView(textView);
}
//顯示隱藏軟鍵盤
new android.os.Handler().postDelayed(new Runnable() {
@Override
public void run() {
mEditText.setFocusable(true);
mEditText.setFocusableInTouchMode(true);
mEditText.requestFocus();
InputMethodManager imm = (InputMethodManager) mContext.getSystemService(Context.INPUT_METHOD_SERVICE);
imm.toggleSoftInput(0, InputMethodManager.HIDE_NOT_ALWAYS);
}
}, 500);
//監聽刪除鍵
mEditText.setOnKeyListener(new OnKeyListener() {
@Override
public boolean onKey(View v, int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_DEL) {
if (mEditText.getText().length() >= mTextViewsList.size()) return false;
mTextViewsList.get(mEditText.getText().length()).setText("");
}
return false;
}
});
this.setOnLongClickListener(this);
}
private void initEditText(Context context) {
mEditText = new EditText(context);
mEditText.setBackgroundColor(Color.parseColor("#00000000"));
mEditText.setMaxLines(1);
mEditText.setInputType(inputType);
mEditText.setFilters(new InputFilter[]{new InputFilter.LengthFilter(editViewNum)});
mEditText.addTextChangedListener(this);
mEditText.setTextSize(0);
mEditText.setHeight(1);
mEditText.setWidth(1);
addView(mEditText);
}
//清空文字
public void clearText() {
mEditText.setText("");
for (TextView textView : mTextViewsList) {
textView.setText("");
}
}
@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) {
if (callBack != null) {
callBack.afterTextChanged(s.toString());
}
if (s.length() <= 1) {
mTextViewsList.get(0).setText(s);
} else {
mTextViewsList.get(mEditText.getText().length() - 1).setText(s.subSequence(s.length() - 1, s.length()));
}
if (s.length() == editViewNum) {
if (callBack != null) {
callBack.input(mEditText.getText().toString());
}
}
}
@Override
public void onClick(View v) { //TextView點擊時獲取焦點彈出輸入法
mEditText.setFocusable(true);
mEditText.setFocusableInTouchMode(true);
mEditText.requestFocus();
InputMethodManager imm = (InputMethodManager) mContext.getSystemService(Context.INPUT_METHOD_SERVICE);
imm.toggleSoftInput(0, InputMethodManager.HIDE_NOT_ALWAYS);
}
}
attrs : CodeEditView
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="CodeEditView">
<attr name="textColor" format="color"/>
<attr name="textSize" format="integer"/>
<attr name="borderSize" format="integer"/>
<attr name="borderMargin" format="integer"/>
<attr name="borderNum" format="integer"/>
</declare-styleable>
</resources>
popupwindow_view.xlm
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<TextView
android:background="@drawable/select_popupwindow_bg"
android:id="@+id/paste"
android:padding="8dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="#ffffff"
android:text="粘貼"/>
</LinearLayout>
main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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"
android:orientation="vertical"
tools:context=".MainActivity">
<com.leixiansheng.codeeditview.CodeEditView
android:id="@+id/normal_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_marginTop="20dp"/>
<Button
android:id="@+id/btn_clear"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_marginTop="20dp"
android:text="清除輸入"/>
<com.leixiansheng.codeeditview.CodeEditView
android:id="@+id/custom_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_horizontal"
android:layout_marginTop="20dp"
app:textColor="@color/colorPrimary"
app:textSize="5"
app:borderNum="10"
app:borderSize="30"
app:borderMargin="10"/>
<TextView
android:padding="10dp"
android:id="@+id/textview1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="\n\t
app:textColor=@color/colorAccent //字體顏色\n\t
app:borderNum=4 //輸入框個數\n\t
app:borderMargin=20 //輸入框間距\n\t
app:borderSize=48 //輸入框大小\n\t
app:textSize=10 //字體大小"
android:layout_gravity="center_horizontal"/>
</LinearLayout>
主代碼:
public class MainActivity extends AppCompatActivity {
private CodeEditView normalView;
private CodeEditView customView;
private Button mClear;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
normalView = findViewById(R.id.normal_view);
customView = findViewById(R.id.custom_view);
mClear = findViewById(R.id.btn_clear);
normalView.setOnInputEndCallBack(new CodeEditView.inputEndListener() {
@Override
public void input(String text) {
toast(text);
}
@Override
public void afterTextChanged(String text) {
}
});
customView.setOnInputEndCallBack(new CodeEditView.inputEndListener() {
@Override
public void input(String text) {
toast(text);
}
@Override
public void afterTextChanged(String text) {
toast(text);
}
});
mClear.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
clear(normalView);
}
});
}
//清除文字
public void clear(CodeEditView view) {
view.clearText();
}
public void toast(String str) {
Toast.makeText(this, str, Toast.LENGTH_SHORT).show();
}
}