电话号码在Android中格式化EditText


74

我正在制作一个简单的通讯簿应用程序(定位4.2),该应用程序使用名称,地址,城市,州,邮政编码和电话。

我想将输入的电话号码格式化为电话号码(XXX)XXX-XXXX,但是我需要将值作为字符串提取出来,以便在保存时将其存储在数据库中。我怎样才能做到这一点??我为“电话号码”输入设置了EditText,但显然做得并不多。


1
您是否需要将字符串全部设为数字,还是要使用空格,破折号和括号?
查尔斯·芒格2013年

我猜想字符串的格式可以与电话号码相同,只要我可以将其放入字符串变量中,然后将其插入数据库表即可即可
BackDoorNoBaby 2013年

1
您可以将模式匹配与正则表达式结合使用
Raghunandan 2013年

您还应该记住,(xxx)xxx-xxxx只是美国和其他一些地方的数字格式。
draksia 2013年

Answers:


61

有一个名为PhoneNumberUtils的库,可以帮助您处理电话号码的转换和比较。例如,使用...

EditText text = (EditText) findViewById(R.id.editTextId);
PhoneNumberUtils.formatNumber(text.getText().toString())

...以标准格式格式化您的电话号码。

PhoneNumberUtils.compare(String a, String b);

...有助于进行模糊比较。还有更多。查看http://developer.android.com/reference/android/telephony/PhoneNumberUtils.html了解更多信息。

ps将EditText设置phone为已经是不错的选择;最终可能会有所帮助,digits例如在您的布局中添加看起来像...

<EditText
    android:id="@+id/editTextId"
    android:inputType="phone"
    android:digits="0123456789+" 
/> 

1
这就是我要建议的。我使用那个图书馆,还算不错。
yarian 2013年

请注意在不同版本的Android上对其进行测试...在较新的API上,它的工作方式往往有所不同。
艾哈迈德(Ahmed)2013年

@ JaVAndroid:是的,肯定;有时候这很棘手,因为不同的国家/地区也允许使用不同的字符。
Trinimon

3
PhoneNumberUtils是PhoneNumberFormattingTextWatcher背后的类,因此我们有相同的基本答案。不同之处在于,您的方法是在TextWatcher不断更新的过程中一次性发生的。(您的+1。)但是为什么要使用输入类型数字?
2013年

1
@André如果要在输入数字时格式化EditText怎么办?这样就可以完美地格式化它的存储方式,但是当用户键入“ 123”时,我希望它显示为(123),然后为其他7个数字分别为(123)XXX-XXXX
BackDoorNoBaby

100

只需使用PhoneNumberFormattingTextWatcher,只需调用:

editText.addTextChangedListener(new PhoneNumberFormattingTextWatcher());

另外
要清楚一点,PhoneNumberFormattingTextWatcher的主干是PhoneNumberUtils类。区别在于TextWatcher维护EditText,而您PhoneNumberUtils.formatNumber()每次更改其内容时都必须调用它。


4
我曾这样尝试过,但未将文本设置为(XXX)XXX-XXXX的格式。它的允许格式,例如xxx-xxx-xxxx
Vishal Thakkar

30

只需使用:

在Java代码中:

editText.addTextChangedListener(new PhoneNumberFormattingTextWatcher());

在XML代码中:

<EditText
    android:id="@+id/etPhoneNumber"
    android:inputType="phone"/>

这段代码对我有用。当文本在编辑文本中更改时,它将自动设置格式。


并用于String phoneNumbers = maskedString.replaceAll("[^\\d]", "");获取没有任何空格的phonenum
Nur4I

请注意android:inputType =“ phone”,因为某些手机(例如Xiomi)不会显示带有数字的键盘。当用户尝试键入某个字母时(因为数字键盘未显示给他/他),用户不会得到反馈。这真是奇怪。因此,为了最佳实践,我将推荐android:inputType =“ number”
Mladen Rakonjac

嘿,您可以将其android:inputType="phone|number"用作备用机制
Pulkit

它不适用于日语电话号码。如果尝试输入ISO代码(“ JP”),则根本不会格式化该数字。
Tiago

inputType =“ phone”显然不存在,这只适合我吗?
speedox

