這幾天在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;
}
}
}
<?xml version="1.0" encoding="utf-8"?>
<?xml version="1.0" encoding="utf-8"?>