问题阐述:

        根据需求,需要设置EditText从后往前输入,光标默认在输入文字的末尾,如图所示:

android 设置光标默认在最后_Text

暴力思路:

这种经常的做法是使用一个TextView覆盖在EditText来伪装EditText的提示文字。实际操作时却发现在android6.0及以下没有问题,在更高版本中,却出现光标定位在末尾的时候特别细的情况,显然是不合格的。网上搜索解决办法不多,没办法,只有自己来了。由于项目中这种输入形式较多,索性做成自定义组合控件统一处理,解决思路:光标显示异常只出现在高版本,并且是光标在末尾的时候才出现,由于是显示问题,大可使用障眼法解决,何不让EditText末尾追加一个空格,另外让用户使用时光标定位不到末尾。

解决之道:

布局很简单,里面使用了项目中的样式,见谅,如下:

<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/ll"
    style="@style/LLWithPaddingStyle">
    <TextView
        android:id="@+id/tv_title"
        style="@style/TvLeftWapStyle" />
    <FrameLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content">
        <com.hc360.koiambuyer.widget.SelectionEditText
            android:id="@+id/et_input"
            style="@style/TvRightStyle"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginRight="0dp"
            android:background="@null"
            android:maxLines="4"
            android:textCursorDrawable="@drawable/shape_et_cursor"
            android:gravity="right|center_vertical"
            android:textColor="@color/tvNormalColor" />
        <TextView
            android:id="@+id/tv_et_hint"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginRight="9dp"
            android:gravity="right|center_vertical"
            android:text="@string/personal_data_name_hint"
            android:textColor="@color/HintColor" />
    </FrameLayout>
</LinearLayout>

定义一些距离自定义属性

<declare-styleable name="EditInput">
        <attr name="ei_paddingBottom" format="dimension"/>
        <attr name="ei_paddingTop" format="dimension"/>
        <attr name="ei_paddingLeft" format="dimension"/>
        <attr name="ei_paddingRight" format="dimension"/>
    </declare-styleable>

自定义组合控件,注释已经很明白了,也很简单,就不多说了

public class EditInput extends LinearLayout {

    private static final float PADDING_DEFAULT = 20;
    private static final float PADDING_DEFAULT_LEFT = 15;
    private static final float ANDROID_SDK_NUM= 24;
    @BindView(R.id.tv_title)
    TextView mTvTitle;
    @BindView(R.id.et_input)
    SelectionEditText mEtInput;
    @BindView(R.id.tv_et_hint)
    TextView mTvEtHint;
    @BindView(R.id.ll)
    LinearLayout mLl;

    public EditInput(Context context) {
        this(context, null);
    }

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

    public EditInput(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        View.inflate(context, R.layout.layout_et, this);
        ButterKnife.bind(this);
        try {
            //获取自定义属性
            TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.CircleImageView);
            int paddingBottom = a.getDimensionPixelSize(R.styleable.EditInput_ei_paddingBottom,
                    (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, PADDING_DEFAULT, 
                            getResources().getDisplayMetrics()));
            int paddingLeft = a.getDimensionPixelSize(R.styleable.EditInput_ei_paddingLeft,
                    (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, PADDING_DEFAULT_LEFT, 
                            getResources().getDisplayMetrics()));
            int paddingRight = a.getDimensionPixelSize(R.styleable.EditInput_ei_paddingRight,
                    (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, PADDING_DEFAULT_LEFT,
                            getResources().getDisplayMetrics()));
            int paddingTop = a.getDimensionPixelSize(R.styleable.EditInput_ei_paddingTop,
                    (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, PADDING_DEFAULT,
                            getResources().getDisplayMetrics()));
            mLl.setPadding(paddingLeft,0,0,0);
            mEtInput.setPadding(0,paddingTop,paddingRight,paddingBottom);
            mTvEtHint.setPadding(0,paddingTop,10,paddingBottom);
        }catch (Exception e){}
        //当EditText获取焦点的时候,覆盖的TextView就消失
        mEtInput.setOnFocusChangeListener(new OnFocusChangeListener() {
            @Override
            public void onFocusChange(View v, boolean hasFocus) {
                if (hasFocus){
                    mTvEtHint.setVisibility(GONE);
                }else {
                    if (!TextUtils.isEmpty(mEtInput.getText().toString().trim())){
                        mTvEtHint.setVisibility(GONE);
                    }else {
                        mTvEtHint.setVisibility(VISIBLE);
                    }
                }
            }
        });