21

我最近为Android EditText做过类似的格式化,例如1(XXX)XXX-XXXX。请在下面找到代码。只需使用TextWatcher子类作为文本更改的监听器即可:....

UsPhoneNumberFormatter addLineNumberFormatter = new UsPhoneNumberFormatter(
            new WeakReference<EditText>(mYourEditText));
    mYourEditText.addTextChangedListener(addLineNumberFormatter);

...

private class UsPhoneNumberFormatter implements TextWatcher {
    //This TextWatcher sub-class formats entered numbers as 1 (123) 456-7890
    private boolean mFormatting; // this is a flag which prevents the
                                    // stack(onTextChanged)
    private boolean clearFlag;
    private int mLastStartLocation;
    private String mLastBeforeText;
    private WeakReference<EditText> mWeakEditText;

    public UsPhoneNumberFormatter(WeakReference<EditText> weakEditText) {
        this.mWeakEditText = weakEditText;
    }

    @Override
    public void beforeTextChanged(CharSequence s, int start, int count,
            int after) {
        if (after == 0 && s.toString().equals("1 ")) {
            clearFlag = true;
        }
        mLastStartLocation = start;
        mLastBeforeText = s.toString();
    }

    @Override
    public void onTextChanged(CharSequence s, int start, int before,
            int count) {
        // TODO: Do nothing
    }

    @Override
    public void afterTextChanged(Editable s) {
        // Make sure to ignore calls to afterTextChanged caused by the work
        // done below
        if (!mFormatting) {
            mFormatting = true;
            int curPos = mLastStartLocation;
            String beforeValue = mLastBeforeText;
            String currentValue = s.toString();
            String formattedValue = formatUsNumber(s);
            if (currentValue.length() > beforeValue.length()) {
                int setCusorPos = formattedValue.length()
                        - (beforeValue.length() - curPos);
                mWeakEditText.get().setSelection(setCusorPos < 0 ? 0 : setCusorPos);
            } else {
                int setCusorPos = formattedValue.length()
                        - (currentValue.length() - curPos);
                if(setCusorPos > 0 && !Character.isDigit(formattedValue.charAt(setCusorPos -1))){
                    setCusorPos--;
                }
                mWeakEditText.get().setSelection(setCusorPos < 0 ? 0 : setCusorPos);
            }
            mFormatting = false;
        }
    }

    private String formatUsNumber(Editable text) {
        StringBuilder formattedString = new StringBuilder();
        // Remove everything except digits
        int p = 0;
        while (p < text.length()) {
            char ch = text.charAt(p);
            if (!Character.isDigit(ch)) {
                text.delete(p, p + 1);
            } else {
                p++;
            }
        }
        // Now only digits are remaining
        String allDigitString = text.toString();

        int totalDigitCount = allDigitString.length();

        if (totalDigitCount == 0
                || (totalDigitCount > 10 && !allDigitString.startsWith("1"))
                || totalDigitCount > 11) {
            // May be the total length of input length is greater than the
            // expected value so we'll remove all formatting
            text.clear();
            text.append(allDigitString);
            return allDigitString;
        }
        int alreadyPlacedDigitCount = 0;
        // Only '1' is remaining and user pressed backspace and so we clear
        // the edit text.
        if (allDigitString.equals("1") && clearFlag) {
            text.clear();
            clearFlag = false;
            return "";
        }
        if (allDigitString.startsWith("1")) {
            formattedString.append("1 ");
            alreadyPlacedDigitCount++;
        }
        // The first 3 numbers beyond '1' must be enclosed in brackets "()"
        if (totalDigitCount - alreadyPlacedDigitCount > 3) {
            formattedString.append("("
                    + allDigitString.substring(alreadyPlacedDigitCount,
                            alreadyPlacedDigitCount + 3) + ") ");
            alreadyPlacedDigitCount += 3;
        }
        // There must be a '-' inserted after the next 3 numbers
        if (totalDigitCount - alreadyPlacedDigitCount > 3) {
            formattedString.append(allDigitString.substring(
                    alreadyPlacedDigitCount, alreadyPlacedDigitCount + 3)
                    + "-");
            alreadyPlacedDigitCount += 3;
        }
        // All the required formatting is done so we'll just copy the
        // remaining digits.
        if (totalDigitCount > alreadyPlacedDigitCount) {
            formattedString.append(allDigitString
                    .substring(alreadyPlacedDigitCount));
        }

        text.clear();
        text.append(formattedString.toString());
        return formattedString.toString();
    }

}

