เครื่องหมายจุลภาคคั่นทศนิยม (',') พร้อมด้วย numberDecimal inputType ใน EditText


137

inputType numberDecimalในEditTextการใช้จุด '' เป็นตัวคั่นทศนิยม ในยุโรปมักจะใช้ลูกน้ำ "," แทน แม้ว่าสถานที่ของฉันจะถูกตั้งค่าเป็นภาษาเยอรมัน แต่ตัวคั่นทศนิยมก็ยังคงเป็น "."

มีวิธีรับลูกน้ำเป็นตัวคั่นทศนิยมหรือไม่?



1
ในที่สุดข้อบกพร่องนี้ได้รับการแก้ไขแล้วใน Android O: issueetracker.google.com/issues/36907764
Lovis

พวกเขาบอกว่าได้รับการแก้ไข แต่ฉันไม่สามารถยืนยันได้ว่าแก้ไขแล้ว? คุณสามารถ?
เซบาสเตียน

7
ฉันสามารถยืนยันได้ว่ามันไม่ได้รับการแก้ไขอย่างน้อยใน Nexus 4 ของฉันที่ใช้ Android 8.1 (aka LineageOS 15.1) ด้วยการตั้งค่า -> ภาษาที่ตั้งค่าเป็นฝรั่งเศส (ฝรั่งเศส) EditText กับ android: inputType = "numberDecimal" จะมีตัวคั่น "," (ลูกน้ำ) แต่ยังคงปฏิเสธที่จะยอมรับลูกน้ำ ข้อเสนอ '.' (จุดทศนิยม) ได้รับการยอมรับ เป็นเวลากว่า 9 ปีแล้วที่มีการรายงานข้อบกพร่องนี้เป็นครั้งแรก นั่นคือบันทึกบางประเภทหรือไม่? กะพร่องกะแพร่ง.
pete

คำตอบ:


105

การแก้ปัญหา (จนกว่า Google จะแก้ไขปัญหานี้) คือการใช้EditTextด้วยและandroid:inputType="numberDecimal"android:digits="0123456789.,"

จากนั้นเพิ่ม TextChangedListener ไปยัง EditText ด้วย afterTextChanged ต่อไปนี้:

public void afterTextChanged(Editable s) {
    double doubleValue = 0;
    if (s != null) {
        try {
            doubleValue = Double.parseDouble(s.toString().replace(',', '.'));
        } catch (NumberFormatException e) {
            //Error
        }
    }
    //Do something with doubleValue
}

1
@Zoombie เพื่อให้เครื่องหมายจุลภาค (,) แสดงบนแป้นพิมพ์ของคุณขึ้นอยู่กับภาษาที่ตั้งค่าบนอุปกรณ์ของคุณ หากข้อมูลที่คุณป้อนมีประเภท numberDecimal และภาษาของคุณเป็นภาษาอังกฤษ (สหรัฐอเมริกา) จะแสดงบนอุปกรณ์ Nexus (ข้อมูลอ้างอิง) เป็นไปได้ว่าอุปกรณ์ที่ไม่ใช่ Nexus ไม่เคารพสิ่งนี้
hcpl

11
ใช้งานได้ แต่โปรดทราบว่าข้อความเช่น "24,22.55" จะผ่านไปได้ คุณอาจต้องเพิ่มการตรวจสอบความถูกต้องเพิ่มเติมเพื่อแก้ไขปัญหานี้!
dimsuz

8
นี่ยังเป็นวิธีที่จะไป?
Willi Mentzel

ยิ่งไปกว่านั้นให้ใช้ char localizedSeparator = DecimalFormatSymbols.getInstance () getDecimalSeparator (); localizedFloatString = localizedFloatString.replace ('.', localizedSeparator);
southerton

4
ดูเหมือนว่านี่เป็นเพียงการแลกเปลี่ยนข้อบกพร่องหนึ่งสำหรับอีกข้อหนึ่ง ตามที่ดำเนินการข้างต้นสิ่งนี้จะใช้ได้กับภาษาที่ใช้แทน ในราคาที่กลับกันซึ่งพบได้ทั่วไปทั่วโลก การปรับแต่งของ @ southerton ช่วยในเรื่องนี้ได้อย่างไรก็ตามผู้ใช้ของคุณอาจประหลาดใจเมื่อพวกเขากดไฟล์. และมี a ปรากฏในอินพุต
นิค

30

รูปแบบของโซลูชัน 'หลัก' มีให้ที่นี่:

char separator = DecimalFormatSymbols.getInstance().getDecimalSeparator();
input.setKeyListener(DigitsKeyListener.getInstance("0123456789" + separator));

คำนึงถึงตัวคั่นโลแคล


