background

Most financial apps will process the default numeric keypad to implement a custom numeric security keypad. Based on this, this paper imitated the style of wechat numeric keyboard, and realized a set of customized digital security keyboard (support random number distribution).

1. Graphical effect

Ii. Issues to be considered

  1. The implementation of the layout; The demo uses PopupWindow and Tablayout through XML files.
  2. Disallow EditText’s default soft keyboard popup and replace it with a custom numeric keypad and popup effect when switching focus with other EditTexts;
  3. The cursor position needs to be updated when deleting and adding characters.
  4. Implementation of random number distribution;

Three. Implementation code

1.MainActivity call code:

public class MainActivity extends AppCompatActivity { private static final String TAG = "MainActivity"; private EditText numberEt; private KeyboardPopupWindow keyboardPopupWindow; private boolean isUiCreated = false; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); initView(); } private void initView() { numberEt = findViewById(R.id.numberEt); keyboardPopupWindow = new KeyboardPopupWindow(MainActivity.this, getWindow().getDecorView(), numberEt,true); // numberEt.setInputType(InputType.TYPE_NULL); / / this setting will cause the cursor invisible numberEt setOnClickListener (new View. An OnClickListener () {@ Override public void onClick (View v) {if (keyboardPopupWindow ! = null) { keyboardPopupWindow.show(); }}}); numberEt.setOnFocusChangeListener(new View.OnFocusChangeListener() { @Override public void onFocusChange(View v, boolean hasFocus) { if (keyboardPopupWindow ! = null && isUiCreated) {//isUiCreated is important, Unable to add window -- token null is not valid; is your activity running? keyboardPopupWindow.refreshKeyboardOutSideTouchable(! hasFocus); } if (hasFocus) {// Hide system soft keyboard InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE); imm.hideSoftInputFromWindow(numberEt.getWindowToken(), 0); }}}); } @Override public void onWindowFocusChanged(boolean hasFocus) { super.onWindowFocusChanged(hasFocus); isUiCreated = true; } @Override protected void onDestroy() { if (keyboardPopupWindow ! = null) { keyboardPopupWindow.releaseResources(); } super.onDestroy(); }}Copy the code

As you can see, this piece of code implementation is very simple, mainly through KeyboardPopupWindow this custom View to achieve the keyboard pop-up and key click effect. Note that isUiCreated is the flag bit. You need to use methods such as onWindowFocusChanged to determine the status of the customized keyboard after the current page is loaded; otherwise, an error will be reported.

2. Custom numeric keypad code:


public class KeyboardPopupWindow extends PopupWindow {
    private static final String TAG = "KeyboardPopupWindow";
    private Context context;
    private View anchorView;
    private View parentView;
    private EditText editText;
    private boolean isRandomSort = false; Private List<Integer> List = new ArrayList<>(); private int[] commonButtonIds = new int[]{R.id.button00, R.id.button01, R.id.button02, R.id.button03, R.id.button04, R.id.button05, R.id.button06, R.id.button07, R.id.button08, R.id.button09}; /** * @param context * @param anchorView * @param editText * @param isRandomSort If numbers are randomly sorted */ public KeyboardPopupWindow(Context context, View anchorView, EditText editText, boolean isRandomSort) { this.context = context;  this.anchorView = anchorView; this.editText = editText; this.isRandomSort = isRandomSort;if (context == null || anchorView == null) {
            return;
        }
        initConfig();
        initView();
    }


