先上代碼
public class MinMaxEditText extends LinearLayout implements SaveFormField {
@Inject
Bus bus;
TextView label;
EditText value;
TextView charLimit;
TextView minLimit;
int charLimitValue;
private String labelText;
private DirtyListener listener;
private String originalString;
private TextWatcher externalTextWatcher;
public MinMaxEditText(Context context) {
super(context);
init();
}
public MinMaxEditText(Context context, AttributeSet attrs) {
super(context, attrs);
init();
TypedArray a = context.getTheme().obtainStyledAttributes(attrs, R.styleable.MinMaxEditText, 0, 0);
try {
setLabel(a.getString(R.styleable.MinMaxEditText_label));
setCharLimit(a.getInt(R.styleable.MinMaxEditText_charLimit, 0));
setMinLimit(a.getInt(R.styleable.MinMaxEditText_minLimit, 0));
setHint(a.getString(R.styleable.MinMaxEditText_hintText));
showCharLimit(a.getBoolean(R.styleable.MinMaxEditText_showCharLimit, true));
setIconId((a.getResourceId(R.styleable.MinMaxEditText_iconResource, -1)));
setLimitTextSize(a.getDimension(R.styleable.MinMaxEditText_limitTextSize, 0));
setHintTextColorIfExists(a);
setEditTextTextColorIfExists(a);
} finally {
// TypedArray 是單例模式 回收之后 其他地方才能夠使用
a.recycle();
}
}
private void init() {
//這里是bus組件的引入 不用管
GrindrApplication.getGrindrComponent().inject(this);
//設(shè)置布局方向
// 特定的布局view 有什么提供的方法 可以看源碼 看提供哪些方法 來用
setOrientation(VERTICAL);
// 引入我們要展示的布局文件 并且賦值引用
View.inflate(getContext(), R.layout.min_max_edit_text, this);
label = findViewById(R.id.view_edit_profile_edit_label);
value = findViewById(R.id.view_edit_profile_edit_value);
charLimit = findViewById(R.id.view_edit_profile_edit_char_limit);
minLimit = findViewById(R.id.view_edit_profile_edit_min_limit);
//當(dāng)輸入的內(nèi)容改變的時(shí)候 做一些判斷和處理
value.addTextChangedListener(new ExternalTextWatcher());
//這個(gè)地方是設(shè)置輸入軟鍵盤enter鍵的顯示
value.setImeOptions(EditorInfo.IME_ACTION_DONE);
//設(shè)置只能單行處理
setNumLines();
}
//自定義listener的名稱 并且添加
public void addTextChangedListener(TextWatcher tw) {
this.externalTextWatcher = tw;
}
public String getText() {
return value.getText().toString();
}
public void setText(String text) {
value.setText(text);
originalString = text;
setContentDescription();
}
public String getLabel() {
return labelText;
}
public void setLabel(String labelText) {
this.labelText = labelText;
label.setText(labelText);
setContentDescription();
}
private void setContentDescription() {
setContentDescription(getResources().getString(R.string.edit_profile_edit_text_content_description, getLabel(), getText(), getText().length(), charLimitValue));
}
public void setCharLimit(int charLimitValue) {
this.charLimitValue = charLimitValue;
if (charLimitValue == 0) {
charLimit.setVisibility(View.GONE);
} else {
charLimit.setVisibility(View.VISIBLE);
int numOfChars = charLimit.getText().length();
charLimit.setText(String.format(Locale.getDefault(), "%d/%d", numOfChars, charLimitValue));
//這個(gè)地方是設(shè)置edittext輸入字符的最大個(gè)數(shù)
value.setFilters(new InputFilter[]{createInputFilter(charLimitValue)});
}
}
public void setMinLimit(int charLimitValue) {
if (charLimitValue == 0) {
minLimit.setVisibility(View.GONE);
} else {
minLimit.setVisibility(View.VISIBLE);
minLimit.setText(String.format(getResources().getString(R.string.min_max_edit_text_minimum), charLimitValue));
}
}
public void setHint(String hint) {
value.setHint(hint);
}
protected void setNumLines() {
value.setMaxLines(1);
value.setSingleLine();
value.setLines(1);
}
public String getHint() {
return value.getHint().toString();
}
public void showCharLimit(boolean show) {
charLimit.setVisibility(show ? View.VISIBLE : View.GONE);
}
public void setIconId(int iconId) {
if (iconId > 0) {
value.setCompoundDrawablesWithIntrinsicBounds(ContextCompat.getDrawable(GrindrApplication.getGrindrApplication(), iconId), null, null, null);
}
}
@Override
public void setDirtyListener(DirtyListener listener) {
this.listener = listener;
}
public EditText getValueView() {
return value;
}
public void update(String value, DirtyListener dirtyListener) {
setText(value);
setDirtyListener(dirtyListener);
getValueView().setHorizontallyScrolling(false);
getValueView().setMaxLines(Integer.MAX_VALUE);
}
private void setLimitTextSize(float limitTextSize) {
if (limitTextSize != 0) {
charLimit.setTextSize(TypedValue.COMPLEX_UNIT_PX, limitTextSize);
minLimit.setTextSize(TypedValue.COMPLEX_UNIT_PX, limitTextSize);
}
}
private void setEditTextTextColorIfExists(TypedArray a) {
if (a.hasValue(R.styleable.MinMaxEditText_minMaxEditTextColor)) {
int editTextColor = a.getColor(R.styleable.MinMaxEditText_minMaxEditTextColor, 0);
value.setTextColor(editTextColor);
}
}
private void setHintTextColorIfExists(TypedArray a) {
if (a.hasValue(R.styleable.MinMaxEditText_minMaxHintTextColor)) {
int hintTextColor = a.getColor(R.styleable.MinMaxEditText_minMaxHintTextColor, 0);
value.setHintTextColor(hintTextColor);
}
}
private class ExternalTextWatcher implements TextWatcher {
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
if (externalTextWatcher != null) {
externalTextWatcher.beforeTextChanged(s, start, count, after);
}
}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
if (externalTextWatcher != null) {
externalTextWatcher.onTextChanged(s, start, before, count);
}
}
// 上面兩個(gè)方法安全使用自定義的 listener 代替系統(tǒng)的 listener
@Override
public void afterTextChanged(Editable s) { // s 是改變后的字符串的值
//判斷數(shù)值是否改變 改變的話用 改變isDirty的值
if (listener != null && (originalString == null || !originalString.equals(s.toString()))) {
listener.onFieldDirty(true);
}
//設(shè)置字?jǐn)?shù)顯示的值 在這里進(jìn)行組裝
if (charLimitValue != 0) {
charLimit.setText(String.format(Locale.getDefault(), "%d/%d", getCurCharSize(s), charLimitValue));
}
if (externalTextWatcher != null) {
externalTextWatcher.afterTextChanged(s);
}
setContentDescription();
}
}
protected InputFilter createInputFilter(int charLimitValue){
return new InputFilter.LengthFilter(charLimitValue);
}
protected int getCurCharSize(Editable s){
return s.length();
}
}
- 自定義屬性文件如下
<declare-styleable name="MinMaxEditText">
<attr name="label" format="string" />
<attr name="charLimit" format="integer" />
<attr name="minLimit" format="integer" />
<attr name="hintText" format="string" />
<attr name="minMaxHintTextColor" format="color" />
<attr name="showCharLimit" format="boolean" />
<attr name="iconResource" format="reference" />
<attr name="minMaxEditTextColor" format="color" />
<attr name="limitTextSize" format="dimension" />
</declare-styleable>
說明
-
自定義view的效果如圖所示
custom1.jpg - 功能: 設(shè)置上方的說明文字闽坡,設(shè)置輸入框的最大輸入數(shù)量洼怔,最小輸入數(shù)量谅河,hinttext铡买,hinttext的color,輸入框左邊的圖像標(biāo)志低淡,以及輸入數(shù)量顯示的數(shù)字大小姓言。