安卓中IP地址文本框?

12

我完全不懂 Android。

我想放置一个文本框,让用户输入 IP 地址……但是如何限制用户只输入数字呢?……还有,如何验证输入的地址是否正确?

有没有现成的 IP 地址文本框可以直接使用呢?

谢谢!

Mojo

9个回答

13

我发现有效的方法是将 EditText 设置为使用 android:inputType="phone",这样输入会被限制为数字、句点和一些其他字符。但是,这仅允许您输入IPV4地址,因为它只有数字。要进行验证,您需要手动获取输入文本并解析它。

至于现成的输入部件,我还没有找到过。


9
除了Erich说的,您还可以使用android:digits="0123456789."来禁止除数字和小数点以外的任何字符。

1
在LG G2 / Lolipop上,即使在“android:digits”中有句号,键盘也没有句号,因此无法使用“数字”类型输入IPv4地址。 - Victor Sergienko

8
您可以使用:

EditText ipAddress = (EditText)findViewById(R.id.ip_address);
InputFilter[] filters = new InputFilter[1];
    filters[0] = new InputFilter() {
        @Override
        public CharSequence filter(CharSequence source, int start, int end,
                android.text.Spanned dest, int dstart, int dend) {
            if (end > start) {
                String destTxt = dest.toString();
                String resultingTxt = destTxt.substring(0, dstart) + source.subSequence(start, end) + destTxt.substring(dend);
                if (!resultingTxt.matches ("^\\d{1,3}(\\.(\\d{1,3}(\\.(\\d{1,3}(\\.(\\d{1,3})?)?)?)?)?)?")) { 
                    return "";
                } else {
                    String[] splits = resultingTxt.split("\\.");
                    for (int i=0; i<splits.length; i++) {
                        if (Integer.valueOf(splits[i]) > 255) {
                            return "";
                        }
                    }
                }
            }
            return null;
        }

    };
    ipAddress.setFilters(filters);

7

用于验证IP地址的正则表达式可在regular-expressions.info网站上找到,该网站提供了一个良好的正则表达式字符串,您可以用它来测试是否在有效范围内(0-255):

