Show numeric keyboard with percent symbol

143 Views Asked by At

Is there an idea to show numeric soft keyboard with % symbol programmatically?

For example I need to enter 13% in EditText, so I need numbers and percent symbol and I don't want to show letters in soft keyboard.

The below code shows only numbers and .

editText.setRawInputType(InputType.TYPE_CLASS_NUMBER);

Any help is appreciated

1

There are 1 best solutions below

0
TwiXter On

For a customer i have allowed the '-' char within the layout.xml file (android:digits attribute, see bellow):

        <EditText
        android:id="@+id/searchText"
        android:layout_width="match_parent"
        android:layout_height="50dp"
        android:maxLines="1"
        android:layout_marginStart="8dp"
        android:layout_marginTop="4dp"
        android:layout_marginEnd="8dp"
        android:hint="@string/searchRecord_inputHint"
        android:imeOptions="actionSearch"
        android:inputType="number"
        android:digits="1234567890-"
        android:text="@={viewModel.textToSearch}"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@id/switchSearchBy" />

Then, before searching i replace the '-' char occurences by '%'. Of course, you must inform your users about this logic. Other solution is to build a simple Digits + '%' keyboard with buttons in a DialogFragment or even in your search layout directly.

Update: Integrated numeric keyboard view example

Simple integrated numeric keyboard

keyboard_num.xml

<?xml version="1.0" encoding="utf-8"?>
<layout     xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools">
<data>
    <variable name="myCls" 
type="com.sample.keyboard.KeyboardNumeric"/>
</data>
<merge>
<GridLayout
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:stretchColumns="*"
    android:columnCount="4"
    android:rowCount="4">
    <!--Row1-->
    <Button
        style="@style/KeyboardPluStyle"
        android:id="@+id/button_7"
        android:layout_width="130dp"
        android:layout_height="64dp"
        android:text="7"
        android:layout_row="0"
        android:layout_column="0"
        android:onClick='@{(v)->myCls.onKey("7")}'/>

    <Button
        android:id="@+id/button_8"
        android:layout_width="130dp"
        android:layout_height="64dp"
        android:text="8"
        android:layout_row="0"
        android:layout_column="1"
        android:onClick='@{(v)->myCls.onKey("8")}'/>
    <Button
        style="@style/KeyboardPluStyle"
        android:id="@+id/button_9"
        android:layout_width="130dp"
        android:layout_height="64dp"
        android:text="9"
        android:layout_row="0"
        android:layout_column="2"
        android:onClick='@{(v)->myCls.onKey("9")}'/>

    <Button
        android:id="@+id/button_clr"
        android:layout_width="120dp"
        android:layout_height="64dp"
        android:layout_row="0"
        android:layout_column="3"
        android:foreground="@drawable/ic_clear"
        android:onClick='@{(v)->myCls.onClickClear()}'/>

    <!--Row2-->
    <Button
        android:id="@+id/button_4"
        android:layout_width="130dp"
        android:layout_height="64dp"
        android:layout_row="1"
        android:layout_column="0"
        android:text="4"
        android:onClick='@{(v)->myCls.onKey("4")}'/>

    <Button
        android:id="@+id/button_5"
        android:layout_width="130dp"
        android:layout_height="64dp"
        android:layout_row="1"
        android:layout_column="1"
        android:text="5"
        android:onClick='@{(v)->myCls.onKey("5")}'/>

    <Button
        android:id="@+id/button_6"
        android:layout_width="130dp"
        android:layout_height="64dp"
        android:text="6"
        android:layout_row="1"
        android:layout_column="2"
        android:onClick='@{(v)->myCls.onKey("6")}'/>

    <Button
        android:id="@+id/button_percent"
        android:layout_width="120dp"
        android:layout_height="64dp"
        android:text="%"
        app:autoSizeTextType="uniform"
        app:autoSizeMinTextSize="12sp"
        app:autoSizeMaxTextSize="50sp"
        app:autoSizeStepGranularity="2sp"
        android:textStyle="bold"
        android:visibility="invisible"
        tools:visibility="visible"
        android:layout_row="1"
        android:layout_column="3"
        android:onClick='@{(v)->myCls.onKey("%")}'/>

    <!--Row3-->

    <Button
        style="@style/KeyboardPluStyle"
        android:id="@+id/button_1"
        android:layout_height="64dp"
        android:layout_width="130dp"
        android:text="1"
        android:layout_row="2"
        android:layout_column="0"
        android:onClick='@{(v)->myCls.onKey("1")}' />

    <Button
        style="@style/KeyboardPluStyle"
        android:id="@+id/button_2"
        android:layout_width="130dp"
        android:layout_height="64dp"
        android:text="2"
        android:layout_row="2"
        android:layout_column="1"
        android:onClick='@{(v)->myCls.onKey("2")}'/>

    <Button
        style="@style/KeyboardPluStyle"
        android:id="@+id/button_3"
        android:layout_width="130dp"
        android:layout_height="64dp"
        android:layout_row="2"
        android:layout_column="2"
        android:text="3"
        android:onClick='@{(v)->myCls.onKey("3")}'/>

    <Button
        style="@style/KeyboardPluStyleBlue"
        android:id="@+id/button_enter"
        android:layout_width="120dp"
        android:layout_height="64dp"
        android:layout_rowWeight="2"
        android:layout_row="2"
        android:layout_rowSpan="2"
        android:layout_column="3"
        android:foreground="@drawable/ic_enter"
        android:onClick='@{(v)->myCls.onClickEnter()}' />

    <!-- Row 4-->

    <Button
        style="@style/KeyboardPluStyle"
        android:id="@+id/button_0"
        android:layout_width="0dp"
        android:layout_height="64dp"
        android:text="0"
        android:layout_row="3"
        android:layout_column="0"
        android:layout_columnSpan="2"
        android:layout_columnWeight="1"
        android:onClick='@{(v)->myCls.onKey("0")}'/>

    <Button
        style="@style/KeyboardPluStyleGray"
        android:id="@+id/button_Cancel"
        android:layout_width="130dp"
        android:layout_height="64dp"
        android:text="@string/adlb_dialog_cancel"
        app:autoSizeTextType="uniform"
        app:autoSizeMinTextSize="12sp"
        app:autoSizeMaxTextSize="50sp"
        app:autoSizeStepGranularity="2sp"
        android:layout_row="3"
        android:layout_column="2"
        android:onClick='@{(v)->myCls.onClickCancel()}'/>
