0

我正在开发一个使用键盘进行输入的游戏,但是当用户触摸输入字段时,我只想显示字母字符,没有数字或特殊符号。现在,当键盘打开时,应用程序如下所示:

在此处输入图像描述

当“键入一些字母”EditText 具有焦点时,如何用自定义键盘替换软键盘?

4

2 回答 2

0

I ended up creating a layout of the keyboard I wanted and then I disabled the focus for the EditText:

<EditText
    android:id="@+id/typed_word"
    android:focusable="false"
    android:maxLength="10"
    android:inputType="text"
    android:textCursorDrawable="@drawable/custom_cursor"
    android:enabled="false"
    android:layout_below="@+id/word_list"
    android:digits="abcdefghijklmnopqrstuvwxyz"
    android:textSize="25sp"
    android:textColor="@color/colorPrimaryDark"
    android:layout_margin="10dp"
    android:hint="@string/type_hint"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"/>

By disabling the focus, I was able to prevent the standard keyboard from being displayed.

于 2020-07-21T12:23:19.603 回答
0

在你的xml中使用android:inputType和。android:digitsEditText

<EditText
 android:id="@+id/plain_text_input"
 android:layout_height="wrap_content"
 android:layout_width="wrap_content"
 android:inputType="text"
 android:digits="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ "/>

这将只允许插入字母字符和空格

您还可以检查用户是否尝试输入数字或其他非字母字符,然后向他显示警告。然后,你用任何东西替换它regex [^\p{L}\p{Nd}]+- 这匹配所有既不是字母也不是数字的字符。

EditText text = (EditText) findViewById(R.id.plain_text_input);
text.addTextChangedListener(new TextWatcher() {

public void afterTextChanged(Editable s) {
  if(s.matches(".*\\d.*")){ // contains a number
    text.setError("Sorry, numbers are not allowed");
    text.replaceAll("[^\\p{L}\\p{Nd}]+", "");
   } 
}

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

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

});

或者,您可以创建自己的 InputFilter 来过滤掉任何非字母字符。

InputFilter input = new InputFilter() {
    
    public CharSequence filter
        (CharSequence source, int start, int end, Spanned dest, int dstart, int dend) {
        
        String filtered = "";
        for (int i = start; i < end; i++) {
            char character = source.charAt(i);
            if (!Character.isWhitespace(character) && Character.isLetter(character)) {
                filtered += character;
            }
        }

        return filtered;
    }
};

text.setFilters(new InputFilter[]{input}); 

我希望这对您有所帮助。^ - ^


改变


由于他们弃用KeyboardView了 api 29 中的其他相关类,因此请忽略我对该类的最后评论,因为他们将来会删除它。

创建自定义键盘的最佳方法是使用InputMethodService该类,创建您自己的自定义xml布局。

但是,当您正在开发使用更简单输入法的游戏时,这对游戏之外的任何地方的用户都没有用(例如消息应用程序),请考虑这一点。

请记住,此解决方案不会重现用户通常使用键盘执行的所有操作。您可以轻松修改它以满足您的需求。

