java - 即使 EditText 不可编辑,EditText 光标也可见

标签 java android android-edittext focus

我需要在 EditText 中引入数据,但我想使用虚拟键盘,而不是 android 键盘。如果我使用 setKeyListener(null),即使在使用 setCursorVisible(true) 之后,光标也是不可见的。

是否可以制作一个 EditText,即使它不可编辑,光标也是可见的?

编辑 2: 我找到了一个部分方法来做到这一点,但是当我双击 EditText 时它不起作用。

我为 EditText 创建了一个 setOnClickListner() 和一个 setOnLongClickListner() 方法。在这种方法中,我从窗口中隐藏了软输入,我还使用了 setTextIsSelectable(false)。我唯一的问题是,当我双击 EditText 软输入键盘时,我不知道如何隐藏它,我尝试使用 android:windowSoftInputMode="stateAlwaysHidden"在 list 中,但它也不起作用。

编辑:

这是我目前为基本转换器计算器使用的代码。

public class MainActivity extends AppCompatActivity {

EditText number;
EditText base;
boolean baseB = false;
String numberS = "0";
String baseS = "10";

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(activity_main);


    //make the EditText for number and base not editable
    number = (EditText) findViewById(R.id.number);
    number.setKeyListener(null);
    base = (EditText) findViewById(R.id.base);
    base.setKeyListener(null);

    //... more code here (changing fonts for each EditText and changing status bar color

}

// I have a function for each button all are the same

public void onClickBaseChange(View v) {
    if (baseB) {
        baseB = false;
        // i use toasts at this moment to know when i'm on number or base field
        Toast.makeText(this, "Number", Toast.LENGTH_SHORT).show();
    } else {
        baseB = true;
        Toast.makeText(this, "Base", Toast.LENGTH_SHORT).show();
    }
}

public void onClickB0(View v) {
    if (numberS.length() > 0 && !numberS.equals("0") && !baseB) {
        numberS += "0";
        number = (EditText) findViewById(R.id.number);
        number.setText(numberS, TextView.BufferType.EDITABLE);
        number.setSelection(numberS.length());
    } else {
        if (Integer.valueOf(baseS) >= 1) {
            baseS += "0";
            base = (EditText) findViewById(R.id.base);
            base.setText(baseS, TextView.BufferType.EDITABLE);
        }
    }
}

public void onClickB1(View v) {
    if (numberS.equals("0")) {
        numberS = "1";
    } else {
        numberS += "1";
    }
    number = (EditText) findViewById(R.id.number);
    number.setText(numberS, TextView.BufferType.EDITABLE);
    number.requestFocus();
    number.setSelection(numberS.length());
}

xml 看起来像这样:

<android.widget.RelativeLayout 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="fill_parent"
android:layout_height="fill_parent"
android:background="@color/colorBackground"

tools:context="manastur.calculator.MainActivity">


<EditText
    android:id="@+id/base"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_alignParentRight="true"
    android:layout_marginRight="20dp"
    android:layout_marginTop="120dp"
    android:background="@android:color/transparent"
    android:cursorVisible="true"
    android:text=""
    android:textColor="@color/text"
    android:textSize="30dp" />

<EditText
    android:id="@+id/number"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_alignParentTop="true"
    android:layout_marginLeft="30dp"
    android:layout_marginTop="50dp"
    android:background="@android:color/transparent"
    android:cursorVisible="true"
    android:text=""
    android:textColor="@color/text"
    android:textSize="50dp" />


<LinearLayout
    android:id="@+id/secondRow"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_above="@+id/firstRow"
    android:layout_centerHorizontal="true">

    <Button
        android:id="@+id/b1"
        android:layout_width="85dp"
        android:layout_height="85dp"
        android:background="@drawable/b1"
        android:onClick="onClickB1" />

    <Button
        android:id="@+id/b2"
        android:layout_width="85dp"
        android:layout_height="85dp"
        android:background="@drawable/b2"
        android:onClick="onClickB2" />

   <!-- from this point on is the same, there are 5 LinearLayouts which
   represents the 5 rows of button of the num pad -->       

最佳答案

使用这段代码来实现,

在开发过程中,我引用了原生 Dialpad代码

KeypadlessKeypad.java

