2014-11-02 38 views
4

我想为我的应用程序使用自定义ViewGroup。在这我使用以下xml在我的ViewGroup类中充气。Textwatcher无法在KitKat上输入数字作为inputType

<?xml version="1.0" encoding="utf-8"?> 
<!-- This layout is used wherever the pin entering screens used --> 
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 
    android:layout_width="match_parent" 
    android:layout_height="wrap_content" 
    android:gravity="center" 
    android:orientation="horizontal" > 

    <TextView 
     android:id="@+id/textView1" 
     style="?attr/txtNormalStyle" 
     android:layout_width="wrap_content" 
     android:layout_height="wrap_content" 
     android:background="@android:drawable/editbox_background_normal" 
     android:ems="1" 
     android:inputType="numberPassword" /> 

    <TextView 
     android:id="@+id/textView2" 
     style="?attr/txtNormalStyle" 
     android:layout_width="wrap_content" 
     android:layout_height="wrap_content" 
     android:background="@android:drawable/editbox_background_normal" 
     android:ems="1" 
     android:inputType="numberPassword" /> 

    <TextView 
     android:id="@+id/textView3" 
     style="?attr/txtNormalStyle" 
     android:layout_width="wrap_content" 
     android:layout_height="wrap_content" 
     android:background="@android:drawable/editbox_background_normal" 
     android:ems="1" 
     android:inputType="numberPassword" /> 

    <TextView 
     android:id="@+id/textView4" 
     style="?attr/txtNormalStyle" 
     android:layout_width="wrap_content" 
     android:layout_height="wrap_content" 
     android:background="@android:drawable/editbox_background_normal" 
     android:ems="1" 
     android:inputType="numberPassword" /> 

    <EditText 
     android:id="@+id/edtInvisible" 
     android:layout_width="0dp" 
     android:layout_height="wrap_content" 
     android:inputType="text" 
     android:maxLength="4" 
     android:visibility="visible" /> 
    </LinearLayout> 

而以下是我的扩展视图组类

public class View_Pin_Text extends LinearLayout implements 
     View.OnClickListener, TextWatcher, View.OnKeyListener { 

    private String strPin; 
    private TextView txtView1, txtView2, txtView3, txtView4; 
    private EditText edtText; 
    private boolean isInTextWatcher = false; 

    public View_Pin_Text(Context context, AttributeSet attrs) { 
     super(context, attrs); 

     // inflating the custom layout for the view group 
     LayoutInflater mInflater = (LayoutInflater) context 
       .getSystemService(Context.LAYOUT_INFLATER_SERVICE); 
     mInflater.inflate(R.layout.view_pin_enter, this, true); 

     // 4 text views for showing pin to user 
     txtView1 = (TextView) findViewById(R.id.textView1); 
     txtView2 = (TextView) findViewById(R.id.textView2); 
     txtView3 = (TextView) findViewById(R.id.textView3); 
     txtView4 = (TextView) findViewById(R.id.textView4); 

     // setting on click listener 
     txtView1.setOnClickListener(this); 
     txtView2.setOnClickListener(this); 
     txtView3.setOnClickListener(this); 
     txtView4.setOnClickListener(this); 

     // invisible edit text for invoking keyboard 
     edtText = (EditText) findViewById(R.id.edtInvisible); 

     // text change listener to update the input in text views 
     edtText.addTextChangedListener(this); 

     // key listener to handle backspace/del keys press 
     edtText.setOnKeyListener(this); 

    } 

    /** 
    * @return strPin 
    *   <p> 
    *   Gives the currently given pin by the user 
    *   </p> 
    */ 
    public String getStrPin() { 
     return strPin; 
    } 

    /** 
    * @param strPin 
    *   <p> 
    *   Sets the pin to instance object and updates the proper 
    *   characters in all text views 
    *   </p> 
    */ 
    public void setStrPin(String strPin) { 

     if (strPin != null) { 
      int lenght = strPin.length(); 

      if (lenght <= 4) 
       this.strPin = strPin; 

      Log.d("text", strPin); 

      switch (lenght) { 
      case 0: 
       txtView1.setText(""); 
       txtView2.setText(""); 
       txtView3.setText(""); 
       txtView4.setText(""); 
       break; 
      case 1: 
       txtView1.setText(String.valueOf(strPin.charAt(0))); 
       txtView2.setText(""); 
       txtView3.setText(""); 
       txtView4.setText(""); 
       break; 
      case 2: 
       txtView1.setText(String.valueOf(strPin.charAt(0))); 
       txtView2.setText(String.valueOf(strPin.charAt(1))); 
       txtView3.setText(""); 
       txtView4.setText(""); 
       break; 
      case 3: 
       txtView1.setText(String.valueOf(strPin.charAt(0))); 
       txtView2.setText(String.valueOf(strPin.charAt(1))); 
       txtView3.setText(String.valueOf(strPin.charAt(2))); 
       txtView4.setText(""); 
       break; 
      case 4: 
       txtView1.setText(String.valueOf(strPin.charAt(0))); 
       txtView2.setText(String.valueOf(strPin.charAt(1))); 
       txtView3.setText(String.valueOf(strPin.charAt(2))); 
       txtView4.setText(String.valueOf(strPin.charAt(3))); 
       ((InputMethodManager) getContext().getSystemService(
         Context.INPUT_METHOD_SERVICE)).hideSoftInputFromWindow(
         edtText.getWindowToken(), 0); 
       break; 
      } 
     } else { 
      this.strPin = strPin; 
     } 
    } 

    @Override 
    public void onClick(View v) { 
     Toast.makeText(getContext(), "OnClick", Toast.LENGTH_SHORT).show(); 
     ((InputMethodManager) getContext().getSystemService(
       Context.INPUT_METHOD_SERVICE)).showSoftInput(edtText, 
       InputMethodManager.SHOW_FORCED); 
    } 

    @Override 
    public void afterTextChanged(Editable s) { 

     if (isInTextWatcher) 
      return; 

     isInTextWatcher = true; 

     Log.d("text", "changed-" + s.toString()); 

     if (getStrPin() == null) { 
      setStrPin(s.toString()); 
     } else { 
      setStrPin(getStrPin() + "" + s.toString()); 
     } 
     edtText.setText(""); 

     isInTextWatcher = false; 
    } 

    @Override 
    public void beforeTextChanged(CharSequence arg0, int arg1, int arg2, 
      int arg3) { 

    } 

    @Override 
    public void onTextChanged(CharSequence cs, int arg1, int arg2, int arg3) { 
    } 

    @Override 
    public boolean onKey(View v, int keyCode, KeyEvent event) { 

     if (keyCode == KeyEvent.KEYCODE_DEL 
       && event.getAction() != KeyEvent.ACTION_DOWN) { 
      if (getStrPin() != null) { 
       int length = getStrPin().length(); 
       if (length > 0) { 
        setStrPin(getStrPin() 
          .substring(0, getStrPin().length() - 1)); 
       } 
      } 
     } 
     return true; 
    } 

    } 