1、创建keyboard.xml布局。如果需要,您可以修改此示例。

        <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout 
        xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        android:id="@+id/keyboard_parent"
        android:orientation="vertical" android:layout_width="match_parent" android:layout_height="wrap_content"
        android:focusable="true" android:clickable="true"
        android:background="@android:color/white"
        android:visibility="gone">
    
        <LinearLayout android:orientation="horizontal" android:layout_width="match_parent" android:layout_height="50dp">
            <TextView style="@style/alpha" android:id="@+id/keyboard_abc_q"/>
            <TextView style="@style/alpha" android:id="@+id/keyboard_abc_w"/>
            <TextView style="@style/alpha" android:id="@+id/keyboard_abc_e"/>
            <TextView style="@style/alpha" android:id="@+id/keyboard_abc_r"/>
            <TextView style="@style/alpha" android:id="@+id/keyboard_abc_t"/>
            <TextView style="@style/alpha" android:id="@+id/keyboard_abc_y"/>
            <TextView style="@style/alpha" android:id="@+id/keyboard_abc_u"/>
            <TextView style="@style/alpha" android:id="@+id/keyboard_abc_i"/>
            <TextView style="@style/alpha" android:id="@+id/keyboard_abc_o"/>
            <TextView style="@style/alpha" android:id="@+id/keyboard_abc_p"/>
        </LinearLayout>
    
        <LinearLayout android:orientation="horizontal" android:layout_width="match_parent" android:layout_height="50dp"
            android:paddingStart="8dp" android:paddingEnd="8dp">
            <TextView style="@style/alpha" android:id="@+id/keyboard_abc_a"/>
            <TextView style="@style/alpha" android:id="@+id/keyboard_abc_s"/>
            <TextView style="@style/alpha" android:id="@+id/keyboard_abc_d"/>
            <TextView style="@style/alpha" android:id="@+id/keyboard_abc_f"/>
            <TextView style="@style/alpha" android:id="@+id/keyboard_abc_g"/>
            <TextView style="@style/alpha" android:id="@+id/keyboard_abc_h"/>
            <TextView style="@style/alpha" android:id="@+id/keyboard_abc_j"/>
            <TextView style="@style/alpha" android:id="@+id/keyboard_abc_k"/>
            <TextView style="@style/alpha" android:id="@+id/keyboard_abc_l"/>
            <TextView style="@style/alpha" android:id="@+id/keyboard_abc_ç"/>
        </LinearLayout>
    
        <LinearLayout android:orientation="horizontal" android:layout_width="match_parent" android:layout_height="50dp">
    
            <ImageView
                style="@style/action"
                android:layout_weight="1"
                android:id="@+id/keyboard_action_all_caps"
                android:tint="@android:color/darker_gray"
                app:srcCompat="@android:drawable/ic_menu_upload"/>
    
            <TextView style="@style/alpha" android:id="@+id/keyboard_abc_z"/>
            <TextView style="@style/alpha" android:id="@+id/keyboard_abc_x"/>
            <TextView style="@style/alpha" android:id="@+id/keyboard_abc_c"/>
            <TextView style="@style/alpha" android:id="@+id/keyboard_abc_v"/>
            <TextView style="@style/alpha" android:id="@+id/keyboard_abc_b"/>
            <TextView style="@style/alpha" android:id="@+id/keyboard_abc_n"/>
            <TextView style="@style/alpha" android:id="@+id/keyboard_abc_m"/>
    
            <ImageView
                style="@style/action"
                android:layout_weight="1"
                android:id="@+id/keyboard_action_delete"
                android:tint="@android:color/darker_gray"
                app:srcCompat="@android:drawable/ic_input_delete"/>
        </LinearLayout>
    
        <LinearLayout
            android:orientation="horizontal"
            android:layout_width="match_parent"
            android:layout_height="60dp">
            <ImageView
                style="@style/action"
                android:id="@+id/keyboard_action_something"
                android:layout_width="56dp"
                android:layout_height="match_parent"
                app:srcCompat="@android:drawable/ic_menu_sort_alphabetically"/>
            <Button
                android:id="@+id/keyboard_action_space"
                android:layout_weight="1"
                android:layout_width="0dp"
                android:layout_height="40dp"
                android:layout_gravity="center_vertical"
                app:backgroundTint="@android:color/black"/>
            <ImageView
                style="@style/action"
                android:layout_width="56dp"
                android:layout_height="match_parent"
                android:id="@+id/keyboard_action_send"
                app:srcCompat="@android:drawable/ic_menu_send"/>
        </LinearLayout>
    </LinearLayout>

地点@style/alpha和地点@style/action

<style name="alpha">
    <item name="android:layout_weight">1</item>
    <item name="android:layout_width">wrap_content</item>
    <item name="android:layout_height">match_parent</item>
    <item name="android:text">"A"</item>
    <item name="android:textSize">8pt</item>
    <item name="android:textColor">@android:color/black</item>
    <item name="android:gravity">center</item>
    <item name="android:layout_gravity">center_vertical</item>
</style>

<style name="action">
    <item name="android:layout_width">wrap_content</item>
    <item name="android:layout_height">wrap_content</item>
    <item name="android:layout_gravity">center_vertical</item>
    <item name="android:scaleType">center</item>
    <item name="android:padding">4dp</item>
    <item name="android:tint">@android:color/black</item>
</style>

第二为您的键盘创建一个构造函数。

public class MyKeyboard {

  private Context context;
  private boolean is_all_caps_single = false;
  private boolean is_all_caps_double = false;
  
  public MyKeyboard(Context c, View container, boolean is_reference) {
    this.context = c;
    if (is_reference) {
        keyboard = container.findViewById(R.id.keyboard_parent);
        initializeComponents();
    } else {
        keyboard = View.inflate(context, R.layout.keyboard, null);
        initializeComponents();
        ((ViewGroup) container).removeAllViews();
        ((ViewGroup) container).addView(keyboard);
    }
  }
  
  private View keyboard;
  private TextView[] characters;
  private ImageView all_caps;
  