</GridLayout>

The KeyboardNumeric class:

package com.sample.keyboard;

import android.content.Context;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.ViewGroup;
import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.ExtractedTextRequest;
import android.view.inputmethod.InputConnection;
import android.widget.LinearLayout;

import com.averydennison.foodxpress.R;
import com.sample.keyboard.databinding.KeyboardQtyBinding;

public class KeyboardNumeric extends LinearLayout {

private KeyboardNumBinding binding;
    // constructors
    public KeyboardNumeric(Context context) {
        this(context, null, 0);
    }

    public KeyboardNumeric(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public KeyboardNumeric(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

@Override
protected void onAttachedToWindow() {
    super.onAttachedToWindow();
    if(isInEditMode())//Uses LayoutInflater if you are in Android studio
        LayoutInflater.from(getContext()).inflate(R.layout.keyboard_num, this, true);
    else
        init(getContext());
}

    // Our communication link to the EditText
    InputConnection inputConnection;

    void init(Context context) {

        binding= KeyboardNumBinding.inflate(LayoutInflater.from(context),(ViewGroup)this,true);
        binding.setMyCls(this);
    }

/**
 * Call this on a key press
 * @param value Key text value as String
 */
public void onKey(String value){
    inputConnection.commitText(value, 1);
}

/**
 * Call this when Enter key is pressed
 */
public void onClickEnter(){
    inputConnection.performEditorAction(EditorInfo.IME_ACTION_DONE);
}

/**
 * Call this when Clear key is pressed
 */
public void onClickClear(){
    CharSequence currentText = inputConnection.getExtractedText(new ExtractedTextRequest(), 0).text;
    CharSequence beforCursorText = inputConnection.getTextBeforeCursor(currentText.length(), 0);
    CharSequence afterCursorText = inputConnection.getTextAfterCursor(currentText.length(), 0);
    inputConnection.deleteSurroundingText(beforCursorText.length(), afterCursorText.length());
}

/**
 * Clall this when Cancel key is pressed
 */
public void onClickCancel(){
    inputConnection.performEditorAction(EditorInfo.IME_ACTION_SEND);
}



    /** The activity (or some parent or controller) must give us
    * a reference to the current EditText's InputConnection
    */
    public void setInputConnection(InputConnection ic) {
        this.inputConnection = ic;
    }
}

EditText that avoids Soft input keyboard to be shown:

package com.sample.views;

import android.content.Context;
import android.util.AttributeSet;
import android.view.ActionMode;
import android.view.Menu;
import android.view.MenuItem;
import android.view.MotionEvent;

public class CustomEditText extends 
androidx.appcompat.widget.AppCompatEditText {
public CustomEditText(Context context) {
    super(context);
}

public CustomEditText(Context context, AttributeSet attrs) {
    super(context, attrs);
}

public CustomEditText(Context context, AttributeSet attrs, int defStyleAttr) {
    super(context, attrs, defStyleAttr);
}

private boolean softInputEnabled=false;

public void setSoftInputAllowed(boolean enabled){
    softInputEnabled=enabled;
}

public boolean getSoftInputAllowed(){
   return softInputEnabled;
}

@Override
protected void onAttachedToWindow() {
    super.onAttachedToWindow();
    preventSofInputShown();
    lockContextMenu();
}

private void lockContextMenu(){
    this.setCustomSelectionActionModeCallback(new ActionMode.Callback() {
        @Override
        public boolean onCreateActionMode(ActionMode mode, Menu menu) {
            //to keep the text selection capability available ( selection cursor)
            return true;
        }

        @Override
        public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
            //to prevent the menu from appearing
            menu.clear();
            return false;
        }

        @Override
        public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
            return false;
        }

        @Override
        public void onDestroyActionMode(ActionMode mode) {

        }
    });
}

@Override
public boolean performClick() {
   /* synchronized (this){
        //Find the currently focused view, so we can grab the correct window token from it.
        View view = getRootView().findFocus();
        //If no view currently has focus, create a new one, just so we can grab a window token from it
        if (view == null)
            view = this;
        else
            this.clearFocus();
        InputMethodManager imm = (InputMethodManager)getContext().getSystemService(INPUT_METHOD_SERVICE);
        imm.hideSoftInputFromWindow(view.getWindowToken(), 0);
    }*/
   if(softInputEnabled)
       return false;
   else
        return true;
}


private void preventSofInputShown(){
    this.setOnTouchListener((v, event) -> {
        switch(event.getAction()){
            case MotionEvent.ACTION_DOWN:
            case MotionEvent.ACTION_UP:
                return performClick();
            default:
                return false;
        }
    });
  }

}

fragment_search.xml using CustomEditText + Keyboard:

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    

    <com.sample.views.CustomEditText
        android:id="@+id/txtQty"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="8dp"
        android:layout_marginTop="16dp"
        android:layout_marginEnd="8dp"
        android:clickable="true"
        android:ems="10"
        android:inputType="number"
        android:longClickable="false"
        android:textSize="40sp"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent" 
        app:layout_constraintTop_toTopOf="parent"/>
    

    <com.sample.KeyboardNumeric
        android:id="@+id/keyboardFull"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout>

Finally, in your SearchFragment code (Attached to fragment_search.xml), just add this: (ie: in onCreate after inflating view)

    // pass the InputConnection from the EditText to the keyboard
    KeyboardNumeric keyboard = view.findViewById(R.id.keyboardFull);
    EditText txtQty=view.findViewById(R.id.txtQty);
    InputConnection ic = txtQty.onCreateInputConnection(new EditorInfo());
    KeyboardQty.setInputConnection(ic);