1. 程式人生 > >解決EditText的gravity設定為right時,在android 7.0之上游標變細

解決EditText的gravity設定為right時,在android 7.0之上游標變細

問題闡述:

        根據需求,需要設定EditText從後往前輸入,游標預設在輸入文字的末尾,如圖所示:


暴力思路:

這種經常的做法是使用一個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);
    }
}
本文很簡單,只是我在網上沒有搜到相應的解決辦法,想到了這個粗暴的方法,如果大家有更好的方法,不吝賜教