4
@samik我遇到此错误java.lang.IndexOutOfBoundsException:setSpan(2 ... 2)结束于长度1
Rao的

私有类的修改版本以限制可能的总输入数字,请参见-> gist.github.com/CrandellWS/e254a215c54aa4be0400a3511a23f730 @Rao遇到了相同的问题,请尝试使用我的NoExtraDigits修改...
CrandellWS

13

也许下面的示例项目可以帮助您;

https://github.com/reinaldoarrosi/MaskedEditText

该项目包含一个视图类调用MaskedEditText。首先,应将其添加到项目中

然后在项目的res / values / attrs.xml文件中的xml部分下面添加;

<resources>
    <declare-styleable name="MaskedEditText">
        <attr name="mask" format="string" />
        <attr name="placeholder" format="string" />
    </declare-styleable>
</resources>

然后您就可以使用MaskedEditText视图了。

最后,您应该在XML文件中添加MaskedEditText,如下所示:

<packagename.currentfolder.MaskedEditText
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/maskedEditText"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:ems="10"
    android:text="5"
    app:mask="(999) 999-9999"
    app:placeholder="_" >

当然,您可以以编程方式使用它。

完成这些步骤后,添加MaskedEditText将如下所示;

在此处输入图片说明

以编程方式,如果您想将其文本值设为未屏蔽,则可以使用下面的行;

maskedEditText.getText(true);

要获取屏蔽的值,可以在方法中发送false值而不是truegetText


更新:是的,此库未将inputType = phone | number(至少在styles.xml中)应用于edittext。所以我选择了github.com/VicMikhailau/MaskedEditText-效果很好
修复

7

您需要创建一个类:

public class PhoneTextFormatter implements TextWatcher {

    private final String TAG = this.getClass().getSimpleName();

    private EditText mEditText;

    private String mPattern;

    public PhoneTextFormatter(EditText editText, String pattern) {
        mEditText = editText;
        mPattern = pattern;
        //set max length of string
        int maxLength = pattern.length();
        mEditText.setFilters(new InputFilter[]{new InputFilter.LengthFilter(maxLength)});
    }

    @Override
    public void beforeTextChanged(CharSequence s, int start, int count, int after) {

    }

    @Override
    public void onTextChanged(CharSequence s, int start, int before, int count) {
        StringBuilder phone = new StringBuilder(s);

        Log.d(TAG, "join");

        if (count > 0 && !isValid(phone.toString())) {
            for (int i = 0; i < phone.length(); i++) {
                Log.d(TAG, String.format("%s", phone));
                char c = mPattern.charAt(i);

                if ((c != '#') && (c != phone.charAt(i))) {
                    phone.insert(i, c);
                }
            }

            mEditText.setText(phone);
            mEditText.setSelection(mEditText.getText().length());
        }
    }

    @Override
    public void afterTextChanged(Editable s) {

    }

    private boolean isValid(String phone)
    {
        for (int i = 0; i < phone.length(); i++) {
            char c = mPattern.charAt(i);

            if (c == '#') continue;

            if (c != phone.charAt(i)) {
                return false;
            }
        }

        return true;
    }
}

如下使用:

phone = view.findViewById(R.id.phone);
phone.addTextChangedListener(new PhoneTextFormatter(phone, "+7 (###) ###-####"));

由于用户可以添加格式,因此该解决方案更为通用。现在我还没有测试。
Maxime Claude

谢谢!我还建议setInputType(InputType.TYPE_CLASS_PHONE); setText("+7 ("); setSelection(4)
Miha_x64

非常感谢你。这种解决方案为操纵数据的格式化方式留出了空间。
丹尼斯·奥卢卡


3
//(123) 456 7890  formate set

private int textlength = 0;

public class MyPhoneTextWatcher implements TextWatcher {