\b(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?).(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?).(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?).(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\b


是的,我希望有一种类似于掩码文本框的东西,但正则表达式是一个好的解决方案 - 谢谢! - MojoDK
是的,你可能可以扩展自定义文本框,但我甚至不知道从哪里开始。祝你好运! - Kevin Coppock

5

我认为这是现有解决方案中最完整的一个(至少是我发现的)。唯一可以想象的改进是实现一个新的KeyListener以更好地限制输入,但鉴于IME与布局等方面的工作方式,我并不确定这在实践中是否可行。

public class IPAddressText extends EditText {

    public IPAddressText(Context context) {
        super(context);

        setInputType(InputType.TYPE_CLASS_PHONE);
        setFilters(new InputFilter[] { new InputFilter(){
            @Override
            public CharSequence filter(CharSequence source, int start, int end, android.text.Spanned dest, int dstart, int dend) {
                if (end > start) {
                    String destTxt = dest.toString();
                    String resultingTxt = destTxt.substring(0, dstart) + source.subSequence(start, end) + destTxt.substring(dend);
                    if (!resultingTxt.matches("^\\d{1,3}(\\.(\\d{1,3}(\\.(\\d{1,3}(\\.(\\d{1,3})?)?)?)?)?)?")) {
                        return "";
                    }
                    else {
                        String[] splits = resultingTxt.split("\\.");
                        for (int i = 0; i < splits.length; i++) {
                            if (Integer.valueOf(splits[i]) > 255) {
                                return "";
                            }
                        }
                    }
                }
                return null;
            }
        }
        });

        addTextChangedListener(new TextWatcher(){
            boolean deleting = false;
            int lastCount = 0;

            @Override
                public void afterTextChanged(Editable s) {
                    if (!deleting) {
                        String working = s.toString();
                        String[] split = working.split("\\.");
                        String string = split[split.length - 1];
                        if (string.length() == 3 || string.equalsIgnoreCase("0")
                            || (string.length() == 2 && Character.getNumericValue(string.charAt(0)) > 1)) {
                            s.append('.');
                            return;
                        }
                    }
                }

            @Override
                public void onTextChanged(CharSequence s, int start, int before, int count) {
                    if (lastCount < count) {
                        deleting = false;
                    }
                    else {
                        deleting = true;
                    }
                }

            @Override
                public void beforeTextChanged(CharSequence s, int start, int count, int after) {
                    // Nothing happens here
                }
        });
    }
}

因为这是我最终使用的,所以这里提供一个EditTextPreference版本:

public class IPAddressPreference extends EditTextPreference {

    public IPAddressPreference(Context context) {
        super(context);

        getEditText().setInputType(InputType.TYPE_CLASS_PHONE);
        getEditText().setFilters(new InputFilter[] { new InputFilter(){
            @Override
            public CharSequence filter(CharSequence source, int start, int end, android.text.Spanned dest, int dstart, int dend) {
                if (end > start) {
                    String destTxt = dest.toString();
                    String resultingTxt = destTxt.substring(0, dstart) + source.subSequence(start, end) + destTxt.substring(dend);
                    if (!resultingTxt.matches("^\\d{1,3}(\\.(\\d{1,3}(\\.(\\d{1,3}(\\.(\\d{1,3})?)?)?)?)?)?")) {
                        return "";
                    }
                    else {
                        String[] splits = resultingTxt.split("\\.");
                        for (int i = 0; i < splits.length; i++) {
                            if (Integer.valueOf(splits[i]) > 255) {
                                return "";
                            }
                        }
                    }
                }
                return null;
            }
        }
        });

        getEditText().addTextChangedListener(new TextWatcher(){
            boolean deleting = false;
            int lastCount = 0;

            @Override
                public void afterTextChanged(Editable s) {
                    if (!deleting) {
                        String working = s.toString();
                        String[] split = working.split("\\.");
                        String string = split[split.length - 1];
                        if (string.length() == 3 || string.equalsIgnoreCase("0")
                            || (string.length() == 2 && Character.getNumericValue(string.charAt(0)) > 1)) {
                            s.append('.');
                            return;
                        }
                    }
                }

            @Override
                public void onTextChanged(CharSequence s, int start, int before, int count) {
                    if (lastCount < count) {
                        deleting = false;
                    }
                    else {
                        deleting = true;
                    }
                }

            @Override
                public void beforeTextChanged(CharSequence s, int start, int count, int after) {
                    // Nothing happens here
                }
        });
    }
}

2
有用,但是你的“afterTextChanged”方法不太好。 我删除了“string.equalsIgnoreCase(“0”)”,并将“Character.getNumericValue(string.charAt(0))> 1)”更改为“Integer.parseInt(string)> 25)”。 - RaphMclee
这是我找到的最佳解决方案,但不是100%完整的。在输入有效的IP地址(例如123.45.67.89)后,如果我们删除其中一个点,则该IP将变为无效。我认为在这种情况下不应该能够删除点。 - Ryan Amaral

0

基于NathanOliver和enneract的代码,我用Kotlin编写了一个变体,在删除一个点时插入一个点。

class IpAddressEditText : AppCompatEditText {

    constructor(context: Context) : super(context) {
        init()
    }

    constructor(context: Context, attrs: AttributeSet) : super(context, attrs) {
        init()
    }

    constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super(context, attrs, defStyleAttr) {
        init()
    }