在此上课的时候我的编辑文本设置为安卓afterTextChanged我的文字观察家则不会触发:的inputType =“号”和适用于我的nexus 5(Kitkat 4.4.4)中的文本输入。但是,当我用三星核心(Jellybean 4.1.2)尝试它的工作正常..那么,这是什么问题,这应该如何解决?

+0

你有没有想过这个?我仍然有这个问题。我在我的TextWatcher中将“/”添加到出生日期,并且我只需要数字,但现在不会使用数字来触发 – 2014-12-01 22:14:35

回答

2

Android自己的软键盘(LatinIME)处理数字输入与其他字符稍有不同。这里是发生了什么:

private void sendKeyCodePoint(final int code) { 
    .... 
    .... 

    // TODO: Remove this special handling of digit letters. 
    // For backward compatibility. See {@link InputMethodService#sendKeyChar(char)}. 
    if (code >= '0' && code <= '9') { 
     sendDownUpKeyEvent(code - '0' + KeyEvent.KEYCODE_0); 
     return; 
    } 

    if (Constants.CODE_ENTER == code && mAppWorkAroundsUtils.isBeforeJellyBean()) { 
     // Backward compatibility mode. Before Jelly bean, the keyboard would simulate 
     // a hardware keyboard event on pressing enter or delete. This is bad for many 
     // reasons (there are race conditions with commits) but some applications are 
     // relying on this behavior so we continue to support it for older apps. 
     sendDownUpKeyEvent(KeyEvent.KEYCODE_ENTER); 
    } else { 
     mConnection.commitText(StringUtils.newSingleCodePointString(code), 1); 
    } 
} 

所以, '0' - '9'(和ENTER杰利贝恩之前),一个KeyEvent发送。问题是 - 你的OnKeyListener消耗的KeyEvent:

@Override 
public boolean onKey(View v, int keyCode, KeyEvent event) { 

    if (keyCode == KeyEvent.KEYCODE_DEL 
      && event.getAction() != KeyEvent.ACTION_DOWN) { 
     if (getStrPin() != null) { 
      int length = getStrPin().length(); 
      if (length > 0) { 
       setStrPin(getStrPin() 
         .substring(0, getStrPin().length() - 1)); 
      } 
     } 
    } 

    // Returning `true` at this point means that you have handled whatever was sent 
    return true; 
} 

看来你要处理KeyEvent.KEYCODE_DEL。在这种情况下,您的OnKeyListener应该是这样的:

@Override 
public boolean onKey(View v, int keyCode, KeyEvent event) { 

    if (keyCode == KeyEvent.KEYCODE_DEL 
      && event.getAction() != KeyEvent.ACTION_DOWN) { 
     if (getStrPin() != null) { 
      int length = getStrPin().length(); 
      if (length > 0) { 
       setStrPin(getStrPin() 
         .substring(0, getStrPin().length() - 1)); 

       // Handled 
       return true; 
      } 
     } 
    } 

    // Let everything other that KEYCODE_DEL be handled elsewhere 
    return false; 
} 

我不知道为什么你的代码工作对三星的核心,但是这可能是因为三星对相当多的变化AOSP的。可能是因为他们不会发送KeyEvent0 - 9

另一个问题:您的OnKeyListener只适用于API < 16.对于API> = 16,KEYCODE_DEL不作为KeyEvent发送。看看InputConnectionWrapper(特别是deleteSurroundingText(...))以支持稍后在JellyBean &上的类似功能。

相关问题