    @Override
    public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {
    }
    @Override
    public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {


        String text = etMobile.getText().toString();
        textlength = etMobile.getText().length();

        if (text.endsWith(" "))
            return;

        if (textlength == 1) {
            if (!text.contains("(")) {
                etMobile.setText(new StringBuilder(text).insert(text.length() - 1, "(").toString());
                etMobile.setSelection(etMobile.getText().length());
            }

        } else if (textlength == 5) {

            if (!text.contains(")")) {
                etMobile.setText(new StringBuilder(text).insert(text.length() - 1, ")").toString());
                etMobile.setSelection(etMobile.getText().length());
            }

        } else if (textlength == 6 || textlength == 10) {
            etMobile.setText(new StringBuilder(text).insert(text.length() - 1, " ").toString());
            etMobile.setSelection(etMobile.getText().length());
        }

    }
    @Override
    public void afterTextChanged(Editable editable) {
    }
}

仅代码答案不是很有用,请您解释一下如何回答OP问题?
雅克·高丁

3

更像干净:

@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {

String text = etyEditText.getText();
    int textlength = etyEditText.getText().length();

    if (text.endsWith("(") ||text.endsWith(")")|| text.endsWith(" ") || text.endsWith("-")  )
                return;

    switch (textlength){
        case 1:
            etyEditText.setEditText(new StringBuilder(text).insert(text.length() - 1, "(").toString());
            etyEditText.setSelection(etyEditText.getText().length());
            break;
        case 5:
            etyEditText.setEditText(new StringBuilder(text).insert(text.length() - 1, ")").toString());
            etyEditText.setSelection(etyEditText.getText().length());
            break;
        case 6:
            etyEditText.setEditText(new StringBuilder(text).insert(text.length() - 1, " ").toString());
            etyEditText.setSelection(etyEditText.getText().length());
            break;
        case 10:
            etyEditText.setEditText(new StringBuilder(text).insert(text.length() - 1, "-").toString());
            etyEditText.setSelection(etyEditText.getText().length());
            break;
    }

}

谢谢。这对于希望按照美国标准格式化数字的人很有帮助
Mehul Ranpara'1

2

您可以将正则表达式与模式匹配一​​起使用,以从字符串中提取数字。

    String s="";
    Pattern p = Pattern.compile("\\d+");
    Matcher m = p.matcher("(1111)123-456-789"); //editText.getText().toString()                                      
    while (m.find()) {
    s=s+m.group(0);
    }
    System.out.println("............"+s);    

    Output : ............1111123456789

当然是一种解决方案...尽管在大多数情况下,我仍然认为PhoneNumberUtils是可行的方法。
诺曼H

1

不用担心 我为您提供了更好的解决方案。您可以在下面看到这个简单的应用程序链接。

private EditText mPasswordField;
public int textLength = 0;

@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    mPasswordField = (EditText) findViewById(R.id.password_field);
    mPasswordField.addTextChangedListener(this);
}

@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 text = mPasswordField.getText().toString();
    textLength = mPasswordField.getText().length();

    if (text.endsWith("-") || text.endsWith(" ") || text.endsWith(" "))
        return;

    if (textLength == 1) {
        if (!text.contains("(")) {
            mPasswordField.setText(new StringBuilder(text).insert(text.length() - 1, "(").toString());
            mPasswordField.setSelection(mPasswordField.getText().length());
        }

    } else if (textLength == 5) {

        if (!text.contains(")")) {
            mPasswordField.setText(new StringBuilder(text).insert(text.length() - 1, ")").toString());
            mPasswordField.setSelection(mPasswordField.getText().length());
        }

    } else if (textLength == 6) {
            mPasswordField.setText(new StringBuilder(text).insert(text.length() - 1, " ").toString());
            mPasswordField.setSelection(mPasswordField.getText().length());

    } else if (textLength == 10) {
        if (!text.contains("-")) {
            mPasswordField.setText(new StringBuilder(text).insert(text.length() - 1, "-").toString());
            mPasswordField.setSelection(mPasswordField.getText().length());
        }
    } else if (textLength == 15) {
        if (text.contains("-")) {
            mPasswordField.setText(new StringBuilder(text).insert(text.length() - 1, "-").toString());
            mPasswordField.setSelection(mPasswordField.getText().length());
        }
    }else if (textLength == 18) {
        if (text.contains("-")) {
            mPasswordField.setText(new StringBuilder(text).insert(text.length() - 1, "-").toString());
            mPasswordField.setSelection(mPasswordField.getText().length());
        }
    } else if (textLength == 20) {
        Intent i = new Intent(MainActivity.this, Activity2.class);
        startActivity(i);

    }



}