นี่เป็นคำตอบที่ชัดเจนที่สุดสำหรับคำถามเดิม ขอบคุณ
peter.bartos

วางไว้ใน onCreate () นี่คือวิธีที่จะไป IMHO
TechNyquist

6
ฉันชอบสิ่งนี้ แต่ระวัง ... มีแป้นพิมพ์ที่ไม่สนใจภาษาของผู้ใช้ดังนั้นผู้ใช้ที่ไม่มีคีย์,ในแป้นพิมพ์ ตัวอย่าง: แป้นพิมพ์ Samsung (KitKat)
Brais Gabin

2
สิ่งนี้จะทำให้ตัวคั่นทศนิยมซ้ำกัน ดูคำตอบด้านล่างเพื่อจัดการ: stackoverflow.com/a/45384821/6138589
Esdras Lopez

19

ตามมาสก์สกุลเงินรหัสสำหรับ EditText ($ 123,125.155)

เค้าโครง XML

  <EditText
    android:inputType="numberDecimal"
    android:layout_height="wrap_content"
    android:layout_width="200dp"
    android:digits="0123456789.,$" />

รหัส

EditText testFilter=...
testFilter.addTextChangedListener( new TextWatcher() {
        boolean isEdiging;
        @Override public void onTextChanged(CharSequence s, int start, int before, int count) { }
        @Override public void beforeTextChanged(CharSequence s, int start, int count, int after) { }

        @Override public void afterTextChanged(Editable s) {
            if(isEdiging) return;
            isEdiging = true;

            String str = s.toString().replaceAll( "[^\\d]", "" );
            double s1 = Double.parseDouble(str);

            NumberFormat nf2 = NumberFormat.getInstance(Locale.ENGLISH);
            ((DecimalFormat)nf2).applyPattern("$ ###,###.###");
            s.replace(0, s.length(), nf2.format(s1));

            isEdiging = false;
        }
    });

17

นี่เป็นข้อบกพร่องที่ทราบแล้วใน Android SDK วิธีแก้ปัญหาเพียงอย่างเดียวคือการสร้างแป้นพิมพ์อ่อนของคุณเอง คุณสามารถค้นหาตัวอย่างของการดำเนินงานที่นี่


15
มีข่าวหลังจากสี่ปีหรือไม่?
Antonio Sesto

พบสิ่งนี้ใน Xamarin.Forms เช่นกัน วัฒนธรรมคือ {se-SV} และตัวเลขแสดงบอท "," (ตัวคั่นทศนิยม) และ "." (ตัวคั่นพันกลุ่ม) แต่เมื่อกดปุ่ม "" จะไม่มีการป้อนข้อมูลใด ๆ ในช่องข้อความและไม่มีเหตุการณ์ใดเกิดขึ้น
joacar

ฉันสามารถยืนยันได้ว่าข้อบกพร่องยังคงมีอยู่
Lensflare

แก้ไขในตัวอย่างนักพัฒนา Android O
R00We

2
@ R00 เราเห็นว่าสิ่งนี้ถูกทำเครื่องหมายว่าได้รับการแก้ไขแล้วในเครื่องมือติดตามปัญหา แต่ฉันยังคงพบปัญหานี้เมื่อกำหนดเป้าหมาย API 29 คุณสามารถแก้ไขปัญหานี้ได้หรือเพียงแค่ยืนยันว่าได้รับการทำเครื่องหมายว่าแก้ไขแล้ว
masterwok

7

คุณสามารถใช้วิธีแก้ปัญหาต่อไปนี้เพื่อรวมเครื่องหมายจุลภาคเป็นอินพุตที่ถูกต้อง: -

ผ่าน XML:

<EditText
    android:inputType="number"
    android:digits="0123456789.," />

โดยทางโปรแกรม:

EditText input = new EditText(THE_CONTEXT);
input.setKeyListener(DigitsKeyListener.getInstance("0123456789.,"));

ด้วยวิธีนี้ระบบ Android จะแสดงแป้นพิมพ์ตัวเลขและอนุญาตให้ป้อนลูกน้ำ หวังว่านี่จะตอบคำถาม :)


ด้วยวิธีนี้เมื่อคุณแตะ "," แต่ข้อความแก้ไขจะแสดง ""
Mara Jimenez

6

คำตอบของ Martins จะไม่ทำงานหากคุณกำลังสร้างอินสแตนซ์ EditText แบบเป็นโปรแกรม ฉันดำเนินการต่อและแก้ไขDigitsKeyListenerคลาสที่รวมจาก API 14 เพื่อให้ทั้งลูกน้ำและจุดเป็นตัวคั่นทศนิยม

