这几天在ListView中需要添加一个EditText,监视输入内容并保存,再EditText输入完成并按回车的时候,新增一个EditText在ListView中。
需求很简单,但是遇到了很多意想不到的问题。
问题 1:保存item中EditText中的数据。
解决方法:这需要用到Map进行保存,如果用arraylist的话,在同一个item中的EditText修改数据,导致重复添加。需要在其上注册OnTextChangedListener监听事件,并在afterTextChanged()中写入存储操作。
问题 2:EditText存在焦点问题,由于复用的存在,会出现焦点落在多个EditText上或者复用后EditText中的Text也被复用的情况。
解决方法:继承于TextWatcher和OnFocusChangeListener,在EditText上分别注册上OnFocusChangeListener和
OnTextChangedListener监听,通过OnFocusChangeListener监听事件,动态的改变TextWatcher,
使它始终只作用在真正获得焦点的EditText上。
问题 3:在输入时,软键盘的问题
下面直接贴上代码:
public class AddAdapter extends BaseAdapter {
private Context context;
//需要增加的条目用一个Map存储
private Map
edItem;
//记录增加的条目数,作为下标给deItem赋值,可以不要,赋值另想办法
private int edindex = 0;
private Handler handler;
// 这是我继承写的两个监听,没用匿名内部类,首先是为了方便对position这个变量进行操作,再者
// Adapter中我只分别实例化了一个监听对象,这样对内存开支应该会小些,好吧,我是对Java的垃圾回收机制信不过。
private MyFoucus myFoucus;
private MyWatch myWatch;
//需要存储EditText内容的Map
public HashMap
inputContainer;
public HashMap
getInputContainer() {
return inputContainer;
}
public AddAdapter(Context context, Handler handler) {
edItem = new HashMap<>();
// 默认只加载一个Item
edItem.put(edindex, "edindex");
this.context = context;
this.handler = handler;
inputContainer = new HashMap
();
myFoucus = new MyFoucus();
myWatch = new MyWatch();
}
public class ViewHolder {
public EditText editText;
public ViewHolder(View convertView) {
editText = (EditText) convertView.findViewById(R.id.editNumber);
}
}
@Override
public int getCount() {
return edItem.size();
}
@Override
public Object getItem(int position) {
return edItem.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(final int position, View convertView, ViewGroup viewGroup) {
final ViewHolder holder;
if (convertView == null) {
convertView = View.inflate(context, R.layout.item_addadapterview, null);
holder = new ViewHolder(convertView);
// 注册上自己写的焦点监听
holder.editText.setOnFocusChangeListener(myFoucus);
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
holder.editText.setTag(position);
View currentFocus = ((Activity) context).getCurrentFocus();
if (currentFocus != null) {
currentFocus.clearFocus();
}
// 为了实现最小的内存开销,复用两个不同的监听对象,通过每次点击的事件来修正mywatch中的position;
// 使用remove和add来区别开复用修正和手动添加;之所以费劲的加个remove又加个add也是为了能尽量减少些
// 思考量,剔除修正EditText时的TextChange监听事件,整个世界都清净了。。。
holder.editText.removeTextChangedListener(myWatch);
if (inputContainer.containsKey(position)) {
holder.editText.setText(inputContainer.get(position).toString());
} else {
holder.editText.setText("");
}
holder.editText.addTextChangedListener(myWatch);
//监听EditText的回车键
holder.editText.setOnEditorActionListener(new TextView.OnEditorActionListener() {
@Override
public boolean onEditorAction(TextView textView, int i, KeyEvent keyEvent) {
if ((edItem.size() == inputContainer.size())) {
edindex += 1;
// 添加一项控件
edItem.put(edindex, "edindex");
notifyDataSetChanged();
//给Activity发消息,让ListView在notifyDataSetChanged之后,回到底部而不是顶部
handler.sendEmptyMessage(1);
}
return false;
}
});
return convertView;
}
class MyFoucus implements View.OnFocusChangeListener {
// 当获取焦点时修正myWatch中的position值,这是最重要的一步!
@Override
public void onFocusChange(View v, boolean hasFocus) {
if (hasFocus) {
int position = (int) v.getTag();
myWatch.position = position;
}
}
}
class MyWatch implements TextWatcher {
// 不得不吐槽一下这里,java的内部类机制怎么就和我想的不一样呢,外部依然能很轻松的访问这个“私有化的”position,我是不是该去看看《think in java》了。
private int position;
@Override
public void afterTextChanged(Editable s) {
Log.e("11111", "afterTextChanged");
//把数据存储到Map中
inputContainer.put(position, s.toString());
}
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
Log.e("11111", "beforeTextChanged");
}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
Log.e("11111", "onTextChanged");
}
}
}
public class AddadapterActivity extends AppCompatActivity implements View.OnClickListener {
private TextView textVie;
private ListView listview;
private AddAdapter myadapter;
private Map
text; private int edindex = 0; private Handler handler = new Handler() { @Override public void handleMessage(Message msg) { super.handleMessage(msg); switch (msg.what) { case 1: //回到底部 Log.e("11111", "case 1"); listview.setSelection(myadapter.getCount() - 1); break; } } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_addadaptermain); initView(); initData(); } private void initView() { textVie = (TextView) findViewById(R.id.textVie); listview = (ListView) findViewById(R.id.listview); textVie.setOnClickListener(this); } private void initData() { text = new HashMap<>(); text.put(edindex, "edindex"); myadapter = new AddAdapter(AddadapterActivity.this, handler); listview.setAdapter(myadapter); //对键盘滑动进行处理 listview.setOnScrollListener(new AbsListView.OnScrollListener() { @Override public void onScrollStateChanged(AbsListView absListView, int scrollState) { switch (scrollState) { //当停止滚动时 case AbsListView.OnScrollListener.SCROLL_STATE_IDLE: break; //滚动时 case AbsListView.OnScrollListener.SCROLL_STATE_TOUCH_SCROLL: //没错,下面这一坨就是隐藏软键盘的代码 ((InputMethodManager) getSystemService(INPUT_METHOD_SERVICE)).hideSoftInputFromWindow(AddadapterActivity.this.getCurrentFocus().getWindowToken(), InputMethodManager.HIDE_NOT_ALWAYS); break; //手指抬起,但是屏幕还在滚动状态 case AbsListView.OnScrollListener.SCROLL_STATE_FLING: break; } } @Override public void onScroll(AbsListView absListView, int firstVisibleItem, int visibleItemCount, int totalItemCount) { } }); } @Override public void onClick(View view) { switch (view.getId()) { case R.id.textVie: Log.e("11111", "size = " + myadapter.getInputContainer().size()); Log.e("11111", "count = " + myadapter.getCount()); for (int i = 0; i < myadapter.getInputContainer().size(); i++) { Log.e("11111", "getInputContainer = " + myadapter.getInputContainer().get(i) + "[" + i + "]"); } for (int i = 0; i < myadapter.getCount(); i++) { Log.e("11111", "Item = " + myadapter.getItem(i) + "[" + i + "]"); } break; } } }