import android.content.Context;
import android.graphics.Rect;
import android.support.v4.view.MotionEventCompat;
import android.text.InputType;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.view.accessibility.AccessibilityEvent;
import android.view.inputmethod.InputMethodManager;
import android.widget.EditText;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class KeypadlessKeypad extends EditText {

    private static final Method mShowSoftInputOnFocus = getSetShowSoftInputOnFocusMethod(
            EditText.class, "setShowSoftInputOnFocus", boolean.class);

    public static Method getSetShowSoftInputOnFocusMethod(Class<?> cls, String methodName, Class<?>... parametersType) {
        Class<?> sCls = cls.getSuperclass();
        while (sCls != Object.class) {
            try {
                return sCls.getDeclaredMethod(methodName, parametersType);
            } catch (NoSuchMethodException e) {
                // Just super it again
            }
            sCls = sCls.getSuperclass();
        }
        return null;
    }

    private Context mContext;


    /**
     * Listener for Copy, Cut and Paste event
     * Currently callback only for Paste event is implemented
     */
    private OnEditTextActionListener mOnEditTextActionListener;

    public KeypadlessKeypad(Context context) {
        super(context);
        mContext = context;
        init();
    }

    public KeypadlessKeypad(Context context, AttributeSet attrs) {
        super(context, attrs);
        mContext = context;
        init();
    }

    public KeypadlessKeypad(Context context, AttributeSet attrs,
                            int defStyle) {
        super(context, attrs, defStyle);
        mContext = context;

        init();
    }

    @Override
    protected void onSelectionChanged(int selStart, int selEnd) {
        super.onSelectionChanged(selStart, selEnd);
    }


    public final void appendText(CharSequence text) {
        append(text, 0, text.length());
    }

    /***
     * Initialize all the necessary components of TextView.
     */
    private void init() {

        setSingleLine(true);

        synchronized (this) {
            setInputType(getInputType() | InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS);
            setFocusableInTouchMode(true);
        }

        reflexSetShowSoftInputOnFocus(false); // Workaround.

        // Ensure that cursor is at the end of the input box when initialized. Without this, the
        // cursor may be at index 0 when there is text added via layout XML.
        setSelection(getText().length());
    }

    @Override
    protected void onFocusChanged(boolean focused, int direction, Rect previouslyFocusedRect) {
        super.onFocusChanged(focused, direction, previouslyFocusedRect);
        hideKeyboard();
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        final boolean ret = super.onTouchEvent(event);
        // Must be done after super.onTouchEvent()
        hideKeyboard();
        return ret;
    }

    private void hideKeyboard() {
        final InputMethodManager imm = ((InputMethodManager) getContext()
                .getSystemService(Context.INPUT_METHOD_SERVICE));
        if (imm != null && imm.isActive(this)) {
            imm.hideSoftInputFromWindow(getApplicationWindowToken(), 0);
        }
    }

    private void reflexSetShowSoftInputOnFocus(boolean show) {
        if (mShowSoftInputOnFocus != null) {
            invokeMethod(mShowSoftInputOnFocus, this, show);
        } else {
            // Use fallback method. Not tested.
            hideKeyboard();
        }
    }

    public static Object invokeMethod(Method method, Object receiver, Object... args) {
        try {
            return method.invoke(receiver, args);
        } catch (IllegalArgumentException e) {
        } catch (IllegalAccessException e) {
        } catch (InvocationTargetException e) {
        }

        return null;
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);

        int textViewWidth = View.MeasureSpec.getSize(widthMeasureSpec);
        int height = getMeasuredHeight();

        this.setMeasuredDimension(textViewWidth, height);
    }

    @Override
    protected void onTextChanged(CharSequence text, int start, int before,
                                 int after) {
        super.onTextChanged(text, start, before, after);
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
    }

    @Override
    public boolean onTextContextMenuItem(int id) {
        boolean consumed = super.onTextContextMenuItem(id);

        switch (id) {
            case android.R.id.paste:
                if (mOnEditTextActionListener != null) {
                    mOnEditTextActionListener.onPaste();
                }
                break;
        }

        return consumed;
    }


    /**
     * Setter method for {@link #mOnEditTextActionListener}
     *
     * @param onEditTextActionListener
     *         Instance of the {@link OnEditTextActionListener}
     */
    public void setOnEditTextActionListener(OnEditTextActionListener onEditTextActionListener) {
        this.mOnEditTextActionListener = onEditTextActionListener;
    }


    private Rect mRect = new Rect();

    @Override
    public boolean dispatchTouchEvent(MotionEvent event) {
        final int action = MotionEventCompat.getActionMasked(event);

        int[] location = new int[2];
        getLocationOnScreen(location);
        mRect.left = location[0];
        mRect.top = location[1];
        mRect.right = location[0] + getWidth();
        mRect.bottom = location[1] + getHeight();

        int x = (int) event.getX();
        int y = (int) event.getY();

        if (action == MotionEvent.ACTION_DOWN && !mRect.contains(x, y)) {
            InputMethodManager input = (InputMethodManager) mContext.getSystemService(Context.INPUT_METHOD_SERVICE);
            input.hideSoftInputFromWindow(getWindowToken(), 0);
        }
        return super.dispatchTouchEvent(event);
    }

    @Override
    public void sendAccessibilityEventUnchecked(AccessibilityEvent event) {
        if (event.getEventType() == AccessibilityEvent.TYPE_VIEW_TEXT_CHANGED) {
            // Since we're replacing the text every time we add or remove a
            // character, only read the difference. (issue 5337550)
            final int added = event.getAddedCount();
            final int removed = event.getRemovedCount();
            final int length = event.getBeforeText().length();
            if (added > removed) {
                event.setRemovedCount(0);
                event.setAddedCount(1);
                event.setFromIndex(length);
            } else if (removed > added) {
                event.setRemovedCount(1);
                event.setAddedCount(0);
                event.setFromIndex(length - 1);
            } else {
                return;
            }
        } else if (event.getEventType() == AccessibilityEvent.TYPE_VIEW_FOCUSED) {
            // The parent EditText class lets tts read "edit box" when this View has a focus, which
            // confuses users on app launch (issue 5275935).
            return;
        }
        super.sendAccessibilityEventUnchecked(event);
    }

    /**
     * Interface to get callback from the Edittext copy, cut and paste event
     * For time being only the Paste Event callback is generated
     */
    public interface OnEditTextActionListener {

        /**
         * If Edittext get paste event then this method will be called
         */
        void onPaste();
    }

}

