1、设置XML布局
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:focusable="true"
android:focusableInTouchMode="true"
android:orientation="vertical">
<EditText
android:id="@+id/et_input"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@android:color/transparent"
android:gravity="top"
android:inputType="textMultiLine"
android:padding="10dp"
android:selectAllOnFocus="true"
android:textColor="#DE000000"
android:textSize="16dp" />
<TextView
android:id="@+id/tv_input"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="right"
android:layout_marginBottom="5dp"
android:layout_marginRight="7dp"
android:text="100/100"
android:textColor="#8A000000"
android:textSize="14dp" />
</LinearLayout>
2、定义attrs.xml文件
<declare-styleable name="LinesEditView">
<attr name="lev_maxCount" format="integer"/>
<attr name="lev_ignoreCnOrEn" format="boolean"/>
<attr name="lev_hintText" format="string|reference"/>
<attr name="lev_hintTextColor" format="color|reference"/>
<attr name="lev_contentText" format="string|reference"/>
<attr name="lev_contentTextSize" format="dimension|reference"/>
<attr name="lev_contentTextColor" format="color|reference"/>
<attr name="lev_contentViewHeight" format="dimension|reference"/>
</declare-styleable>
3、自定义控件继承LinearLayout
public class LinesEditView extends LinearLayout {
private Context mContext;
private EditText mInputEt;
private TextView mInputTv;
private int MAX_COUNT;
private String hintText;
private int hintTextColor;
private boolean ignoreCnOrEn;
private String contentText;
private int contentTextSize;
private int contentTextColor;
private float contentViewHeight;
public LinesEditView(Context context) {
this(context, null);
}
public LinesEditView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public LinesEditView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
mContext = context;
TypedArray typedArray = context.obtainStyledAttributes(attrs,R.styleable.LinesEditView);
MAX_COUNT = typedArray.getInteger(R.styleable.LinesEditView_lev_maxCount, 100);
ignoreCnOrEn = typedArray.getBoolean(R.styleable.LinesEditView_lev_ignoreCnOrEn, true);
hintText = typedArray.getString(R.styleable.LinesEditView_lev_hintText);
hintTextColor = typedArray.getColor(R.styleable.LinesEditView_lev_hintTextColor, Color.parseColor("#42000000"));
contentText = typedArray.getString(R.styleable.LinesEditView_lev_contentText);
contentTextColor = typedArray.getColor(R.styleable.LinesEditView_lev_contentTextColor, Color.parseColor("#8A000000"));
contentTextSize = typedArray.getDimensionPixelSize(R.styleable.LinesEditView_lev_contentTextSize, dp2px(context, 14));
contentViewHeight = typedArray.getDimensionPixelSize(R.styleable.LinesEditView_lev_contentViewHeight,dp2px(context, 140));
typedArray.recycle();
initView();
}
private void initView() {
View view = LayoutInflater.from(mContext).inflate(R.layout.layout_lines_edit_view, this);
mInputEt = (EditText) view.findViewById(R.id.et_input);
mInputTv = (TextView) view.findViewById(R.id.tv_input);
if (this.getBackground() == null) {
this.setBackgroundResource(R.drawable.selector_lines_edit_view_bg);
}
mInputEt.addTextChangedListener(mTextWatcher);
mInputEt.setHint(hintText);
mInputEt.setHintTextColor(hintTextColor);
mInputEt.setText(contentText);
mInputEt.setTextColor(contentTextColor);
mInputEt.setTextSize(TypedValue.COMPLEX_UNIT_PX, contentTextSize);
mInputEt.setHeight((int) contentViewHeight);
/**
* 配合 mInputTv xml的 android:focusable="true"
android:focusableInTouchMode="true"
在iet_input设置完文本后
不给et_input 焦点
*/
mInputTv.requestFocus();
configCount();
mInputEt.setSelection(mInputEt.length()); // 将光标移动最后一个字符后面
/**
* focus后给背景设置Selected
*/
mInputEt.setOnFocusChangeListener(new OnFocusChangeListener() {
@Override
public void onFocusChange(View view, boolean b) {
LinesEditView.this.setSelected(b);
}
});
}
private TextWatcher mTextWatcher = new TextWatcher() {
private int editStart;
private int editEnd;
@Override
public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {
}
@Override
public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {
}
@Override
public void afterTextChanged(Editable editable) {
editStart = mInputEt.getSelectionStart();
editEnd = mInputEt.getSelectionEnd();
// 先去掉监听器,否则会出现栈溢出
mInputEt.removeTextChangedListener(mTextWatcher);
if (ignoreCnOrEn) {
//当输入字符个数超过限制的大小时,进行截断操作
while (calculateLengthIgnoreCnOrEn(editable.toString()) > MAX_COUNT) {
editable.delete(editStart - 1, editEnd);
editStart--;
editEnd--;
}
} else {
// 因为是中英文混合,单个字符而言,calculateLength函数都会返回1
while (calculateLength(editable.toString()) > MAX_COUNT) { // 当输入字符个数超过限制的大小时,进行截断操作
editable.delete(editStart - 1, editEnd);
editStart--;
editEnd--;
}
}
mInputEt.setSelection(editStart);
// 恢复监听器
mInputEt.addTextChangedListener(mTextWatcher);
configCount();
}
};
private long calculateLength(CharSequence c) {
double len = 0;
for (int i = 0; i < c.length(); i++) {
int tmp = (int) c.charAt(i);
if (tmp > 0 && tmp < 127) {
len += 0.5;
} else {
len++;
}
}
return Math.round(len);
}
private int calculateLengthIgnoreCnOrEn(CharSequence c) {
int len = 0;
for (int i = 0; i < c.length(); i++) {
len++;
}
return len;
}
private void configCount() {
if (ignoreCnOrEn) {
int nowCount = calculateLengthIgnoreCnOrEn(mInputEt.getText().toString());
mInputTv.setText(String.valueOf((nowCount)) + "/" + MAX_COUNT);
} else {
long nowCount = calculateLength(mInputEt.getText().toString());
mInputTv.setText(String.valueOf((nowCount)) + "/" + MAX_COUNT);
}
}
private static int dp2px(Context context, float dp) {
final float scale = context.getResources().getDisplayMetrics().density;
return (int) (dp * scale + 0.5f);
}
public void setContentText(String content) {
contentText = content;
if (mInputEt == null) {
return;
}
mInputEt.setText(contentText);
}
public String getContentText() {
if (mInputEt != null) {
contentText = mInputEt.getText() == null ? "" : mInputEt.getText().toString();
}
return contentText;
}
public void setHintText(String hintText) {
this.hintText = hintText;
if (mInputEt == null) {
return;
}
mInputEt.setHint(hintText);
}
public void setContentTextSize(int size) {
if (mInputEt == null) {
return;
}
mInputEt.setTextSize(TypedValue.COMPLEX_UNIT_PX, size);
}
public void setContentTextColor(int color) {
if (mInputEt == null) {
return;
}
mInputEt.setTextColor(color);
}
public void setHintColor(int color) {
if (mInputEt == null) {
return;
}
mInputEt.setHintTextColor(color);
}
public String getHintText() {
if (mInputEt != null) {
hintText = mInputEt.getHint() == null ? "" : mInputEt.getHint().toString();
}
return hintText;
}
public void setMaxCount(int max_count) {
this.MAX_COUNT = max_count;
configCount();
}
public void setIgnoreCnOrEn(boolean ignoreCnOrEn) {
this.ignoreCnOrEn = ignoreCnOrEn;
configCount();
}
}
4、使用方法,直接在layout文件中引用自定义控件
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.tf.camerapreview.myapplication.LinesEditView
android:id="@+id/et"
android:layout_width="match_parent"
android:layout_height="160dp"
android:layout_margin="20dp"
app:lev_maxCount="100"
/>
</LinearLayout>