自定义固定头文字的多行编辑框控件的实现分析
写这个自定义控件的缘由:公司新的UI界面实现需要实现一个可以固定头文字,并且可以代码去配置这个头文字,用户不能去修改和删除,在网上查阅了相关资料,貌似没有人去做过相关的自定义控件,于是自己花几个小时写了一遍,其中也想过多种方案,踩过许多坑。
首先,按照国际惯例,要实现自己的EditText当然得继承EditText控件于是乎我开始创建一个自定义的EditText,也开始了第一步入坑:
/**
* 主要功能: 左边有固定文字EditText
* Created by wz on 2016/8/5
* 修订历史:
*/
public class FixedEditText extends EditText {
private String fixedText;
private View.OnClickListener mListener;
@Override
protected void onTextChanged(CharSequence text, int start, int lengthBefore, int lengthAfter) {
super.onTextChanged(text, start, lengthBefore, lengthAfter);
}
@Override
public void setGravity(int gravity) {
super.setGravity(gravity);
}
@Override
public int getCompoundPaddingLeft() {
return 20;
}
public FixedEditText(Context context, AttributeSet attrs) {
super(context, attrs);
}
public void setFixedText(String text) {
fixedText = text;
int left = (int) getPaint().measureText(fixedText)+ getPaddingLeft();
setPadding(left, 0, 0, 100);
invalidate();
}
public void setDrawableClk(View.OnClickListener listener) {
mListener = listener;
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
Paint paint=new Paint();
if (!TextUtils.isEmpty(fixedText)) {
canvas.drawText(fixedText, 0, getTextSize(), getPaint());
this.setSelection(fixedText.length());
}
}
@Override
public boolean onTouchEvent(MotionEvent event) {
if (mListener != null && getCompoundDrawables()[2] != null) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
int i = getMeasuredWidth() - getCompoundDrawables()[2].getIntrinsicWidth();
int h=getMeasuredHeight() - getCompoundDrawables()[2].getIntrinsicHeight();
if (event.getX() > i||event.getY()>h) {
mListener.onClick(this);
return true;
}
break;
case MotionEvent.ACTION_UP:
break;
default:
break;
}
}
return super.onTouchEvent(event);
}
}
这段代码当我敲完,我以为可以完美的去装逼了,但是当我在准备运行时候,我忽然想到了,我需要的是多行文本,而且多行文本左对齐,运行来看,不能多行,设置完属性,发现多行特别并不是左对齐后面的活动文本左对齐了(UI要求的是第二行开始下面的活动文本都得与第一行的固定文本对齐),然后这样的Code当然是不能实现的。然后无脑的我马上想到了第二种解决办法,既然继承EditText得不到我想要的结果,而且显示不出我想要的效果,于是转换了一下思路,所谓固定值,也就是不能让用户删除,对吧?然而我们能够监听用户对键盘的操作,所以当我们判定到用户是否正在删除固定文字,如果是就拦截操作,这里面会涉及到光标的操作,和用户点击的操作,处理好这两个的关系,就会很简单的实现所谓的固定多行文本框啦。
下面贴上类代码供参考
/**
* 主要功能:
* Created by wz on 2016/8/5
* 修订历史:
*/
public class FixEditView extends EditText {
private Context context;
private String fixText;
private boolean isDelete = false;//是否是可删除
private boolean isFix = false;//表示是否需要显示固定文字
private ColorStateList defColor;//默认的字体颜色
private int fixColor=0;
public String getFixText() {
return fixText;
}
public void setFixTextColor(int color){
this.fixColor=color;
}
public void setFixText(String fixText) {
this.fixText = fixText;
if(fixColor!=0){
this.setTextColor(fixColor);
}
this.setText(fixText);
if (fixText.length() > 0) {
isFix = true;
}
//初始化光标位置
this.setSelection(fixText.length());
}
public FixEditView(Context context) {
super(context);
this.context = context;
init();
}
public FixEditView(Context context, AttributeSet attrs) {
super(context, attrs);
this.context = context;
init();
}
public void init() {
defColor=this.getTextColors();
this.addTextChangedListener(textWatcher);
this.setImeOptions(EditorInfo.IME_FLAG_NO_EXTRACT_UI);
this.setLongClickable(false);
}
TextWatcher textWatcher = new TextWatcher() {
private CharSequence temp;
@Override
public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {
temp = charSequence;
}
@Override
public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {
}
@Override
public void afterTextChanged(Editable editable) {
Random random=new Random();
//产生100000-999999的随机数
int randNum=random.nextInt(100000)%(999999-100000+1) + 100000;
//监听用户的输入状态
if (temp.length() == fixText.length() || temp.length() < fixText.length()) {
isDelete = false;
} else {
//产生随机颜色代码,只为装13,辣眼睛
int color=Color.parseColor("#"+randNum);
FixEditView.this.setTextColor(color);
isDelete = true;
}
}
};
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
}
@Override
protected void onSelectionChanged(int selStart, int selEnd) {
//限制光标的位置,使得最初光标总是从固定文本之后开始的
if (isFix) {
selStart = selStart < fixText.length() ? fixText.length() : selStart;
selEnd = selStart;
this.setSelection(selStart, selEnd);
}
super.onSelectionChanged(selStart, selEnd);
}
@Override
public boolean dispatchKeyEvent(KeyEvent event) {
if (event.getAction() == KeyEvent.ACTION_DOWN && event.getKeyCode() == 67) {//删除键
//当标记为不能删除的时候拦截操作
if (!isDelete) {
return !isDelete;
}
}
return super.dispatchKeyEvent(event);
}
}
xml布局文件代码:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:background="@color/bg_page"
android:layout_height="match_parent">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="250px"
android:layout_marginTop="14px"
android:background="@color/white"
android:orientation="horizontal"
android:visibility="visible">
<TextView
android:layout_width="170px"
android:layout_height="wrap_content"
android:layout_marginTop="30px"
android:gravity="center"
android:singleLine="true"
android:text="工作要求"
android:textColor="@color/text_gray_normal"
android:textSize="28px" />
<View
android:layout_width="1px"
android:layout_height="206px"
android:layout_gravity="center_vertical"
android:layout_marginLeft="10px"
android:background="@color/line_main" />
<com.example.lenovo.diyedittext.FixEditView
android:id="@+id/fev_work_info"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginLeft="40px"
android:layout_marginTop="30px"
android:layout_weight="1"
android:background="@color/transparent"
android:gravity="top"
android:hint="请输入相关内容,岗位要求,要求20-1500字。"
android:maxHeight="220px"
android:maxLength="1500"
android:minHeight="220px"
android:padding="5dp"
android:textColor="@color/text_gray_normal"
android:textSize="28px" />
</LinearLayout>
</LinearLayout>
Activity中如何使用:
/**
* 主要功能:
* Created by wz on 2016/8/5
* 修订历史:
*/
public class MainActivity extends Activity {
FixEditView fev_work_info;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_maple);
fev_work_info= (FixEditView) findViewById(R.id.fev_work_info);
fev_work_info.setFixTextColor(Color.parseColor("#30C27B"));
fev_work_info.setFixText("这是固定文字。");
fev_work_info.setGravity(Gravity.LEFT);
}
}
感受:不要总是用别人造的轮子,新手主要是用现成的轮子,普通的主要是改造成自己的轮子,高手都是造轮子,所以一步步来,能自己写出来的东西尽量自己写,相信总有一天会蜕变成那个造轮子的嘛。
内容大概就是这样,如果有什么不对的地方,欢迎指正,相互学习很有必要。