在你的xml中你可以这样给出,

<[package name].KeypadlessKeypad
        android:id="@+id/dialnumbertv"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="#00000000"
        android:cursorVisible="false"
        android:ellipsize="start"
        android:gravity="center"
        android:inputType="phone"
        android:singleLine="true"
        android:textIsSelectable="true"
        android:textSize="30sp"
        android:textStyle="italic"
        android:visibility="visible"/>

在你的 fragment 中你可以这样实现,

   public void onViewCreated(final View view, Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);

        mDialNumbertv = view.findViewById(R.id.dialnumbertv);

        mDialNumbertv.setCursorVisible(false);

        mDialNumbertv.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (!isDigitsEmpty()) {
                    mDialNumbertv.setCursorVisible(true);
                }
            }
        });

        mDialNumbertv.addTextChangedListener(new TextWatcher() {
            @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) {
                if (isDigitsEmpty()) {
                    mDialNumbertv.setCursorVisible(false);
                }
//                updateDeleteButton();
            }
        });

        mDialNumbertv.setOnLongClickListener(new View.OnLongClickListener() {
            @Override
            public boolean onLongClick(View v) {
                // Ref https://android.googlesource.com/platform/packages/apps/Contacts/+/39948dc7e34dc2041b801058dada28fedb80c388/src/com/android/contacts/dialpad/DialpadFragment.java
                // Right now EditText does not show the "paste" option when cursor is not visible.
                // To show that, make the cursor visible, and return false, letting the EditText
                // show the option by itself.
                mDialNumbertv.setCursorVisible(true);
                return false;
            }
        });

        mDialNumbertv.setOnEditTextActionListener(
                new KeypadlessKeypad.OnEditTextActionListener() {
                    @Override
                    public void onPaste() {
                        // If some content pasted on mDialNumbertv
                        // we need to run some search on Contact and Price

                        String mobileNumber = mDialNumbertv.getText().toString();

                        if (TextUtils.isEmpty(mobileNumber)) {
                            return;
                        }

//                        updateContactName(mobileNumber);
                    }
                });

    }

    private KeypadlessKeypad mDialNumbertv;

    private boolean isDigitsEmpty() {
        return mDialNumbertv.length() == 0;
    }

    private void setClickedDigit(final String digitToSet) {
        if (!TextUtils.isEmpty(digitToSet)) {

            char digit = digitToSet.charAt(0);

            String mobileNumber = mDialNumbertv.getText() + digitToSet;
            mDialNumbertv.getText().insert(mDialNumbertv.getSelectionStart(), digitToSet);

            // If the cursor is at the end of the text we hide it.
            final int length = mDialNumbertv.length();
            if (length == mDialNumbertv.getSelectionStart() && length == mDialNumbertv.getSelectionEnd()) {
                mDialNumbertv.setCursorVisible(false);
            }
        }
    }

关于java - 即使 EditText 不可编辑,EditText 光标也可见,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45526766/

相关文章:

android - 迁移到 Android X 后应用程序崩溃 android.view.InflateException

java - 如何使用 EL 将字段绑定(bind)到重复的数据源?

java - 检查服务器上的 tomcat 版本以获取 ansible

java - 已签名的 Java 小程序

java - 将 Math.log 应用于 EditText

android - 如何在 android 中执行 setFocusable(false) 后检索焦点

android - 我如何更改 EditText 光标旋钮颜色 android(不是光标颜色旋钮)

java - 为什么 Integer 类缓存值在 -128 到 127 范围内?

Android 输入对话框返回输入值

java - 从波形获取声功率