EditTextでユーザーが入力した電話番号に、ユーザーが番号を入力するたびに動的に形式を変更させるようにしたいのですが。つまり、ユーザーが7144のように4桁まで入力すると、editTextは「714-4」を示します。ユーザーが数字を入力するたびに、editTextが###-###-####の形式に動的に更新されるようにしたいと思います。これはどのように行うことができますか?また、1つ以上のeditTextを処理しています。
これを行う最も簡単な方法は、組み込みのAndroid PhoneNumberFormattingTextWatcher を使用することです。
したがって、基本的にはコードでEditTextを取得し、テキストウォッチャーを次のように設定します...
EditText inputField = (EditText) findViewById(R.id.inputfield);
inputField.addTextChangedListener(new PhoneNumberFormattingTextWatcher());
PhoneNumberFormattingTextWatcherを使用する良い点は、ロケールに基づいて番号エントリを正しくフォーマットすることです。
上記の答えは正しいですが、国ごとに機能します。そのような形式の電話番号が必要な場合(###-###-####)。次にこれを使用します:
etPhoneNumber.addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
int digits = etPhoneNumber.getText().toString().length();
if (digits > 1)
lastChar = etPhoneNumber.getText().toString().substring(digits-1);
}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
int digits = etPhoneNumber.getText().toString().length();
Log.d("LENGTH",""+digits);
if (!lastChar.equals("-")) {
if (digits == 3 || digits == 7) {
etPhoneNumber.append("-");
}
}
}
@Override
public void afterTextChanged(Editable s) {
}
});
宣言String lastChar = " "
あなたの活動。
次に、この行を編集テキストのxmlに追加します
Android:inputType="phone"
それで全部です。
編集済み: edittextの長さを10桁に制限する場合は、以下の行も追加します。
Android:maxLength="12"
(「-」は2回スペースを取るので12です)
私のスクリプト、ここからの例 ここの説明
<Android.support.design.widget.TextInputLayout
Android:id="@+id/numphone_layout"
app:hintTextAppearance="@style/MyHintText"
Android:layout_width="match_parent"
Android:layout_height="wrap_content"
Android:layout_marginTop="8dp">
<Android.support.design.widget.TextInputEditText
Android:id="@+id/edit_text_numphone"
Android:layout_width="match_parent"
Android:layout_height="wrap_content"
Android:theme="@style/MyEditText"
Android:digits="+() 1234567890-"
Android:hint="@string/hint_numphone"
Android:inputType="phone"
Android:maxLength="17"
Android:textSize="14sp" />
</Android.support.design.widget.TextInputLayout>
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
TextInputEditText phone = (TextInputEditText) findViewById(R.id.edit_text_numphone);
//Add to mask
phone.addTextChangedListener(textWatcher);
}
TextWatcher textWatcher = new TextWatcher() {
private boolean mFormatting; // this is a flag which prevents the stack overflow.
private int mAfter;
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
// nothing to do here..
}
//called before the text is changed...
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
//nothing to do here...
mAfter = after; // flag to detect backspace..
}
@Override
public void afterTextChanged(Editable s) {
// Make sure to ignore calls to afterTextChanged caused by the work done below
if (!mFormatting) {
mFormatting = true;
// using US or RU formatting...
if(mAfter!=0) // in case back space ain't clicked...
{
String num =s.toString();
String data = PhoneNumberUtils.formatNumber(num, "RU");
if(data!=null)
{
s.clear();
s.append(data);
Log.i("Number", data);//8 (999) 123-45-67 or +7 999 123-45-67
}
}
mFormatting = false;
}
}
};
次を電話番号のEditTextに追加して、フォーマットされた電話番号を取得します(###-###-####)
Phone.addTextChangedListener(new TextWatcher() {
int length_before = 0;
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
length_before = s.length();
}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
}
@Override
public void afterTextChanged(Editable s) {
if (length_before < s.length()) {
if (s.length() == 3 || s.length() == 7)
s.append("-");
if (s.length() > 3) {
if (Character.isDigit(s.charAt(3)))
s.insert(3, "-");
}
if (s.length() > 7) {
if (Character.isDigit(s.charAt(7)))
s.insert(7, "-");
}
}
}
});
上記のソリューションではバックスペースが考慮されていないため、入力後に数字をいくつか削除すると、フォーマットが混乱する傾向があります。以下のコードはこの問題を修正します。
phoneNumberEditText.addTextChangedListener(new TextWatcher() {
int beforeLength;
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
beforeLength = phoneNumberEditText.length();
}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
int digits = phoneNumberEditText.getText().toString().length();
if (beforeLength < digits && (digits == 3 || digits == 7)) {
phoneNumberEditText.append("-");
}
}
@Override
public void afterTextChanged(Editable s) { }
});
Androidの動的マスク。これは正常に機能し、電話番号マスクに厳密に適合しています。どのマスクでも指定できます。
編集:ユーザーがキーボードで入力した不要な文字をイベントにロックする新しいバージョンがあります。
/**
* Text watcher allowing strictly a MASK with '#' (example: (###) ###-####
*/
class PhoneNumberTextWatcher(private var mask: String) : TextWatcher {
companion object {
const val MASK_CHAR = '#'
}
// simple mutex
private var isCursorRunning = false
private var isDeleting = false
override fun afterTextChanged(s: Editable?) {
if (isCursorRunning || isDeleting) {
return
}
isCursorRunning = true
s?.let {
val onlyDigits = removeMask(it.toString())
it.clear()
it.append(applyMask(mask, onlyDigits))
}
isCursorRunning = false
}
override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {
isDeleting = count > after
}
override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {}
private fun applyMask(mask: String, onlyDigits: String): String {
val maskPlaceholderCharCount = mask.count { it == MASK_CHAR }
var maskCurrentCharIndex = 0
var output = ""
onlyDigits.take(min(maskPlaceholderCharCount, onlyDigits.length)).forEach { c ->
for (i in maskCurrentCharIndex until mask.length) {
if (mask[i] == MASK_CHAR) {
output += c
maskCurrentCharIndex += 1
break
} else {
output += mask[i]
maskCurrentCharIndex = i + 1
}
}
}
return output
}
private fun removeMask(value: String): String {
// extract all the digits from the string
return Regex("\\D+").replace(value, "")
}
}
このコードでは、マスク###-###-####(スペースなし)を使用して電話番号を入力できます。また、電話番号の削除に関する問題が修正されています。
editText.addTextChangedListener(new TextWatcher() {
final static String DELIMITER = "-";
String lastChar;
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
int digits = editText.getText().toString().length();
if (digits > 1)
lastChar = editText.getText().toString().substring(digits-1);
}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
int digits = editText.getText().length();
// prevent input dash by user
if (digits > 0 && digits != 4 && digits != 8) {
CharSequence last = s.subSequence(digits - 1, digits);
if (last.toString().equals(DELIMITER))
editText.getText().delete(digits - 1, digits);
}
// inset and remove dash
if (digits == 3 || digits == 7) {
if (!lastChar.equals(DELIMITER))
editText.append("-"); // insert a dash
else
editText.getText().delete(digits -1, digits); // delete last digit with a dash
}
dataModel.setPhone(s.toString());
}
@Override
public void afterTextChanged(Editable s) {}
});
レイアウト:
<EditText
Android:layout_width="match_parent"
Android:layout_height="wrap_content"
Android:imeOptions="actionDone"
Android:textAlignment="textStart"
Android:inputType="number"
Android:digits="-0123456789"
Android:lines="1"
Android:maxLength="12"/>
これが私の解決策です
アクティビティ/フラグメントでの実行方法(つまり、onViewCreatedで):
//field in class
private val exampleIdValidator by lazy { ExampleIdWatcher(exampleIdField.editText!!) }
exampleIdField.editText?.addTextChangedListener(exampleIdValidator)
検証クラス:
import Android.text.Editable
import Android.text.TextWatcher
import Android.widget.EditText
class ExampleIdWatcher(exampleIdInput: EditText) : TextWatcher {
private var exampleIdInput: EditText = exampleIdInput
override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {
}
override fun onTextChanged(userInput: CharSequence?, start: Int, before: Int, count: Int) {
if (userInput!!.isNotEmpty() && !areSpacesCorrect(userInput)) {
val stringTextWithoutWhiteSpaces: String = userInput.toString().replace(" ", "")
val textSB: StringBuilder = StringBuilder(stringTextWithoutWhiteSpaces)
when {
textSB.length > 8 -> {
setSpacesAndCursorPosition(textSB, 2, 6, 10)
}
textSB.length > 5 -> {
setSpacesAndCursorPosition(textSB, 2, 6)
}
textSB.length > 2 -> {
setSpacesAndCursorPosition(textSB, 2)
}
}
}
}
override fun afterTextChanged(s: Editable?) {
}
private fun setSpacesAndCursorPosition(textSB: StringBuilder, vararg ts: Int) {
for (t in ts) // ts is an Array
textSB.insert(t, SPACE_CHAR)
val currentCursorPosition = getCursorPosition(exampleIdInput.selectionStart)
exampleIdInput.setText(textSB.toString())
exampleIdInput.setSelection(currentCursorPosition)
}
private fun getCursorPosition(currentCursorPosition: Int): Int {
return if (EXAMPLE_ID_SPACE_CHAR_CURSOR_POSITIONS.contains(currentCursorPosition)) {
currentCursorPosition + 1
} else {
currentCursorPosition
}
}
private fun areSpacesCorrect(userInput: CharSequence?): Boolean {
EXAMPLE_ID_SPACE_CHAR_INDEXES.forEach {
if (userInput!!.length > it && userInput[it].toString() != SPACE_CHAR) {
return false
}
}
return true
}
companion object {
private val EXAMPLE_ID_SPACE_CHAR_INDEXES: List<Int> = listOf(2, 6, 10)
private val EXAMPLE_ID_SPACE_CHAR_CURSOR_POSITIONS: List<Int> = EXAMPLE_ID_SPACE_CHAR_INDEXES.map { it + 1 }
private const val SPACE_CHAR: String = " "
}
}
レイアウト:
<com.google.Android.material.textfield.TextInputEditText
Android:layout_width="match_parent"
Android:layout_height="wrap_content"
Android:digits=" 0123456789"
Android:inputType="numberPassword"
Android:maxLength="14"
tools:text="Example text" />
結果は次のとおりです。
XX XXX XXX XXX