今天抽出时间写一写关于这个控件我的理解,文笔不好,但是可以解决问题哈。
一、公司定下来的需求是这样的:
1、某两个界面都有右侧侧滑;
2、侧滑上有四个文本框;
3、每个文本框点击时候即出现提示下拉;
4、每个文本框输入的时候也会出现提示下拉;
6、当点击下拉内的item时,item文字显示在文本框内;
7、巴拉巴拉...就这么一堆。
二、想法
1、EditText+ListView;
2、AutoCompleteTextView或AppCompatAutoCompleteTextView或MultiAutoCompleteTextView
3、EditText+ListView;
4、去gihub大海捞针去;
...
为了保证程序性的简洁性、易用性、低维护成本....(其实就是懒),选择了第二个方案;实施之后,第二个虽然代码少了,但是这个逻辑啊,一张图表示(此处省略一万字)。既然是自己选择的方案,哭着也得写完。
三、实施
1、在xml文件内写布局
<android.support.v7.widget.AppCompatAutoCompleteTextView
android:id="@+id/act_hidden_danger_pro_name"
android:layout_width="match_parent"
android:layout_height="35dp"
android:layout_below="@+id/tv_nv_hidden_danger_name"
android:layout_marginEnd="20dp"
android:layout_marginStart="20dp"
android:layout_marginTop="20dp"
android:background="@mipmap/bg_text_all"
android:completionThreshold="1"
android:hint="项目名称"
android:lines="1"
android:paddingEnd="@dimen/widget_margin_5"
android:paddingStart="@dimen/widget_margin_5"
android:singleLine="true"
android:textColor="@color/contents_text"
android:textSize="16sp" />
这样的控件写了四个,其实可以写到values/style.xml文件内,但是为了只管展现,我就这么写了(说到底第还是懒)。下面放完整的侧滑代码:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="@+id/tv_nv_hidden_danger_name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="40dp"
android:gravity="center"
android:text="@string/filtrate"
android:textColor="@color/contents_text"
android:textSize="20sp" />
<android.support.v7.widget.AppCompatAutoCompleteTextView
android:id="@+id/act_hidden_danger_pro_name"
android:layout_width="match_parent"
android:layout_height="35dp"
android:layout_below="@+id/tv_nv_hidden_danger_name"
android:layout_marginEnd="20dp"
android:layout_marginStart="20dp"
android:layout_marginTop="20dp"
android:background="@mipmap/bg_text_all"
android:completionThreshold="1"
android:hint="项目名称"
android:lines="1"
android:paddingEnd="@dimen/widget_margin_5"
android:paddingStart="@dimen/widget_margin_5"
android:singleLine="true"
android:textColor="@color/contents_text"
android:textSize="16sp" />
<android.support.v7.widget.AppCompatAutoCompleteTextView
android:id="@+id/act_hidden_danger_sys_name"
android:layout_width="match_parent"
android:layout_height="35dp"
android:layout_below="@+id/act_hidden_danger_pro_name"
android:layout_marginEnd="20dp"
android:layout_marginStart="20dp"
android:layout_marginTop="20dp"
android:background="@mipmap/bg_text_all"
android:completionThreshold="1"
android:hint="系统名称"
android:lines="1"
android:paddingEnd="@dimen/widget_margin_5"
android:paddingStart="@dimen/widget_margin_5"
android:singleLine="true"
android:textColor="@color/contents_text"
android:textSize="16sp" />
<android.support.v7.widget.AppCompatAutoCompleteTextView
android:id="@+id/act_hidden_danger_firm_name"
android:layout_width="match_parent"
android:layout_height="30dp"
android:layout_below="@+id/act_hidden_danger_sys_name"
android:layout_marginEnd="20dp"
android:layout_marginStart="20dp"
android:layout_marginTop="20dp"
android:background="@mipmap/bg_text_all"
android:completionThreshold="1"
android:hint="厂商名称"
android:lines="1"
android:paddingEnd="@dimen/widget_margin_5"
android:paddingStart="@dimen/widget_margin_5"
android:singleLine="true"
android:textColor="@color/contents_text"
android:textSize="14sp" />
<android.support.v7.widget.AppCompatAutoCompleteTextView
android:id="@+id/act_hidden_danger_type"
android:layout_width="match_parent"
android:layout_height="35dp"
android:layout_below="@+id/act_hidden_danger_firm_name"
android:layout_marginEnd="20dp"
android:layout_marginStart="20dp"
android:layout_marginTop="20dp"
android:background="@mipmap/bg_text_all"
android:completionThreshold="1"
android:hint="报警类型"
android:lines="1"
android:paddingEnd="@dimen/widget_margin_5"
android:paddingStart="@dimen/widget_margin_5"
android:singleLine="true"
android:textColor="@color/contents_text"
android:textSize="16sp" />
<LinearLayout
android:id="@+id/act_service"
android:layout_width="match_parent"
android:layout_height="35dp"
android:layout_below="@+id/act_hidden_danger_type"
android:layout_marginEnd="20dp"
android:layout_marginStart="20dp"
android:layout_marginTop="20dp"
android:background="@drawable/shape_dialog_et"
android:orientation="vertical"
android:paddingEnd="@dimen/widget_margin_5"
android:paddingStart="@dimen/widget_margin_5">
<android.support.v7.widget.AppCompatSpinner
android:id="@+id/as_service_type"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:dropDownWidth="wrap_content"
android:paddingEnd="0dp"
android:paddingStart="0dp"
android:spinnerMode="dropdown"
android:textColor="#666666"
android:textSize="12sp" />
</LinearLayout>
<TextView
android:id="@+id/btn_hidden_danger_y"
android:layout_width="100dp"
android:layout_height="30dp"
android:layout_below="@+id/act_service"
android:layout_centerHorizontal="true"
android:layout_marginTop="60dp"
android:background="@drawable/bg_group_delete_shape"
android:gravity="center"
android:text="确 定"
android:textColor="#ffffffff" />
</RelativeLayout>
然后进入咱们的熟悉的Activity内开始装x大业;
2、满足点击文本框就出现下拉菜单
初始化后的 AppCompatAutoCompleteTextView 对象实现 onFocusChangeListener() 接口
在 onFocusChangeListener() 接口内判断点击的是哪个控件,并且这个控件是否真的活得了焦点;
我当时没有用 switch、case 的形式,而是采用了 if、 else 的形式进行的判断,代码如下:
@Override
public void onFocusChange(View v, boolean hasFocus) {
if (TextUtils.isEmpty(etProName.getText().toString())) {
projectId = 0;
}
if (TextUtils.isEmpty(etSysName.getText().toString().trim())) {
systemId = 0;
}
if (TextUtils.isEmpty(etSysName.getText().toString().trim())) {
firmId = 0;
}
if (v.getId() == etProName.getId() && etProName.hasFocus()) {
HttpRequest.getProject(etProName.getText().toString().trim(), HiddenDangerActivity.this);
} else if (v.getId() == etSysName.getId() && etSysName.hasFocus()) {
if (TextUtils.isEmpty(etProName.getText().toString().trim())) {
if (TextUtils.isEmpty(etFirmName.getText().toString().trim()))
firmId = 0;
HttpRequest.getSystems(etSysName.getText().toString().trim(), firmId, 0, HiddenDangerActivity.this);
} else {
HttpRequest.getSystemData(projectId, HiddenDangerActivity.this);
}
} else if (v.getId() == etFirmName.getId() && etFirmName.hasFocus()) {
if (TextUtils.isEmpty(etSysName.getText().toString().trim()))
systemId = 0;
HttpRequest.getFirms(etFirmName.getText().toString().trim(), 0, systemId, HiddenDangerActivity.this);
} else if (v.getId() == etTypeName.getId() && etTypeName.hasFocus()) {
HttpRequest.getDanger(etTypeName.getText().toString().trim(), HiddenDangerActivity.this);
}
}
当点击的控件为当前控件并且该控件获取了焦点,则进行相关的网络请求,此时返回数据展示在文本框的下拉的菜单当中
3、展示下拉菜单
/**
* 展示搜索框下拉列表
*
* @param i 标志位
*/
private void setAdapter(int i) {
if (isShow) {
switch (i) {
case 1:
ArrayAdapter projectAdapter = new ArrayAdapter<>(HiddenDangerActivity.this,
R.layout.item_h_f_iact, projects);
projectAdapter.notifyDataSetChanged();
etProName.setAdapter(projectAdapter);
removeViewFocus(etProName);
etProName.showDropDown();
break;
case 2:
ArrayAdapter systemAdapter = new ArrayAdapter<>(HiddenDangerActivity.this,
R.layout.item_h_f_iact, systems);
systemAdapter.notifyDataSetChanged();
etSysName.setAdapter(systemAdapter);
removeViewFocus(etSysName);
etSysName.showDropDown();
break;
case 3:
ArrayAdapter firmAdapter = new ArrayAdapter<>(HiddenDangerActivity.this,
R.layout.item_h_f_iact, firms);
firmAdapter.notifyDataSetChanged();
etFirmName.setAdapter(firmAdapter);
removeViewFocus(etFirmName);
etFirmName.showDropDown();
break;
case 4:
ArrayAdapter warnTypeAdapter = new ArrayAdapter<>(HiddenDangerActivity.this,
R.layout.item_h_f_iact, dangerTypes);
warnTypeAdapter.notifyDataSetChanged();
etTypeName.setAdapter(warnTypeAdapter);
removeViewFocus(etTypeName);
etTypeName.showDropDown();
break;
default:
}
}
}
这里比较非常重要的代码是: etTypeName.showDropDown()
这句话丢了就会导致,输入两个字(默认情况下)才会出现下拉菜单,或者是你设置了 android:completionThreshold="1"
属性,也得输入一个字之后才会出息下拉菜单的尴尬局面;所以 .showDropDown()
方法绝对不能懒。
对了 removeViewFocus();
方法内代码为:
private void removeViewFocus(AppCompatAutoCompleteTextView view) {
ArrayList<AppCompatAutoCompleteTextView> views = new ArrayList<>();
views.add(etFirmName);
views.add(etSysName);
views.add(etProName);
views.add(etTypeName);
for (int i = 0; i < views.size(); i++) {
if (views.get(i).equals(view)) {
views.remove(i);
}
}
for (AppCompatAutoCompleteTextView v : views) {
v.clearFocus();
v.dismissDropDown();
}
}
这个方法很简单了,就不多解释了(还是有点懒),如果你要是不明白了,留言给我,我告诉你哈(手动滑稽);
4、进行输入文本展示下拉
当用户不喜欢选择item的时候也可以一个字一个字的的进行输入(一般来说客户都很勤快,别我勤快),我们也得提示一下,放置用户打错了啥的,于是也得展现下拉菜单,导致这4个控件得实现 TextWatcher
这个接口;
在接口回调内斜下如下代码:
对了,我是用内部类的形式实现了这个接口哈,毕竟是四个控件,好区分:
class MyTextWatcher implements TextWatcher {
private int tag;
MyTextWatcher(int tag) {
this.tag = tag;
}
@Override
public void afterTextChanged(Editable s) {
if (isShow) {
switch (tag) {
case 1:
if (TextUtils.isEmpty(etProName.getText().toString().trim())) {
projectId = 0;
}
HttpRequest.getProject(s.toString(), HiddenDangerActivity.this);
break;
case 2:
if (projectId == 0) {
HttpRequest.getSystems(s.toString(), firmId, 0, HiddenDangerActivity.this);
} else {
HttpRequest.getSystemData(projectId, HiddenDangerActivity.this);
}
break;
case 3:
if (TextUtils.isEmpty(s.toString())) {
firmId = 0;
}
HttpRequest.getFirms(s.toString(), 0, systemId, HiddenDangerActivity.this);
break;
case 4:
HttpRequest.getDanger(s.toString(), HiddenDangerActivity.this);
break;
}
}
}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
}
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
}
每次输入的时候都会出现下拉菜单,完美(沾沾自喜中)。以后一测试,傻眼了。。。。
这样写产生的结果是:每次从下拉内点击item之后,数据进入文本框触发 TextWatcher 的回调 ,然后你懂得,可能你也有可能不懂,文本框下面出现一个网络请求来的 item 。
这次我终于不懒了,百度、谷歌了好几天,翻来覆去就是那么两篇文章,而且我感觉那群楼主都是相互抄来抄去的,一个能解决问题的都没有。 不过看见一个回答问题的博主,他说可以使用一个 boolean 的标志位,我感觉也可以,但是赎晚辈愚笨,我是不知道加到哪里可以实现。如果哪位兄台可以弄出来,跪求传授修仙打法。楼主跪下了哈:
5、解决小尾巴问题
经过反复沉思,想到了一个比较靠谱的方法:
在 .showDropDown();
方法处加个if 判断,即将网络请求来的 “数据第一个”与“控件内取出的数据”进行对比,如果不同则展示下拉列表,相同则不展示下拉列表;
修改之后的下拉数据展示代码为:
/**
* 展示搜索框下拉列表
*
* @param i 标志位
*/
private void setAdapter(int i) {
if (isShow) {
switch (i) {
case 1:
ArrayAdapter projectAdapter = new ArrayAdapter<>(HiddenDangerActivity.this,
R.layout.item_h_f_iact, projects);
projectAdapter.notifyDataSetChanged();
etProName.setAdapter(projectAdapter);
removeViewFocus(etProName);
if (!etProName.getText().toString().trim().equals(projects.get(0).getProjName())) {
etProName.showDropDown();
}
break;
case 2:
ArrayAdapter systemAdapter = new ArrayAdapter<>(HiddenDangerActivity.this,
R.layout.item_h_f_iact, systems);
systemAdapter.notifyDataSetChanged();
etSysName.setAdapter(systemAdapter);
removeViewFocus(etSysName);
if (!etSysName.getText().toString().trim().equals(systems.get(0).getDevSysName())) {
etSysName.showDropDown();
}
break;
case 3:
ArrayAdapter firmAdapter = new ArrayAdapter<>(HiddenDangerActivity.this,
R.layout.item_h_f_iact, firms);
firmAdapter.notifyDataSetChanged();
etFirmName.setAdapter(firmAdapter);
removeViewFocus(etFirmName);
if (!etFirmName.getText().toString().trim().equals(firms.get(0).getFirmName())) {
etFirmName.showDropDown();
}
break;
case 4:
ArrayAdapter warnTypeAdapter = new ArrayAdapter<>(HiddenDangerActivity.this,
R.layout.item_h_f_iact, dangerTypes);
warnTypeAdapter.notifyDataSetChanged();
etTypeName.setAdapter(warnTypeAdapter);
removeViewFocus(etTypeName);
if (!etTypeName.getText().toString().trim().equals(dangerTypes.get(0).getWarnTyDesc())) {
etTypeName.showDropDown();
}
break;
default:
}
}
}
到此为止,完美的实现了需求,文本框点击数显下拉、输入输入出现下拉的需求。
文笔不好,代码水平不太高。有大佬指点,小弟感激涕零。当然有问题,大家留言区留言,一起探讨哈。关于探讨问题,楼主还是不太懒得哈。