ที่จะใช้นี้โทรsetKeyListener()บนEditTextเช่น

// Don't allow for signed input (minus), but allow for decimal points
editText.setKeyListener( new MyDigitsKeyListener( false, true ) );

อย่างไรก็ตามคุณยังคงต้องใช้กลอุบายของ Martin ในการTextChangedListenerแทนที่เครื่องหมายจุลภาคด้วยจุด

import android.text.InputType;
import android.text.SpannableStringBuilder;
import android.text.Spanned;
import android.text.method.NumberKeyListener;
import android.view.KeyEvent;

class MyDigitsKeyListener extends NumberKeyListener {

    /**
     * The characters that are used.
     *
     * @see KeyEvent#getMatch
     * @see #getAcceptedChars
     */
    private static final char[][] CHARACTERS = new char[][] {
        new char[] { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' },
        new char[] { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '-' },
        new char[] { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '.', ',' },
        new char[] { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '-', '.', ',' },
    };

    private char[] mAccepted;
    private boolean mSign;
    private boolean mDecimal;

    private static final int SIGN = 1;
    private static final int DECIMAL = 2;

    private static MyDigitsKeyListener[] sInstance = new MyDigitsKeyListener[4];

    @Override
    protected char[] getAcceptedChars() {
        return mAccepted;
    }

    /**
     * Allocates a DigitsKeyListener that accepts the digits 0 through 9.
     */
    public MyDigitsKeyListener() {
        this(false, false);
    }

    /**
     * Allocates a DigitsKeyListener that accepts the digits 0 through 9,
     * plus the minus sign (only at the beginning) and/or decimal point
     * (only one per field) if specified.
     */
    public MyDigitsKeyListener(boolean sign, boolean decimal) {
        mSign = sign;
        mDecimal = decimal;

        int kind = (sign ? SIGN : 0) | (decimal ? DECIMAL : 0);
        mAccepted = CHARACTERS[kind];
    }

    /**
     * Returns a DigitsKeyListener that accepts the digits 0 through 9.
     */
    public static MyDigitsKeyListener getInstance() {
        return getInstance(false, false);
    }

    /**
     * Returns a DigitsKeyListener that accepts the digits 0 through 9,
     * plus the minus sign (only at the beginning) and/or decimal point
     * (only one per field) if specified.
     */
    public static MyDigitsKeyListener getInstance(boolean sign, boolean decimal) {
        int kind = (sign ? SIGN : 0) | (decimal ? DECIMAL : 0);

        if (sInstance[kind] != null)
            return sInstance[kind];

        sInstance[kind] = new MyDigitsKeyListener(sign, decimal);
        return sInstance[kind];
    }

    /**
     * Returns a DigitsKeyListener that accepts only the characters
     * that appear in the specified String.  Note that not all characters
     * may be available on every keyboard.
     */
    public static MyDigitsKeyListener getInstance(String accepted) {
        // TODO: do we need a cache of these to avoid allocating?

        MyDigitsKeyListener dim = new MyDigitsKeyListener();

        dim.mAccepted = new char[accepted.length()];
        accepted.getChars(0, accepted.length(), dim.mAccepted, 0);

        return dim;
    }

    public int getInputType() {
        int contentType = InputType.TYPE_CLASS_NUMBER;
        if (mSign) {
            contentType |= InputType.TYPE_NUMBER_FLAG_SIGNED;
        }
        if (mDecimal) {
            contentType |= InputType.TYPE_NUMBER_FLAG_DECIMAL;
        }
        return contentType;
    }

    @Override
    public CharSequence filter(CharSequence source, int start, int end,
                               Spanned dest, int dstart, int dend) {
        CharSequence out = super.filter(source, start, end, dest, dstart, dend);

        if (mSign == false && mDecimal == false) {
            return out;
        }

        if (out != null) {
            source = out;
            start = 0;
            end = out.length();
        }

        int sign = -1;
        int decimal = -1;
        int dlen = dest.length();

        /*
         * Find out if the existing text has '-' or '.' characters.
         */

        for (int i = 0; i < dstart; i++) {
            char c = dest.charAt(i);

            if (c == '-') {
                sign = i;
            } else if (c == '.' || c == ',') {
                decimal = i;
            }
        }
        for (int i = dend; i < dlen; i++) {
            char c = dest.charAt(i);

            if (c == '-') {
                return "";    // Nothing can be inserted in front of a '-'.
            } else if (c == '.' ||  c == ',') {
                decimal = i;
            }
        }

        /*
         * If it does, we must strip them out from the source.
         * In addition, '-' must be the very first character,
         * and nothing can be inserted before an existing '-'.
         * Go in reverse order so the offsets are stable.
         */

        SpannableStringBuilder stripped = null;

        for (int i = end - 1; i >= start; i--) {
            char c = source.charAt(i);
            boolean strip = false;

            if (c == '-') {
                if (i != start || dstart != 0) {
                    strip = true;
                } else if (sign >= 0) {
                    strip = true;
                } else {
                    sign = i;
                }
            } else if (c == '.' || c == ',') {
                if (decimal >= 0) {
                    strip = true;
                } else {
                    decimal = i;
                }
            }

            if (strip) {
                if (end == start + 1) {
                    return "";  // Only one character, and it was stripped.
                }

                if (stripped == null) {
                    stripped = new SpannableStringBuilder(source, start, end);
                }

                stripped.delete(i - start, i + 1 - start);
            }
        }

        if (stripped != null) {
            return stripped;
        } else if (out != null) {
            return out;
        } else {
            return null;
        }
    }
}

จาก doc: KeyListener ควรใช้เฉพาะในกรณีที่แอปพลิเคชันมีปุ่มกดบนหน้าจอเป็นของตัวเองและต้องการประมวลผลเหตุการณ์แป้นพิมพ์แบบแข็งเพื่อให้เข้ากันได้ developer.android.com/reference/android/text/method/…
Loda

6

คุณสามารถใช้สิ่งต่อไปนี้สำหรับภาษาต่างๆ

private void localeDecimalInput(final EditText editText){

    DecimalFormat decFormat = (DecimalFormat) DecimalFormat.getInstance(Locale.getDefault());
    DecimalFormatSymbols symbols=decFormat.getDecimalFormatSymbols();
    final String defaultSeperator=Character.toString(symbols.getDecimalSeparator());

    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) {

        }

