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

时间:2017-08-05 22:05:22

标签: java android android-edittext focus

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

是否有可能使EditText在哪里,即使它不可编辑,光标也可见?

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

我为setOnClickListner()制作了setOnLongClickListner()EditText方法。在这种方法中,我隐藏了窗口的软输入,我也使用setTextIsSelectable(false)。我唯一的问题是当我双击EditText软输入键盘显示而我不知道如何隐藏它时,我尝试在清单中使用android:windowSoftInputMode="stateAlwaysHidden",但它也不起作用。< / p>

编辑:

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

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 -->       

3 个答案:

答案 0 :(得分:1)

使用此代码实现这一目标,

开发时我从原生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"/>

在你的片段中你可以这样实现,

   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);
            }
        }
    }

答案 1 :(得分:0)

您可以使用edittext.setselection(0)

也许您可以使用requestfocus()

请求焦点

答案 2 :(得分:0)

我想要实现以下相同的行为-

  1. 创建一个自定义类,该类将覆盖AppCompatEditText的2个方法。

     class CustomEditText(context: Context?, attrs: AttributeSet) : AppCompatEditText(context, attrs) {
     override fun onCheckIsTextEditor(): Boolean {
         return true
     }
    
     override fun isTextSelectable(): Boolean {
         return true
     }
    }
    
  2. 在XML文件中,使用此自定义视图创建EditText。

     <com.ui.custom.CustomEditText
         android:id="@+id/et_email"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
         android:inputType="none"
         android:focusable="true"
         android:gravity="center"
         android:focusableInTouchMode="true"/>
    
  3. 现在,只需添加onFocusChangeListener并设置editText.setKeyListener = null。

      binding.etEmail.onFocusChangeListener = OnFocusChangeListener { v, hasFocus ->
         if (hasFocus) {
             binding.etEmail.keyListener = null
         }
     }
    

如果需要,您可以在onTouch上添加相同的内容。

这里的主要问题是View类的onCheckIsTextEditor()始终返回false,即使在代码中调用setCursorVisible(true)也会导致光标从不闪烁或不可见。

我希望这会有所帮助。