    private void initConfig() {
        setOutsideTouchable(false);
        setFocusable(false);
        setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT)); forbidDefaultSoftKeyboard(); } /** * Disallow the system's default soft keyboard */ private voidforbidDefaultSoftKeyboard() {
        if (editText == null) {
            return;
        }
        if(android. OS. Build. VERSION. SDK_INT > 10) {/ / 4.0 above, using reflection ways of the soft keyboard system at ban pop-up try {Class < EditText > CLS = EditText. Class; MethodsetShowSoftInputOnFocus;
                setShowSoftInputOnFocus = cls.getMethod("setShowSoftInputOnFocus", boolean.class);
                setShowSoftInputOnFocus.setAccessible(true);
                setShowSoftInputOnFocus.invoke(editText, false); } catch (Exception e) { e.printStackTrace(); }} /** * Refresh custom popupWindow whether outside can touch response: If is untouchable, shows that the soft keyboard view * * @ param isTouchable * / public void refreshKeyboardOutSideTouchable (Boolean isTouchable) {setOutsideTouchable(isTouchable);
        if(! isTouchable) { show(); }else {
            dismiss();
        }
    }

    private void initView() {
        parentView = LayoutInflater.from(context).inflate(R.layout.keyboadview, null);
        initKeyboardView(parentView);
        setWidth(ViewGroup.LayoutParams.MATCH_PARENT);
        setHeight(ViewGroup.LayoutParams.WRAP_CONTENT);
        setContentView(parentView);
    }

    private void initKeyboardView(View view) {
        LinearLayout dropdownLl = view.findViewById(R.id.dropdownLl);
        dropdownLl.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { dismiss(); }}); // set the number key to click listenerfor (int i = 0; i < commonButtonIds.length; i++) {
            final Button button = view.findViewById(commonButtonIds[i]);
            button.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    int curSelection = editText.getSelectionStart();
                    int length = editText.getText().toString().length();
                    if (curSelection < length) {
                        String content = editText.getText().toString();
                        editText.setText(content.substring(0, curSelection) + button.getText() + content.subSequence(curSelection, length));
                        editText.setSelection(curSelection + 1);
                    } else{ editText.setText(editText.getText().toString() + button.getText()); editText.setSelection(editText.getText().toString().length()); }}}); } //② Set clickListener view.findViewById(R.i.buttondot).setonClickListener (new View).OnClickListener() {
            @Override
            public void onClick(View v) {
                int curSelection = editText.getSelectionStart();
                int length = editText.getText().toString().length();
                if (curSelection < length) {
                    String content = editText.getText().toString();
                    editText.setText(content.substring(0, curSelection) + "." + content.subSequence(curSelection, length));
                    editText.setSelection(curSelection + 1);
                } else {
                    editText.setText(editText.getText().toString() + "."); editText.setSelection(editText.getText().toString().length()); }}}); FindViewById (R.i.buttonCross). SetOnClickListener (new View).OnClickListener() {
            @Override
            public void onClick(View v) {
                int length = editText.getText().toString().length();
                int curSelection = editText.getSelectionStart();
                if(length > 0 && curSelection > 0 && curSelection <= length) { String content = editText.getText().toString(); editText.setText(content.substring(0, curSelection - 1) + content.subSequence(curSelection, length)); editText.setSelection(curSelection - 1); }}}); } public voidshow() {
        if(! isShowing() && anchorView ! = null) {doRandomSortOp(); this.showAtLocation(anchorView, Gravity.BOTTOM, 0, 0); }} /** * random distribution of numbers */ private voiddoRandomSortOp() {
        if (parentView == null) {
            return;
        }
        if(! isRandomSort) {for (int i = 0; i < commonButtonIds.length; i++) {
                final Button button = parentView.findViewById(commonButtonIds[i]);
                button.setText(""+ i); }}else {
            list.clear();
            Random ran = new Random();
            while (list.size() < commonButtonIds.length) {
                int n = ran.nextInt(commonButtonIds.length);
                if(! list.contains(n)) list.add(n); }for (int i = 0; i < commonButtonIds.length; i++) {
                final Button button = parentView.findViewById(commonButtonIds[i]);
                button.setText("" + list.get(i));
            }
        }
    }

    public void releaseResources() {
        this.dismiss();
        context = null;
        anchorView = null;
        if(list ! = null) { list.clear(); list = null; }}}Copy the code

The code implementation logic is relatively simple:

  1. By setting the popupWindow contentView, popup position, touch parameters outside the boundary, etc., to achieve the general style effect;
  2. Set the click event for each button in the contentView and handle the passed EditText values and focus changes;
  3. Set the random flag bit for the random distribution of numeric keyboard values;
  4. ForbidDefaultSoftKeyboard process: ban EditText default pop-up soft keyboard. Other methods of concentration that have been tried so far have a major drawback, since the EditText focus is still visible, so reflection is used to achieve this.

4. Summary

Of course, in addition to the above way, you can also use the system KeyboardView and Keyboard to achieve the corresponding effect. In the process of imitation writing, it will be found that the realization of this effect will involve some experiential details, and wechat is to do this, so it will be very convenient to use. Some of the details can be more difficult to achieve than the general effect, but sometimes it happens that these easily overlooked details are the difference. GitHub source code: click here >>