        @Override
        public void afterTextChanged(Editable editable) {
            if(editable.toString().contains(defaultSeperator))
                editText.setKeyListener(DigitsKeyListener.getInstance("0123456789"));
            else
                editText.setKeyListener(DigitsKeyListener.getInstance("0123456789" + defaultSeperator));
        }
    });
}

นี่เป็นวิธีแก้ปัญหาที่ดีที่สุดสำหรับฉัน แต่มีปัญหากับโทรศัพท์บางรุ่นเช่น Samsung ซึ่งไม่แสดงอาการโคม่า "," ในแป้นพิมพ์ ดังนั้นฉันจึงเปลี่ยนสิ่งนี้เพื่อให้ทั้งโคม่าและจุด แต่จากนั้นแทนที่ตามสถานที่
Riccardo Casatta


1

คุณสามารถทำสิ่งต่อไปนี้:

DecimalFormatSymbols d = DecimalFormatSymbols.getInstance(Locale.getDefault());
input.setFilters(new InputFilter[] { new DecimalDigitsInputFilter(5, 2) });
input.setKeyListener(DigitsKeyListener.getInstance("0123456789" + d.getDecimalSeparator()));

จากนั้นคุณสามารถใช้ตัวกรองอินพุต:

    public class DecimalDigitsInputFilter implements InputFilter {

Pattern mPattern;

public DecimalDigitsInputFilter(int digitsBeforeZero, int digitsAfterZero) {
    DecimalFormatSymbols d = new DecimalFormatSymbols(Locale.getDefault());
    String s = "\\" + d.getDecimalSeparator();
    mPattern = Pattern.compile("[0-9]{0," + (digitsBeforeZero - 1) + "}+((" + s + "[0-9]{0," + (digitsAfterZero - 1) + "})?)||(" + s + ")?");
}

@Override
public CharSequence filter(CharSequence source, int start, int end, Spanned dest, int dstart, int dend) {

    Matcher matcher = mPattern.matcher(dest);
    if (!matcher.matches())
        return "";
    return null;
}

}


อาจมีช่องว่างระหว่างพันถึงร้อยรูปแบบนี้จะปฏิเสธอินพุตที่จัดรูปแบบ
Eric Zhao

1

IMHO แนวทางที่ดีที่สุดสำหรับปัญหานี้คือเพียงแค่ใช้ InputFilter จิที่ดีอยู่ที่นี่DecimalDigitsInputFilter จากนั้นคุณสามารถ:

editText.setInputType(TYPE_NUMBER_FLAG_DECIMAL | TYPE_NUMBER_FLAG_SIGNED | TYPE_CLASS_NUMBER)
editText.setKeyListener(DigitsKeyListener.getInstance("0123456789,.-"))
editText.setFilters(new InputFilter[] {new DecimalDigitsInputFilter(5,2)});