@Override
public void afterTextChanged(Editable s) {

}

不是:不要忘了活动类的“实现TextWatcher”。

链接:https//drive.google.com/open?id = 0B-yo9VvU7jyBMjJpT29xc2k5bnc

希望您对此解决方案感到满意。


尽管此链接可以回答问题,但是在Stack Overflow上不鼓励仅链接的答案,但是您可以通过将链接的重要部分放入答案中来改善此答案,这可以确保如果更改链接,您的答案仍然是答案或删除:)
WhatsThePoint

1

您可以使用衍生工具在Android中格式化电话号码。此解决方案比其他解决方案更好,因为它不会更改输入文本。格式化仍然纯粹是可视的。

implementation 'com.googlecode.libphonenumber:libphonenumber:7.0.4'

格式化程序类:

open class PhoneNumberFormatter : TransformationMethod {
private val mFormatter: AsYouTypeFormatter = PhoneNumberUtil.getInstance().getAsYouTypeFormatter(Locale.getDefault().country)

override fun getTransformation(source: CharSequence, view: View): CharSequence {
    val formatted = format(source)
    if (source is Spannable) {
        setSpans(source, formatted)
        return source
    }
    return formatted
}
override fun onFocusChanged(view: View?, sourceText: CharSequence?, focused: Boolean, direction: Int, previouslyFocusedRect: Rect?) = Unit

private fun setSpans(spannable: Spannable, formatted: CharSequence): CharSequence {

    spannable.clearSpawns()

    var charterIndex = 0
    var formattedIndex = 0
    var spawn = ""
    val spawns: List<String> = spannable
        .map {
            spawn = ""
            charterIndex = formatted.indexOf(it, formattedIndex)
            if (charterIndex != -1){
                spawn = formatted.substring(formattedIndex, charterIndex-1)
                formattedIndex = charterIndex+1
            }
            spawn
        }

    spawns.forEachIndexed { index, sequence ->
        spannable.setSpan(CharterSpan(sequence), index, index + 1, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)
    }

    return formatted
}

private fun Spannable.clearSpawns() =
    this
        .getSpans(0, this.length, CharterSpan::class.java)
        .forEach { this.removeSpan(it) }

private fun format(spannable: CharSequence): String {
    mFormatter.clear()
    var formated = ""
    for (i in 0 until spannable.length) {
        formated = mFormatter.inputDigit(spannable[i])
    }
    return formated
}

private inner class CharterSpan(private val charters: String) : ReplacementSpan() {

    var space = 0

    override fun getSize(paint: Paint, text: CharSequence, start: Int, end: Int, fm: Paint.FontMetricsInt?): Int {
        space = Math.round(paint.measureText(charters, 0, charters.length))
        return Math.round(paint.measureText(text, start, end)) + space
    }

    override fun draw(canvas: Canvas, text: CharSequence, start: Int, end: Int, x: Float, top: Int, y: Int, bottom: Int, paint: Paint) {
        space = Math.round(paint.measureText(charters, 0, charters.length))
        canvas.drawText(text, start, end, x + space, y.toFloat(), paint)
        canvas.drawText(charters, x, y.toFloat(), paint)
    }
    }

}

Uasge:

editText.transformationMethod = formatter


0

您只能使用Java代码接受数字和电话号码类型

 EditText number1 = (EditText) layout.findViewById(R.id.edittext); 
    number1.setInputType(InputType.TYPE_CLASS_NUMBER|InputType.TYPE_CLASS_PHONE);
     number1.setKeyListener(DigitsKeyListener.getInstance("0123456789”));
      number1.setFilters(new InputFilter[] {new InputFilter.LengthFilter(14)}); // 14 is max digits

此代码将避免在读取输入后进行大量验证

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.