  @SuppressLint("ClickableViewAccessibility")
  private void initializeComponents() {
    int[] ids = {
        R.id.keyboard_abc_q, R.id.keyboard_abc_w, R.id.keyboard_abc_e, R.id.keyboard_abc_r, R.id.keyboard_abc_t, R.id.keyboard_abc_y, R.id.keyboard_abc_u, R.id.keyboard_abc_i, R.id.keyboard_abc_o, R.id.keyboard_abc_p,
        R.id.keyboard_abc_a, R.id.keyboard_abc_s, R.id.keyboard_abc_d, R.id.keyboard_abc_f, R.id.keyboard_abc_g, R.id.keyboard_abc_h, R.id.keyboard_abc_j, R.id.keyboard_abc_k, R.id.keyboard_abc_l, R.id.keyboard_abc_ç,
        R.id.keyboard_abc_z, R.id.keyboard_abc_x, R.id.keyboard_abc_c, R.id.keyboard_abc_v, R.id.keyboard_abc_b, R.id.keyboard_abc_n, R.id.keyboard_abc_m
    };
    
    String[] chrs =
            {
                    "q", "w", "e", "r", "t", "y", "u", "i", "o", "p",
                    "a", "s", "d", "f", "g", "h", "j", "k", "l", "ç",
                    "z", "x", "c", "v", "b", "n", "m"
            };
    
    characters = new TextView[ids.length];
    for (int i = 0; i < ids.length; i++) {
        characters[i] = keyboard.findViewById(ids[i]);
        characters[i].setText(chrs[i]);
    }

    all_caps = keyboard.findViewById(R.id.keyboard_action_all_caps);
    final GestureDetector all_caps_gesture = new GestureDetector(context, new GestureDetector.SimpleOnGestureListener() {

        @Override
        public boolean onSingleTapConfirmed(MotionEvent e) {
            is_all_caps_double = false;
            is_all_caps_single = !is_all_caps_single;

            for (TextView tw: characters) {
                tw.setAllCaps(is_all_caps_single);
            }
            setForegroundColor(all_caps, is_all_caps_single ? Color.BLACK : Color.GRAY);

            return super.onSingleTapConfirmed(e);
        }

        @Override
        public boolean onDoubleTap(MotionEvent e) {
            is_all_caps_single = true;
            is_all_caps_double = !is_all_caps_double;

            for (TextView tw: characters) {
                tw.setAllCaps(is_all_caps_double);
            }
            setForegroundColor(all_caps, Color.BLUE);

            return super.onDoubleTap(e);
        }
    });

    all_caps.setOnTouchListener(new View.OnTouchListener() {
        @Override
        public boolean onTouch(View v, MotionEvent event) {
            all_caps_gesture.onTouchEvent(event);
            return true;
        }
    });

    for (int i = 0; i < ids.length; i++) {
        final int finalI = i;
        characters[i].setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                String ss = characters[finalI].getText().toString();

                if (is_all_caps_double) {
                    ss = ss.toUpperCase();
                } else if (is_all_caps_single) {
                    is_all_caps_single = false;
                    ss = ss.toUpperCase();

                    for (TextView tw: characters) {
                        tw.setAllCaps(false);
                    }
                    setForegroundColor(all_caps, Color.BLACK);
                } else {
                    ss = ss.toLowerCase();
                }

                popup(characters[finalI], ss);
                edittext.getText().insert(edittext.getSelectionStart(), ss);
            }
        });
    }
    keyboard.findViewById(R.id.keyboard_action_space).setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            edittext.dispatchKeyEvent(new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_SPACE));
        }
    });

    final GestureDetector del_gesture = new GestureDetector(context, new GestureDetector.SimpleOnGestureListener() {
        @Override
        public void onLongPress(MotionEvent e) {
            is_fast_delete = true;
            fastDelete(edittext);
            super.onLongPress(e);
        }
    });

    keyboard.findViewById(R.id.keyboard_action_delete).setOnTouchListener(new View.OnTouchListener() {
        @Override
        public boolean onTouch(View v, MotionEvent event) {
            if (event.getAction() == MotionEvent.ACTION_UP) {
                is_fast_delete = false;
                delete();
            }
            del_gesture.onTouchEvent(event);
            return true;
        }
    });

    keyboard.findViewById(R.id.keyboard_action_send).setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            edittext.getText().insert(edittext.getSelectionStart(), "\n");
        }
    });
    keyboard.findViewById(R.id.keyboard_action_something).setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            Log.e("log", "Make something here");
        }
    });
  }
  
  private EditText edittext;
  public void show(EditText focus) {
    this.edittext = focus;
    keyboard.animate().y(0).setListener(new AnimatorListenerAdapter() {
        @Override
        public void onAnimationStart(Animator animation) {
            super.onAnimationStart(animation);
            keyboard.setVisibility(View.VISIBLE);
        }
    });
  }
  public void hide() {
    if (isVisible()) {
        edittext.clearFocus();
        keyboard.animate().y(keyboard.getHeight()).setListener(new AnimatorListenerAdapter() {
            @Override
            public void onAnimationEnd(Animator animation) {
                super.onAnimationEnd(animation);
                keyboard.setVisibility(View.GONE);
            }
        });
    }
  }

  public boolean isVisible() {
    return keyboard.getVisibility() == View.VISIBLE;
  }

  // show popup when typing
  private void popup(View vw, String s) {
    final PopupWindow popup = new PopupWindow(context);

    RelativeLayout layout = new RelativeLayout(context);
    layout.setBackgroundColor(Color.BLACK);

    TextView tw = new TextView(context);
    tw.setLayoutParams(new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT, RelativeLayout.LayoutParams.MATCH_PARENT));
    tw.setGravity(Gravity.TOP | Gravity.CENTER_HORIZONTAL);
    tw.setTextSize(24);
    tw.setTextColor(Color.WHITE);
    tw.setText(s);

    layout.removeAllViews();
    layout.addView(tw);

    popup.setContentView(layout);

    popup.setHeight(120);
    popup.setWidth(72);

    popup.setOutsideTouchable(false);
    popup.setFocusable(false);

    layout.animate().alpha(1 f).setDuration(0).setStartDelay(100).setListener(new AnimatorListenerAdapter() {
        @Override
        public void onAnimationStart(Animator animation) {
            super.onAnimationStart(animation);
            popup.dismiss();
        }
    });

    popup.showAsDropDown(vw, 0, -180);
  }
  
  // change color of an icon
  private void setForegroundColor(ImageView v, int color) {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
        v.getDrawable().setColorFilter(new BlendModeColorFilter(color, BlendMode.SRC_ATOP));
    } else {
        v.getDrawable().setColorFilter(color, PorterDuff.Mode.SRC_ATOP);
    }
  }
  
  private void delete() {
    edittext.dispatchKeyEvent(new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DEL));
  }
  private void fastDelete(final View vw) {
    final AlphaAnimation n = new AlphaAnimation(1 f, 1 f);
    n.setRepeatCount(1000);
    n.setDuration(200);
    n.setAnimationListener(new Animation.AnimationListener() {
        @Override
        public void onAnimationStart(Animation animation) {

        }

        @Override
        public void onAnimationEnd(Animation animation) {

        }

        @Override
        public void onAnimationRepeat(Animation animation) {
            repeat_count = repeat_count + 1;
            if (is_fast_delete) {
                if (repeat_count == 5) {
                    n.setDuration(100);
                } else if (repeat_count >= 10) {
                    n.setDuration(5);
                }
                delete();
            } else {
                n.cancel();
                vw.getAnimation().cancel();
                vw.clearAnimation();
                n.setAnimationListener(null);
                repeat_count = 0;
            }
        }
    });
    vw.startAnimation(n);
  }
  private boolean is_fast_delete = false;
  private int repeat_count = 0;
}