มันใช้งานได้เหมือนมีเสน่ห์ขอบคุณ! (หลังจากแก้ปัญหาผิดหลายข้อด้านบน ... :() แต่ฉันมีคำถาม: ฉันจะทำให้เครื่องหมายจุลภาค (",") ที่แสดงบนหน้าจอไม่ใช่จุด (".") ได้อย่างไรเพราะในฮังการีเราใช้ลูกน้ำเป็นตัวคั่นทศนิยม .
Abigail La'Fay

1
android: digit = "0123456789" สามารถเพิ่มการตั้งค่าใน EditText ได้ ยิ่งไปกว่านั้นแทนที่จะส่งคืนค่าว่างใน DecimalDigitsInputFilter คุณสามารถส่งคืน source.replace (".", ",") ตามคำตอบstackoverflow.com/a/40020731/1510222ไม่มีวิธีซ่อนจุดในแป้นพิมพ์มาตรฐาน
Arkadiusz Cieśliński

1

เพื่อรับการใช้อินพุตของคุณในท้องถิ่น:

char sep = DecimalFormatSymbols.getInstance().getDecimalSeparator();

จากนั้นเพิ่ม:

textEdit.setKeyListener(DigitsKeyListener.getInstance("0123456789" + sep));

อย่าลืมแทนที่ "," ด้วย "" ดังนั้น Float หรือ Double สามารถแยกวิเคราะห์ได้โดยไม่มีข้อผิดพลาด


1
วิธีนี้ช่วยให้ป้อนเครื่องหมายจุลภาคหลายรายการ
Leo Droidcoder

1

โพสต์อื่น ๆ ทั้งหมดที่นี่มีช่องโหว่ที่สำคัญดังนั้นนี่คือวิธีแก้ปัญหาที่จะ:

  • บังคับใช้เครื่องหมายจุลภาคหรือจุดตามภูมิภาคจะไม่ให้คุณพิมพ์ตรงข้าม
  • หาก EditText เริ่มต้นด้วยค่าบางค่าจะแทนที่ตัวคั่นที่ถูกต้องตามต้องการ

ใน XML:

<EditText
    ...
    android:inputType="numberDecimal" 
    ... />

ตัวแปรคลาส:

private boolean isDecimalSeparatorComma = false;

ใน onCreate ค้นหาตัวคั่นที่ใช้ในภาษาปัจจุบัน:

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
    NumberFormat nf = NumberFormat.getInstance();
    if (nf instanceof DecimalFormat) {
        DecimalFormatSymbols sym = ((DecimalFormat) nf).getDecimalFormatSymbols();
        char decSeparator = sym.getDecimalSeparator();
        isDecimalSeparatorComma = Character.toString(decSeparator).equals(",");
    }
}

นอกจากนี้ onCreate ใช้สิ่งนี้เพื่ออัปเดตหากคุณกำลังโหลดด้วยค่าปัจจุบัน:

// Replace editText with commas or periods as needed for viewing
String editTextValue = getEditTextValue(); // load your current value
if (editTextValue.contains(".") && isDecimalSeparatorComma) {
    editTextValue = editTextValue.replaceAll("\\.",",");
} else if (editTextValue.contains(",") && !isDecimalSeparatorComma) {
    editTextValue = editTextValue.replaceAll(",",".");
}
setEditTextValue(editTextValue); // override your current value

นอกจากนี้ onCreate เพิ่มผู้ฟัง

editText.addTextChangedListener(editTextWatcher);

if (isDecimalSeparatorComma) {
    editText.setKeyListener(DigitsKeyListener.getInstance("0123456789,"));
} else {
    editText.setKeyListener(DigitsKeyListener.getInstance("0123456789."));
}

editTextWatcher

TextWatcher editTextWatcher = 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) { }

    @Override
    public void afterTextChanged(Editable s) {
        String editTextValue = s.toString();

        // Count up the number of commas and periods
        Pattern pattern = Pattern.compile("[,.]");
        Matcher matcher = pattern.matcher(editTextValue);
        int count = 0;
        while (matcher.find()) {
            count++;
        }

        // Don't let it put more than one comma or period
        if (count > 1) {
            s.delete(s.length()-1, s.length());
        } else {
            // If there is a comma or period at the end the value hasn't changed so don't update
            if (!editTextValue.endsWith(",") && !editTextValue.endsWith(".")) {
                doSomething()
            }
        }
    }
};

doSomething () ตัวอย่างแปลงเป็นช่วงเวลามาตรฐานสำหรับการจัดการข้อมูล

private void doSomething() {
    try {
        String editTextStr = editText.getText().toString();
        if (isDecimalSeparatorComma) {
            editTextStr = editTextStr.replaceAll(",",".");
        }
        float editTextFloatValue = editTextStr.isEmpty() ?
                0.0f :
                Float.valueOf(editTextStr);

        ... use editTextFloatValue
    } catch (NumberFormatException e) {
        Log.e(TAG, "Error converting String to Double");
    }
}

