有一个需求是这样的,页面上有一个输入框,供用户输入手机号码,如果通讯录里面存在这个号码,会自动把名字追加到号码后面。这个需求变态的地方在于,假如用一个EditText+TextView,那么不好控制二者之间的距离,就算是做了各种适配,但是用户可以设置系统的字体,仍然显示很难看!没办法,之好在一个EditText里面来做,让号码是可编辑的,名字是自动追加上的。
MainActivity.java:
public class MainActivity extends Activity { private EditText edittext; private Button button; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); final View rootView = this.findViewById(R.id.rootview); edittext = (EditText) this.findViewById(R.id.edittext1); //限定只能输入数字 edittext.setInputType(EditorInfo.TYPE_CLASS_NUMBER); //可以获取焦点 button = (Button)this.findViewById(R.id.button1); button.setFocusable(true); button.setFocusableInTouchMode(true); // 空白处点击,隐藏软键盘 rootView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { hideSoftInput(); } }); // 一旦获取焦点,设置光标位置 edittext.setOnFocusChangeListener(new OnFocusChangeListener() { @Override public void onFocusChange(View v, boolean hasFocus) { if (hasFocus) { String mobile = getMobile(edittext.getText().toString()); setCursorPosition(mobile.length()); } } }); // 返回true,手动处理touch事件,即使edittext获取了焦点,也不会自动弹出软键盘,要手动弹出 // http://*.com/questions/10263384/android-how-to-get-text-position-from-touch-event edittext.setOnTouchListener(new View.OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { if (event.getAction() == MotionEvent.ACTION_DOWN) { Layout layout = ((EditText) v).getLayout(); float x = event.getX() + edittext.getScrollX(); int offset = layout.getOffsetForHorizontal(0, x); if(offset >= 0 && offset < 11){ edittext.setSelection(offset); }else if(offset >= 11){ edittext.setSelection(11); } showSoftInput(); } return true; } }); edittext.addTextChangedListener(new TextWatcher() { private String preText; @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 mobile = getMobile(s.toString()); String nowtext = buildEditTextContent(mobile); if (nowtext.equals(preText)) { return; } // 计算当前的光标位置 int offset = calCursorOffset(preText, nowtext); // 一定要在setTest之前设置preText,否则会* preText = nowtext; edittext.setText(nowtext); // 文字发生变化,重新设置光标,否则会跑到最前面 setCursorPosition(offset); if (mobile.length() == 11) { hideSoftInput(); } } }); edittext.setText("15012341234"); } private void hideSoftInput(){ edittext.requestFocus(); hideKeyboard(); button.requestFocus(); } private void showSoftInput(){ edittext.requestFocus(); showKeyboard(edittext); } private void setCursorPosition(int offset){ edittext.setSelection(offset); } private String getMobile(String text){ if(text == null || text.length() <= 0){ return ""; } String arr[] = text.split("\\s"); String mobile = arr[0]; return mobile; } private String buildEditTextContent(String mobile){ String name = getName(mobile); String text = mobile + (name == null ? "" : " " + name); return text; } private int calCursorOffset(String pre, String now){ if(isBlank(pre) && isBlank(now)){ return 0; }else if(!isBlank(pre) && !isBlank(now)){ for(int i=0; i<pre.length() && i<now.length(); i++){ int prechar = pre.charAt(i); int nowchar = now.charAt(i); if(prechar != nowchar){ return i; } } } return now.length() > 11 ? 11 : now.length(); } // 业务方法,联系人数据 private Map<String, String> data; private String getName(String mobile) { if (data == null) { data = contactData(); } return data.get(mobile); } private Map<String, String> contactData() { Map<String, String> data = new HashMap<String, String>(); data.put("15012341234", "张三"); data.put("15112341234", "李四"); data.put("15212341234", "王五"); return data; } // util方法 public void showKeyboard(View focusView) { Object showing = focusView.getTag(); if (showing != null) { return; } try { InputMethodManager imm = (InputMethodManager) this .getSystemService(Context.INPUT_METHOD_SERVICE); imm.showSoftInput(focusView, 0); focusView.setTag(new Object()); } catch (Exception e) { Log.e("SoftInput:Showing had a wrong.", e.toString()); } } public void hideKeyboard() { View focusView = this.getCurrentFocus(); if (focusView == null || focusView.getTag() == null) { return; } try { InputMethodManager imm = ((InputMethodManager) this .getSystemService(Activity.INPUT_METHOD_SERVICE)); imm.hideSoftInputFromWindow(focusView.getWindowToken(), InputMethodManager.HIDE_NOT_ALWAYS); focusView.setTag(null); } catch (Exception e) { Log.e("SoftInput:Hiding had a wrong.", e.toString()); } } public boolean isBlank(String str){ if(str == null || str.length() <= 0){ return true; } return false; } }activity_main.xml:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" android:id="@+id/rootview"> <EditText android:id="@+id/edittext1" android:layout_width="300dp" android:layout_height="wrap_content"/> <Button android:id="@+id/button1" android:layout_width="0dp" android:layout_height="0dp"/> </LinearLayout>
此外,为了防止在进入页面的时候自动弹出软键盘,可以在manifest的activity元素添加<activity android:windowSoftInputMode="stateAlwaysHidden|adjustPan">