使用輸入框時產品經常會有一些需求,好比123456789變成123-456-789或者限制一些字符的輸入等等。不少時候都是網上搜索就完事了,可是每次都去搜索有點浪費時間,並且有些也不符合需求。因此本身寫一篇,之後就能夠吃老本了。😝android
借鑑博客EditText每4位自動添加空格git
import android.content.Context;
import android.text.Editable;
import android.text.TextUtils;
import android.text.TextWatcher;
import android.util.AttributeSet;
import com.ifreegroup.ebbly.lib_common.utils.AppLogUtil;
/**
* @Describe:自動添加佔位符的輸入框
* @Date: 2019/06/11
* @Author: dengkewu
* @Contact:
*/
public class PlaceHolderEditText extends android.support.v7.widget.AppCompatEditText {
//上次輸入框中的內容
private String lastString;
//光標的位置
private int selectPosition;
//輸入框內容改變監聽
private TextChangeListener listener;
//追加字符
private String item = "-";
public PlaceHolderEditText(Context context) {
super(context);
initView();
}
public PlaceHolderEditText(Context context, AttributeSet attrs) {
super(context, attrs);
initView();
}
public PlaceHolderEditText(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initView();
}
private void initView() {
addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
/**
* 當輸入框內容改變時的回調
* @param s 改變後的字符串
* @param start 改變以後的光標下標
* @param before 刪除了多少個字符
* @param count 添加了多少個字符
*/
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
//由於從新排序以後setText的存在
//會致使輸入框的內容從0開始輸入,這裏是爲了不這種狀況產生一系列問題
if (start == 0 && count > 1 && getSelectionStart() == 0) {
return;
}
String textTrim = getText().toString().trim();
if (TextUtils.isEmpty(textTrim)) {
return;
}
//若是 before >0 && count == 0,表明這次操做是刪除操做
if (before > 0 && count == 0) {
selectPosition = start;
if (TextUtils.isEmpty(lastString)) {
return;
}
//將上次的字符串去空格 和 改變以後的字符串去空格 進行比較
//若是一致,表明本次操做刪除的是空格
if (textTrim.equals(lastString.replaceAll(item, ""))) {
//幫助用戶刪除該刪除的字符,而不是空格
StringBuilder stringBuilder = new StringBuilder(lastString);
stringBuilder.deleteCharAt(start - 1);
selectPosition = start - 1;
setText(stringBuilder.toString());
}
} else {
//此處表明是添加操做
//當光標位於空格以前,添加字符時,須要讓光標跳過空格,再按照以前的邏輯計算光標位置
if ((start + count) % 5 == 0) {
selectPosition = start + count + 1;
} else {
selectPosition = start + count;
}
}
}
@Override
public void afterTextChanged(Editable s) {
//獲取輸入框中的內容,不能夠去空格
String etContent = getText().toString();
if (TextUtils.isEmpty(etContent)) {
if (listener != null) {
listener.textChange("");
}
return;
}
//從新拼接字符串
String newContent = addSpaceByCredit(etContent);
//保存本次字符串數據
lastString = newContent;
//若是有改變,則從新填充
//防止EditText無限setText()產生死循環
if (!newContent.equals(etContent)) {
setText(newContent);
try {
//保證光標的位置
setSelection(selectPosition > newContent.length() ? newContent.length() : selectPosition);
} catch (Exception e) {
//恰好爲限制字符的整數倍時添加空格後會出現越界的狀況
//AppLogUtil.e("超過限制字符");
}
}
//觸發回調內容
if (listener != null) {
listener.textChange(newContent);
}
}
});
}
/**
* 輸入框內容回調,當輸入框內容改變時會觸發
*/
public interface TextChangeListener {
void textChange(String text);
}
public void setTextChangeListener(TextChangeListener listener) {
this.listener = listener;
}
/**
* 每4位添加一個空格
*
* @param content
* @return
*/
public String addSpaceByCredit(String content) {
if (TextUtils.isEmpty(content)) {
return "";
}
content = content.replaceAll(item, "");
if (TextUtils.isEmpty(content)) {
return "";
}
StringBuilder newString = new StringBuilder();
for (int i = 1; i <= content.length(); i++) {
if (i % 4 == 0 && i != content.length()) {
newString.append(content.charAt(i - 1) + item);
} else {
newString.append(content.charAt(i - 1));
}
}
return newString.toString();
}
/**
* 獲取追加字符前輸入內容
* @return
*/
public String getInputText() {
return getText().toString().replaceAll(item, "");
}
}
複製代碼
核心思路是在文本改變時獲取到原字符串取出每個字符添加上要追加的字符後返回字符串並從新setText
。固然中間會有一些坑,好比光標位置、刪除時空格要跳過以及刪除後會再追加空格會形成死循環的問題。固然這裏不少狀況已經處理過了,若是有其餘需求好比手機號碼的111 1111 1111
的形式能夠修改addSpaceByCredit
這個方法。github
借鑑博客Android EditText限制輸入字符的5種實現方式正則表達式
et_traveler_content.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) {
String editable = et_traveler_content.getText().toString();
String str = stringFilter(editable.toString());
if (!editable.equals(str)) {
et_traveler_content.setText(str);
//設置新的光標所在位置
et_traveler_content.setSelection(et_traveler_content.getText().toString().length());
}
}
@Override
public void afterTextChanged(Editable s) {
}
});
public String stringFilter(String str) {
// 只容許字母、數字、英文空白字符
String regEx = "[^a-zA-Z0-9\\s]";
Pattern p = Pattern.compile(regEx);
Matcher m = p.matcher(str);
return m.replaceAll("");
}
複製代碼
這裏也是輸入時作過濾而後從新setText
。只要須要對正則表達式熟悉想作什麼限制均可以。bash
系統自帶app
<android.support.design.widget.TextInputLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginStart="15dp"
android:padding="0dp"
android:layout_centerVertical="true"
android:gravity="center_vertical">
<EditText
…… />
</android.support.design.widget.TextInputLayout>
複製代碼
只須要用TextInputLayout
包裹一層即可以實現MD效果。ide
if (isShowPwd) {
// 可視密碼輸入
setInputType(EditorInfo.TYPE_CLASS_TEXT | EditorInfo
.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD);
} else {
// 非可視密碼狀態
setInputType(EditorInfo.TYPE_CLASS_TEXT | EditorInfo.TYPE_TEXT_VARIATION_PASSWORD);
}
複製代碼
父容器設置(其實只要佈局內有一個控件設置就能夠)佈局
android:focusableInTouchMode="true"
複製代碼