0

Android มีตัวจัดรูปแบบตัวเลขในตัว

คุณสามารถเพิ่มสิ่งนี้ลงในของคุณEditTextเพื่ออนุญาตทศนิยมและลูกน้ำ: android:inputType="numberDecimal"และandroid:digits="0123456789.,"

จากนั้นจะอยู่ที่ไหนสักแห่งในรหัสของคุณไม่ว่าจะเมื่อผู้ใช้คลิกบันทึกหรือหลังจากป้อนข้อความ (ใช้ตัวฟัง)

// Format the number to the appropriate double
try { 
    Number formatted = NumberFormat.getInstance().parse(editText.getText().toString());
    cost = formatted.doubleValue();
} catch (ParseException e) {
    System.out.println("Error parsing cost string " + editText.getText().toString());
    cost = 0.0;
}

0

ฉันตัดสินใจเปลี่ยนลูกน้ำเป็นจุดเฉพาะในขณะที่แก้ไข นี่คือวิธีแก้ปัญหาง่ายๆที่ยุ่งยากและสัมพันธ์กับฉัน:

    editText.setOnFocusChangeListener(new View.OnFocusChangeListener() {
        @Override
        public void onFocusChange(View v, boolean hasFocus) {
            EditText editText = (EditText) v; 
            String text = editText.getText().toString();
            if (hasFocus) {
                editText.setText(text.replace(",", "."));
            } else {
                if (!text.isEmpty()) {
                    Double doubleValue = Double.valueOf(text.replace(",", "."));
                    editText.setText(someDecimalFormatter.format(doubleValue));
                }
            }
        }
    });

someDecimalFormatter จะใช้ลูกน้ำหรือจุดขึ้นอยู่กับ Locale


0

ฉันไม่รู้ว่าทำไมคำตอบของคุณถึงซับซ้อนขนาดนี้ หากมีข้อบกพร่องใน SDK คุณต้องลบล้างหรือดำเนินการต่อ

ฉันได้เลือกวิธีที่สองในการแก้ปัญหานั้น หากคุณจัดรูปแบบสตริงของคุณเป็นLocale.ENGLISHแล้วใส่ลงในEditText(แม้จะเป็นสตริงว่าง) ตัวอย่าง:

String.format(Locale.ENGLISH,"%.6f", yourFloatNumber);

การไล่ตามโซลูชันนั้นผลลัพธ์ของคุณเข้ากันได้กับแป้นพิมพ์ที่แสดง จากนั้นตัวเลขลอยตัวและเลขซ้อนจะทำงานตามแบบฉบับของภาษาโปรแกรมด้วยจุดแทนลูกน้ำ


0

ทางออกของฉันคือ:

  • ในกิจกรรมหลัก:

    char separator =DecimalFormatSymbols.getInstance().getDecimalSeparator(); textViewPitchDeadZone.setKeyListener(DigitsKeyListener.getInstance("0123456789" + separator));

  • ในไฟล์ xml: android:imeOptions="flagNoFullscreen" android:inputType="numberDecimal"

และฉันเอา double ใน editText เป็น String


0

ฉันสามารถยืนยันได้ว่าการแก้ไขที่เสนอใช้ไม่ได้กับ Samsung IMEs (อย่างน้อยก็ใน S6 และ S9) และอาจเป็น LG โดยยังคงแสดงจุดเป็นตัวคั่นทศนิยมโดยไม่คำนึงถึงภาษา การเปลี่ยนไปใช้ IME ของ Google ช่วยแก้ปัญหานี้ได้ แต่แทบจะไม่เป็นตัวเลือกสำหรับนักพัฒนาส่วนใหญ่

นอกจากนี้ยังไม่ได้รับการแก้ไขใน Oreo สำหรับคีย์บอร์ดเหล่านี้เนื่องจากเป็นการแก้ไขที่ Samsung และ / หรือ LG ต้องทำจากนั้นจึงจะผลักดันไปยังโทรศัพท์มือถือรุ่นเก่าของพวกเขา

ฉันได้คดเคี้ยวแทนโครงการจำนวนแป้นพิมพ์และเพิ่มโหมดที่มันจะทำงานเหมือน IME A: ส้อม ดูตัวอย่างโครงการเพื่อดูรายละเอียด วิธีนี้ใช้ได้ผลดีสำหรับฉันและคล้ายกับ IME ปลอม "การป้อน PIN" หลายรายการที่คุณเห็นในแอปธนาคาร

ตัวอย่างภาพหน้าจอแอป


