先看代码
public class EditableSpinner extends LinearLayout implements AdapterView.OnItemClickListener {
private LinearLayout linearLayout;
private EditText inputText;
private ListPopupWindow popupWindow;
private ArrayAdapter arrayAdapter;
private OnItemClickListener onItemClickListener;
public interface OnItemClickListener {
void onItemClick(int position);
}
public interface OnTextChangeListener {
void onTextChanged();
}
public void setOnItemClickListener(OnItemClickListener onItemClickListener) {
this.onItemClickListener = onItemClickListener;
}
public EditableSpinner(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
LayoutInflater.from(context).inflate(R.layout.editable_spinner,this);
ImageButton mImgBtnDown = findViewById(R.id.img_btn_down);
linearLayout = findViewById(R.id.editableSpinner);
inputText = findViewById(R.id.et_input);
popupWindow = new ListPopupWindow(context);
TypedArray attrArr = context.obtainStyledAttributes(attrs, R.styleable.EditableSpinner);
Drawable downImage = attrArr.getDrawable(R.styleable.EditableSpinner_downBtnImage);
float textSize = attrArr.getDimension(R.styleable.EditableSpinner_textSize, 14);
int downBtnWidth = (int) attrArr.getDimension(R.styleable.EditableSpinner_downBtnWidth, DisplayUtil.dp2px(context, 40));
int textColor = attrArr.getColor(R.styleable.EditableSpinner_textColor, 0x000000);
int downBtnBgColor = attrArr.getColor(R.styleable.EditableSpinner_downBtnBackground, 0x00ffffff);
boolean editable = attrArr.getBoolean(R.styleable.EditableSpinner_editText, true);
mImgBtnDown.setImageDrawable(downImage);
mImgBtnDown.setBackgroundColor(downBtnBgColor);
LayoutParams lp = (LayoutParams) mImgBtnDown.getLayoutParams();
lp.width = downBtnWidth;
mImgBtnDown.setLayoutParams(lp);
mImgBtnDown.setOnClickListener(v -> popupWindow.show());
inputText.setTextSize(DisplayUtil.px2dp(context, textSize));
inputText.setTextColor(textColor);
inputText.setFocusable(editable);
inputText.setFocusableInTouchMode(editable);
attrArr.recycle();
}
public EditableSpinner setAdapter(ArrayAdapter<String> adapter) {
arrayAdapter = adapter;
popupWindow.setAdapter(adapter);
popupWindow.setAnchorView(this);
popupWindow.setModal(true);
popupWindow.setOnItemClickListener(this);
return this;
}
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
popupWindow.dismiss();
inputText.setText((CharSequence) arrayAdapter.getItem(position));
if (onItemClickListener != null) {
onItemClickListener.onItemClick(position);
}
}
public int getItemSelectionIndex() {
return popupWindow.getSelectedItemPosition();
}
public void setItemSelection(int index) {
popupWindow.setSelection(index);
arrayAdapter.notifyDataSetChanged();
inputText.setText((CharSequence) arrayAdapter.getItem(index));
if (onItemClickListener != null) {
onItemClickListener.onItemClick(index);
}
}
public String getEditString() {
return inputText.getText().toString().trim();
}
public void setEditString(String str) {
inputText.setText(str);
if (onItemClickListener != null) {
onItemClickListener.onItemClick(0);
}
}
private int maxValue, minValue;
public void setMaxAndMinValue(int minValue, int maxValue) {
inputText.setInputType(InputType.TYPE_CLASS_NUMBER);
this.maxValue = maxValue;
this.minValue = minValue;
}
public void enableTextChangeListener(final OnTextChangeListener listener) {
inputText.addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {
linearLayout.setBackgroundResource(R.drawable.spinner_border_nomal);
}
@Override
public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {
try {
int value = Integer.valueOf(charSequence.toString());
if (value < minValue || value > maxValue) {
linearLayout.setBackgroundResource(R.drawable.spinner_border_error);
}else {
listener.onTextChanged();
}
}catch (NumberFormatException e) {
if (!charSequence.toString().equals("") && !charSequence.toString().equals("- -")) {
linearLayout.setBackgroundResource(R.drawable.spinner_border_error);
}else {
listener.onTextChanged();
}
e.printStackTrace();
}
}
@Override
public void afterTextChanged(Editable editable) {
}
});
}
}
布局文件
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/editableSpinner"
android:background="@drawable/spinner_border_nomal"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="match_parent">
<EditText
android:id="@+id/et_input"
android:inputType=""
android:gravity="center"
android:background="@null"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="match_parent"
android:textCursorDrawable="@null"
android:maxLines="1"
tools:ignore="Autofill,LabelFor" />
<ImageButton
android:id="@+id/img_btn_down"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:scaleType="centerInside"
tools:ignore="ContentDescription" />
</LinearLayout>
下面是 styleable 文件
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="EditableSpinner">
<attr name="downBtnImage" format="reference"/>
<attr name="downBtnBackground" format="color"/>
<attr name="downBtnWidth" format="dimension"/>
<attr name="textSize" format="dimension"/>
<attr name="textColor" format="color"/>
<attr name="editText" format="boolean"/>
</declare-styleable>
</resources>
下面是 spinner_border_error 文件
<?xml version="1.0" encoding="UTF-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<!-- rectangle表示为矩形 -->
<!-- 填充的颜色 -->
<solid android:color="@color/BlueDisable" />
<!-- 边框的颜色和粗细 -->
<stroke
android:width="1dp"
android:color="@color/RedPress" />
<padding
android:left="1dp"
android:top="1dp"
android:bottom="1dp"
android:right="1dp"/>
<!-- android:radius 圆角的半径 -->
<corners
android:radius="0dp" />
</shape>
使用方法
EditableSpinner spinner = findViewById(R.id.spinner);
//数据
List<String> contentList = new ArrayList<>();
contentList.add("1");
contentList.add("2");
contentList.add("3");
//弹框列表适配器
ArrayAdapter<String> arrayAdapter = new ArrayAdapter<>(mActivity, android.R.layout.simple_spinner_item, contentList);
spinner.setAdapter(arrayAdapter);
//通知数据更新
arrayAdapter.notifyDataSetChanged();
//选择类别数据
spinner.setOnItemClickListener(position -> {
String selectStr = spinner.getEditString();
...
});
//设置数据范围
spinner.setMaxAndMinValue(0,100);
//设置文本变化listener
spinner.enableTextChangeListener(() -> {
String selectStr = spinner.getEditString();
...
});
简单说明
代码很简单,就是一个输入框加一个图片按钮,点击图片按钮会弹出一个 PopupWindow,PopupWindow 里面就是一个文本列表,后面在 TextChangeListener 内加了点判断逻辑,如果有问题会将框外围变红,效果看起来不错,没什么技术。