问题阐述:
根据需求,需要设置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);
}
}
本文很简单,只是我在网上没有搜到相应的解决办法,想到了这个粗暴的方法,如果大家有更好的方法,不吝赐教