0

เวลาผ่านไปกว่า 8 ปีแล้วและฉันรู้สึกประหลาดใจปัญหานี้ยังไม่ได้รับการแก้ไข ...
ฉันต่อสู้กับปัญหาง่ายๆนี้เนื่องจากคำตอบที่ได้รับการโหวตมากที่สุดโดย @Martin ช่วยให้สามารถพิมพ์ตัวคั่นได้หลายตัวกล่าวคือผู้ใช้สามารถพิมพ์ "12 ,,, ,,, 12,1,, 21,2, "
นอกจากนี้ข้อกังวลประการที่สองคือในอุปกรณ์บางเครื่องจะไม่แสดงเครื่องหมายจุลภาคบนแป้นพิมพ์ตัวเลข (หรือต้องกดปุ่มจุดหลาย ๆ ครั้ง)

นี่คือวิธีแก้ปัญหาของฉันซึ่งช่วยแก้ปัญหาที่กล่าวถึงและให้ผู้ใช้พิมพ์ "." และ ',' แต่ใน EditText เขาจะเห็นตัวคั่นทศนิยมเพียงตัวเดียวซึ่งสอดคล้องกับโลแคลปัจจุบัน:

editText.apply { addTextChangedListener(DoubleTextChangedListener(this)) }

และผู้เฝ้าดูข้อความ:

  open class DoubleTextChangedListener(private val et: EditText) : TextWatcher {

    init {
        et.inputType = InputType.TYPE_CLASS_NUMBER or InputType.TYPE_NUMBER_FLAG_DECIMAL
        et.keyListener = DigitsKeyListener.getInstance("0123456789.,")
    }

    private val separator = DecimalFormatSymbols.getInstance().decimalSeparator

    override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {
        //empty
    }

    @CallSuper
    override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {
        et.run {
            removeTextChangedListener(this@DoubleTextChangedListener)
            val formatted = toLocalizedDecimal(s.toString(), separator)
            setText(formatted)
            setSelection(formatted.length)
            addTextChangedListener(this@DoubleTextChangedListener)
        }
    }

    override fun afterTextChanged(s: Editable?) {
        // empty
    }

    /**
     * Formats input to a decimal. Leaves the only separator (or none), which matches [separator].
     * Examples:
     * 1. [s]="12.12", [separator]=',' -> result= "12,12"
     * 2. [s]="12.12", [separator]='.' -> result= "12.12"
     * 4. [s]="12,12", [separator]='.' -> result= "12.12"
     * 5. [s]="12,12,,..,,,,,34..,", [separator]=',' -> result= "12,1234"
     * 6. [s]="12.12,,..,,,,,34..,", [separator]='.' -> result= "12.1234"
     * 7. [s]="5" -> result= "5"
     */
    private fun toLocalizedDecimal(s: String, separator: Char): String {
        val cleared = s.replace(",", ".")
        val splitted = cleared.split('.').filter { it.isNotBlank() }
        return when (splitted.size) {
            0 -> s
            1 -> cleared.replace('.', separator).replaceAfter(separator, "")
            2 -> splitted.joinToString(separator.toString())
            else -> splitted[0]
                    .plus(separator)
                    .plus(splitted.subList(1, splitted.size - 1).joinToString(""))
        }
    }
}

0

วิธีแก้ปัญหาง่ายๆทำการควบคุมแบบกำหนดเอง (ทำใน Xamarin android แต่ควรพอร์ตไปยัง java ได้อย่างง่ายดาย)

public class EditTextDecimalNumber:EditText
{
    readonly string _numberFormatDecimalSeparator;

    public EditTextDecimalNumber(Context context, IAttributeSet attrs) : base(context, attrs)
    {
        InputType = InputTypes.NumberFlagDecimal;
        TextChanged += EditTextDecimalNumber_TextChanged;
        _numberFormatDecimalSeparator = System.Threading.Thread.CurrentThread.CurrentUICulture.NumberFormat.NumberDecimalSeparator;

        KeyListener = DigitsKeyListener.GetInstance($"0123456789{_numberFormatDecimalSeparator}");
    }

    private void EditTextDecimalNumber_TextChanged(object sender, TextChangedEventArgs e)
    {
        int noOfOccurence = this.Text.Count(x => x.ToString() == _numberFormatDecimalSeparator);
        if (noOfOccurence >=2)
        {
            int lastIndexOf = this.Text.LastIndexOf(_numberFormatDecimalSeparator,StringComparison.CurrentCulture);
            if (lastIndexOf!=-1)
            {
                this.Text = this.Text.Substring(0, lastIndexOf);
                this.SetSelection(this.Text.Length);
            }

        }
    }
}