    private fun init() {
        // phone input type to show the numeric keyboard in all kinds of devices
        inputType = InputType.TYPE_CLASS_PHONE

        // restrict the input of the characters specified in string bellow
        keyListener = DigitsKeyListener.getInstance("0123456789.")

        // InputFilter decides what can be typed
        filters = arrayOf(InputFilter { source, start, end, dest, dstart, dend ->
            if (end > start) {
                val inputString = dest.toString()
                val substring = inputString.substring(0, dstart) + source.subSequence(start, end) + inputString.substring(dend)

                if (!substring.matches("^\\d{1,3}(\\.(\\d{1,3}(\\.(\\d{1,3}(\\.(\\d{1,3})?)?)?)?)?)?".toRegex())) {
                    // do not allow the input of:
                    //  segments with more than 3 characters and less than 1;
                    //  segments != 4;
                    return@InputFilter ""

                } else {
                    val splits = substring.split("\\.".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()
                    for (i in splits.indices) {
                        // don't allow a segment with a value more than 255
                        if (Integer.valueOf(splits[i]) > 255) {
                            return@InputFilter ""
                        }
                    }
                }
            }
            null
        })

        // TextWatcher notifies what was typed
        addTextChangedListener(object : TextWatcher {
            var isDeleting = false
            var lastCount = 0

            override fun afterTextChanged(editable: Editable) {
                if (!isDeleting) {
                    val inputString = editable.toString()
                    val segmentList = inputString.split("\\.".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()
                    val lastSegment = segmentList[segmentList.size - 1]

                    // each segment of the ip can have max size of 3 characters and a max value of 255
                    if (lastSegment.length == 3 || lastSegment.length == 2 && Integer.parseInt(lastSegment) > 25) {

                        // add a dot automatically if the conditions met
                        editable.append('.')
                        return
                    }
                } else {
                    // add a dot in the same position where it was deleted
                    editable.insert(selectionStart, ".")
                }
            }

            override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {
                isDeleting = lastCount >= count
            }

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

0
以下是一段代码,它通过显示一个只包含数字和小数点的软键盘,来限制用户只能输入数字和小数点(但允许输入多个小数点)。
 etIpAddress.setInputType(InputType.TYPE_CLASS_NUMBER);
 etIpAddress.setInputType(InputType.TYPE_NUMBER_FLAG_DECIMAL);
 etIpAddress.setKeyListener(DigitsKeyListener.getInstance(false,false));
 etIpAddress.setKeyListener(DigitsKeyListener.getInstance("0123456789."));

0
  <EditText
        android:id="@+id/ip_address"
        android:inputType="number|numberDecimal"
        android:digits="0123456789."
        android:layout_width="match_parent"
        android:layout_height="wrap_content"/>

对我有用


您可能希望添加一些解释,以说明它如何解决手头的问题。 - Adonis

0
我正在使用这个TextWatcher:
public class IPTextWatcher implements TextWatcher
{
    private static String LOG_TAG = "IPTextWatcher";

    private EditText editText;
    private BarcodeTextWatcher.ChangeListener listener = null;

    public IPTextWatcher( EditText editText )
    {
        this.editText = editText;
    }

    private static final String IPADDRESS_PATTERN =
            "^([01]?\\d\\d?|2[0-4]\\d|25[0-5])\\." +
                    "([01]?\\d\\d?|2[0-4]\\d|25[0-5])\\." +
                    "([01]?\\d\\d?|2[0-4]\\d|25[0-5])\\." +
                    "([01]?\\d\\d?|2[0-4]\\d|25[0-5])$";

    @Override
    public void afterTextChanged( Editable s )
    {
        Log.v( LOG_TAG, s.toString() );

        if( !s.toString().matches( IPADDRESS_PATTERN ) )
        {
            String ip = format( s.toString() );

            editText.removeTextChangedListener( this );
            editText.setText( ip );

            editText.setTextKeepState( ip );
            Selection.setSelection( editText.getText(), ip.length() );

            editText.addTextChangedListener( this );

            if( listener != null )
                listener.onChange();
        }
    }

    public static String format( String value )
    {
        String userInput = "" + value.replaceAll( "[^\\d\\.]", "" );
        StringBuilder ipBuilder = new StringBuilder();

        String[] address = userInput.split("\\.");

        String glue = null;
        for( String part : address )
        {
            if( glue != null ) ipBuilder.append( glue );

            int p = Integer.valueOf( part );

            if( p >= 256 )
            {
                int i = 1;

                do
                {
                    p = Integer.valueOf( part.substring( 0, part.length() -i ) );
                    i++;
                }
                while( p >= 256 );
            }

            ipBuilder.append( p );

            glue = ".";
        }

        if( userInput.charAt( userInput.length()-1 ) == '.' )
            ipBuilder.append( "." );

        return ipBuilder.toString();
    }

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

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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接