        //android7.0之上执行这段代码

        if (Build.VERSION.SDK_INT >= ANDROID_SDK_NUM) {
            //初始是EditText追加空格,光标定位到空格的前面
            mEtInput.setText(" ");
            mEtInput.setSelection(0);
            //EditText的光标变化监听,当光标位置到末尾时,强制将光标改为空格的前面
            mEtInput.setOnSelectionChange(new SelectionEditText.OnSelectionChange() {
                @Override
                public void onSelectionChange(int selStart, int selEnd) {
                    String etText = mEtInput.getText().toString();
                    if (etText.endsWith(" ")){
                        if (selStart == mEtInput.getText().toString().length()){
                            mEtInput.setSelection(mEtInput.getText().toString().length()-1);
                        }
                    }
                }
            });
            //确保EditText输入文字在空格的前面,光标在空格的前面
            mEtInput.addTextChangedListener(new CustomTextWatcher() {
                @Override
                public void afterTextChanged(Editable s) {
                    if (!mEtInput.getText().toString().endsWith(" ")){
                        mEtInput.setText(s+" ");
                    }
                    if (mEtInput.getSelectionStart() == s.length()){
                        mEtInput.setSelection(s.length()-1);
                    }
                }
            });
        }
    }

    /**
     * 初始化标题跟EditText的提示文字
     * @param title
     * @param contentHint
     */
    public void initText(String title,String contentHint){
        mTvTitle.setText(title);
        mTvEtHint.setText(contentHint);
    }

    /**
     * 设置EditText的输入内容
     * @param text
     */
    public void setEtText(String text){
        //高版本末尾追加空格,设置光标在空格前
        if (!TextUtils.isEmpty(text)){
            if (Build.VERSION.SDK_INT >= ANDROID_SDK_NUM) {
                text = text+" ";
                mEtInput.setText(text);
                mEtInput.setSelection(text.length()-1);
            }else {
                mEtInput.setText(text);
                mEtInput.setSelection(text.length());
            }
            mTvEtHint.setVisibility(GONE);
        }else {
            if (Build.VERSION.SDK_INT >= ANDROID_SDK_NUM) {
                mEtInput.setText(" ");
                mEtInput.setSelection(0);
            }
        }
    }

    /**
     * 获取输入的文字,记得要trim一下,因为EditText可能设置只能输入数字类型等等
     * @return
     */
    public String getEtText(){
        return mEtInput.getText().toString().trim();
    }

    /**
     * 设置最大输入文字数
     * @param max
     */
    public void setEtMaxNum(int max){
        mEtInput.addTextChangedListener(new MaxNumTextWatcher(max, mEtInput));
    }

    /**
     * 设置输入格式
     * @param type
     */
    public void setEtInputType(int type){
        mEtInput.setInputType(type);
    }
}

里面使用的SelectionEditText其实就是一个EditText,只不过是暴漏了光标变化的监听

public class SelectionEditText extends EditText {
    OnSelectionChange mOnSelectionChange;
    public SelectionEditText(Context context, AttributeSet attrs) {
        super(context, attrs);
        // TODO Auto-generated constructor stub
    }

    @Override
    public void onDraw(Canvas canvas) {
        super.onDraw(canvas);
    }

    @Override
    protected void onSelectionChanged(int selStart, int selEnd) {
        // TODO Auto-generated method stub
        super.onSelectionChanged(selStart, selEnd);
        if (mOnSelectionChange !=null){
            mOnSelectionChange.onSelectionChange(selStart,selEnd);
        }
    }

    public void setOnSelectionChange(OnSelectionChange onSelectionChange){
        mOnSelectionChange = onSelectionChange;
    }
    public interface OnSelectionChange{
        void onSelectionChange(int selStart, int selEnd);
    }
}

本文很简单,只是我在网上没有搜到相应的解决办法,想到了这个粗暴的方法,如果大家有更好的方法,不吝赐教