3rd初始化您的键盘并手动处理您的活动的生命周期。

public class YourActivity extends AppCompatActivity {

    private MyKeyboard keyboard;
    private EditText edittext;
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.one);

        keyboard = new MyKeyboard(this, findViewById(R.id.keyboard_container), true); 
        //if true, the layout must include the keyboard.xml manually
        //else, the constructor will include keyboard.xml programatically

        edittext = findViewById(R.id.edittext);
        edittext.setShowSoftInputOnFocus(false); // not show system keyboard

        edittext.setOnFocusChangeListener(new View.OnFocusChangeListener() {
            @Override
            public void onFocusChange(View v, boolean hasFocus) {
                if (hasFocus) { keyboard.show(edittext); }
                else { keyboard.hide(); }
            }
        });
    }
    
    @Override
    public void onBackPressed() {
        if (keyboard.isVisible()) {
            keyboard.hide();
        } else {
            super.onBackPressed();
        }
    }
}

最后,您的主要活动布局应如下所示

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:animateLayoutChanges="true"
    android:focusableInTouchMode="true"
    android:focusable="true"
    android:clickable="true">

    <EditText
        android:id="@+id/edittext"
        android:padding="16dp"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginBottom="2dp"
        android:layout_above="@+id/keyboard_container"
        android:inputType="text|textNoSuggestions"
        android:background="@android:color/white"
        android:hint="@string/app_name"/>
    
    <RelativeLayout
        android:id="@+id/keyboard_container"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:background="@android:color/white">
        <include
            layout="@layout/keyboard"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"/>
    </RelativeLayout>

</RelativeLayout>

每当您希望关闭键盘时,添加focusableInTouchMode="true" focusable="true"和到用户交互的所有视图。clickable="true"每当 Edittext 失去焦点时就会发生这种情况

最终结果是没有数字和特殊字符的键盘。

我使用标准的 android 图标作为示例,您可以将它们替换为其他图标。

在此处输入图像描述

正如我在本版开头所说,此解决方案不会重现用户通常使用键盘执行的所有操作,您可以以最佳方式对其进行改进。

我希望这对您有所帮助。^-^

于 2020-07-16T22:05:32.997 回答