0

คุณสามารถใช้ได้inputType="phone"อย่างไรก็ตามในกรณีนั้นคุณจะต้องจัดการกับหลายรายการ,หรือ.มีอยู่ดังนั้นการตรวจสอบความถูกต้องเพิ่มเติมจึงจำเป็น


0

การแก้ไขของฉันสำหรับ KOTLIN

ฉันเจอข้อผิดพลาดเดียวกันซึ่งฉันแก้ไขด้วย:

val separator = DecimalFormatSymbols.getInstance().decimalSeparator
mEditText.keyListener = DigitsKeyListener.getInstance("0123456789$separator")

และใช้งานได้ดีทีเดียว !แต่! บนแป้นพิมพ์ Samsung จะไม่แสดงตัวคั่นดังนั้นคุณจึงไม่สามารถพิมพ์ตัวเลขทศนิยมได้

ดังนั้นฉันจึงต้องแก้ไขปัญหานี้ด้วยการตรวจสอบหากใช้แป้นพิมพ์ Samsung:

    val x = Settings.Secure.getString(getContentResolver(), Settings.Secure.DEFAULT_INPUT_METHOD);
    if (x.toLowerCase().contains("samsung")) {}
  

แต่แล้วคุณก็ยังมี "." เป็นตัวคั่นทศนิยม ดังนั้นคุณต้องแทนที่จุดด้วยลูกน้ำถ้าตัวคั่นเป็นลูกน้ำ:

val separator: Char = DecimalFormatSymbols.getInstance().decimalSeparator
 
  if (separator == ',') {
     mEditText.addTextChangedListener(object : TextWatcher {
                        override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) = Unit
    
                        override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) = Unit
    
                        override fun afterTextChanged(s: Editable?) {
    
                            if (!s.isNullOrEmpty()) {
                                
                                    if (s.toString().contains(".")) {
                                        val replaced = s.toString().replace('.', separator)
                                        mEditText.setText(replaced)
                                        mEditText.setSelection(replaced.length)
                                    }
    
                                
                            }
                        }
                    })
                }

แต่คุณต้องตรวจสอบว่าไม่มีใครพิมพ์ "," มากกว่านี้ใน EditTextfield ซึ่งสามารถทำได้ด้วย Regex

วิธีแก้ปัญหาทั้งหมดของฉัน:

val x = Settings.Secure.getString(getContentResolver(), Settings.Secure.DEFAULT_INPUT_METHOD);
  if (x.toLowerCase().contains("samsung")) {
         val Number_REGEX: Pattern =  Pattern.compile("^([1-9])*([.,]{1}[0-9]{0,10})?$")
         val separator: Char = DecimalFormatSymbols.getInstance().decimalSeparator
         if (separator == ',') {
            mEditText.addTextChangedListener(object : TextWatcher {
                override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) = Unit

                override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) = Unit

                override fun afterTextChanged(s: Editable?) {

                    if (!s.isNullOrEmpty()) {
                        val matcherMail = Number_REGEX.matcher(s.toString())
                        if (!matcherMail.matches()) {
                            val length: Int = s.length

                            s.delete(length - 1, length);
                        } else {
                            if (s.toString().contains(".")) {
                                val replaced = s.toString().replace('.', separator)
                                mEditText.setText(replaced)
                                mEditText.setSelection(replaced.length)
                            }

                        }
                    }
                }
            })
        }
    } else {
        val separator = DecimalFormatSymbols.getInstance().decimalSeparator
        mEditText.keyListener = DigitsKeyListener.getInstance("0123456789$separator")
       
    }

ไฟล์ xml:

 <com.google.android.material.textfield.TextInputEditText
        android:id="@+id/tEditText"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="Input"
        android:inputType="numberDecimal"
        android:imeOptions="actionDone"/>

หากคุณต้องการใช้หมายเลขตรวจสอบให้แน่ใจว่าได้รับรูปแบบที่ถูกต้อง:

val x = NumberFormat.getInstance().parse(mEditText.text.toString()).toDouble()

-3

ฉันคิดว่าวิธีนี้ซับซ้อนน้อยกว่าวิธีอื่นที่เขียนไว้ที่นี่:

<EditText
    android:inputType="numberDecimal"
    android:digits="0123456789," />

ด้วยวิธีนี้เมื่อคุณกดปุ่ม "." ในแป้นพิมพ์อ่อนไม่มีอะไรเกิดขึ้น อนุญาตให้ใช้เฉพาะตัวเลขและเครื่องหมายจุลภาคเท่านั้น


5
ถ้าคุณทำเช่นนี้คุณจะทำลายทุกภาษาที่ใช้ "." แทน.
นิค
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.