2012-01-07 90 views
12

我有EditText在其中的列表項,我不知道會有多少項目。 我在EditText中輸入一些文本時出現問題,然後向下滾動ListView,再次向上滾動後,我的第一個EditText中沒有文本,或者ListView中的其他EditText有一些文本。EditText在滾動列表視圖中丟失內容

我已經嘗試了TextWatcher,並將數據保存到數組,但問題是ListView中返回的視圖位置總是正確的,所以我從數組中丟失了一些數據。 -.-

如何在ListView中檢測正確的視圖位置?

例如:

如果我有ListView中10個項目,其中只有5當前可見。 適配器返回從0到4的位置......多數民衆贊成。 當我向下滾動項目6的位置是0 ... wtf?和我失去了陣列上的位置0的數據:)

Im使用ArrayAdapter。

請幫忙。

下面是一些代碼:

public View getView(int position, View convertView, ViewGroup parent) { 

    tmp_position = position; 

    if (convertView == null) { 

     holder = new ViewHolder(); 

     LayoutInflater vi = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE); 
     convertView = vi.inflate(R.layout.element_in_game, null); 

     holder.scoreToUpdate = (EditText) convertView 
       .findViewById(R.id.elementUpdateScore); 

     holder.scoreToUpdate.addTextChangedListener(new TextWatcher() { 

      @Override 
      public void onTextChanged(CharSequence s, int start, 
        int before, int count) { 
       scoresToUpdate[tmp_position] = s.toString(); 
      } 

      @Override 
      public void beforeTextChanged(CharSequence s, int start, 
        int count, int after) { 

      } 

      @Override 
      public void afterTextChanged(Editable s) { 

      } 
     }); 

     initScoresToUpdateEditTexts(holder.scoreToUpdate, hint); 

     convertView.setTag(holder); 

    } else { 

     holder = (ViewHolder) convertView.getTag(); 

     holder.scoreToUpdate.setText(scoresToUpdate[tmp_position]); 

    } 

    return convertView; 
} 

回答

14

你應該嘗試在如下這樣:

if (convertView == null) { 

     holder = new ViewHolder(); 

     LayoutInflater vi = (LayoutInflater)  
     getSystemService(Context.LAYOUT_INFLATER_SERVICE); 
     convertView = vi.inflate(R.layout.element_in_game, null); 

     holder.scoreToUpdate = (EditText) convertView 
       .findViewById(R.id.elementUpdateScore); 


     convertView.setTag(holder); 

    } else { 

     holder = (ViewHolder) convertView.getTag(); 

    } 
    //binding data from array list 
    holder.scoreToUpdate.setText(scoresToUpdate[position]); 
    holder.scoreToUpdate.addTextChangedListener(new TextWatcher() { 

      @Override 
      public void onTextChanged(CharSequence s, int start, 
        int before, int count) { 
       //setting data to array, when changed 
       scoresToUpdate[position] = s.toString(); 
      } 

      @Override 
      public void beforeTextChanged(CharSequence s, int start, 
        int count, int after) { 

      } 

      @Override 
      public void afterTextChanged(Editable s) { 

      } 
     }); 

    return convertView; 
} 

說明:ListView控件的 回收行爲,實際上消除其行項目的所有數據綁定,當外出的視野。因此,無論您需要什麼方向再次綁定數據,每一個新的行都可以進入視野。 此外,當EditText文本更改時,您還必須在某些數據結構中保留值,因此稍後再次進行行數據綁定時,您可以提取位置數據。 你可以使用數組ArrayList來保存edittext數據,也可以用來綁定數據。

Recyclerview Adapter中類似的行爲用法,您需要知道有關適配器行數據的數據綁定的邏輯。

+8

不適合我嗎? – DPM 2013-11-29 12:35:56

+0

Anand,你好,我現在有同樣的問題,我試着在你的代碼的解決方案,但顯然我不能得到它的工作,我如何更新arraylist取決於編輯文本 – 2015-07-09 05:47:40

+0

@PankajNimgade,具體數據對我來說作品:http://stackoverflow.com/a/21404201/2914140。裏面'holder.scoreToUpdate.setOnFocusChangeListener(...'寫:if(!hasFocus){scoresToUpdate [position] = holder.scoreToUpdate.getText()。toString();} – CoolMind 2016-08-30 21:15:53

5

如果你只擁有約10行,不與理會ListView。只需將它們放在垂直的LinearLayout中,並將其包裝在ScrollView中,它將爲您節省一些頭痛。

如果你打算有幾十或幾百行,我建議你在ListView行中提出比EditText更好的UX範例。

所有的說法,感覺就像你沒有正確處理你的行回收,或者不知道行被回收。如果您的ListAdapter中有10件商品,並且您只有空間可以顯示5行EditText小部件,則當用戶滾動到底部時,您不應該使用10 EditText小部件。您應該用5-7 - 在屏幕上顯示結果,當用戶下一次滾動時可能需要另外一兩個用於回收。

This free excerpt from one of my books通過創建ArrayAdapter的自定義子類並獲得回收工作的過程。它還涵蓋了一個交互式行,使用RatingBar作爲用戶輸入。這比EditText容易得多,因爲所有你必須擔心的是點擊事件。歡迎您嘗試使用EditText小部件和TextWatcher聽衆擴展該技術,但我不是粉絲。在運行時

+0

tnx快速回答!我會看看你的書...希望我會拿出一些東西:) – Veljko 2012-01-07 21:33:54

+0

我試過使用你的概念,但同樣的事情發生。 – Veljko 2012-01-11 12:17:28

0

更好的方法是創建的EditText並設置其getView()方法id位置參數

。所以現在當添加文本,將其存儲在矢量變量(類

變量),以及基於位置的變量的getView方法設置文本(你可以

開始使用向量的elementAt()方法)相應的EditText。

並且不要忘記將此EditText添加到充氣的視圖中。

+0

我試過早些時候......但問題是,getView只返回可見項目的範圍內的位置。我想我在我的問題中提到它。 – Veljko 2012-01-17 09:34:59

+0

@Veljko ..所以最新的問題在那。您只想顯示可見EditText文本的任何方式。這就是爲什麼我告訴你維護一個存儲文本的向量。或者哈希表是一個更好的選擇,因爲您可以通過將位置轉換爲字符串來將位置作爲鍵。 – ngesh 2012-01-17 09:49:18

1

從你的代碼的簡短摘要看來,你似乎對付回收站。當您在列表視圖中從位置1滾動到位置20時,它不會創建列表視圖項目視圖的20個不同實例。相反,它有7個或8個當滾動屏幕時,它被添加到回收站,然後作爲convertView參數發送到getView方法,因此您可以使用新數據重新填充它,而不是浪費地創建新視圖。

傳統上使用ViewHolder模式來保存列表項目(textview,imageview等)的子視圖,而不是數據(設置並從持有者內部獲得分數) - 發生了什麼是您將值設置爲零在位置零時,向下滾動到5項屏幕上的第6個項目,第0個項目被重新用於位置6,並且它從附加到該列表項目的持有者(在這種情況下爲0)中抽取現有值

簡單的答案:不要將位置特定的數據存儲在持有者中!將其存儲在某個外部數組或散列表中。

0

本準則將幫助您

private class EfficientAdapter extends BaseAdapter { 
     private LayoutInflater mInflater; 
     private String[] attitude_names; 
     public String[] attitude_values; 
     private String name; 
public static HashMap<Integer,String> myList=new HashMap<Integer,String>(); 

     public EfficientAdapter(Context context) { 
      mInflater = LayoutInflater.from(context); 
      attitude_names = context.getResources().getStringArray(R.array.COMP_ATTITUDE_NAME); 
      attitude_values = new String[attitude_names.length]; 
     } 
// initialize myList 
for(int i=0;i<attitude_names.length;i++) 
{ 
    myList.put(i,""); 
} 


     public Object getItem(int position) { 
      return position; 
     } 

     public long getItemId(int position) { 
      return position; 
     } 

     public View getView(int position, View convertView, ViewGroup parent) { 
      final ViewHolder holder; 

      if (convertView == null) { 
       convertView = mInflater.inflate(R.layout.addcomp_attitude_row, null); 

       holder = new ViewHolder(); 
       holder.Attitude_Name = (TextView) convertView.findViewById(R.id.addcomp_att_name); 
       holder.Attitude_Value = (EditText) convertView.findViewById(R.id.addcomp_att_value); 
       holder.Attitude_Value.addTextChangedListener(new TextWatcher() 
        { 
         public void afterTextChanged(Editable edt) 
         { 
          myList.put(pos,s.toString.trim()); 
          attitude_values[holder.ref] = edt.toString(); 
         } 

         public void beforeTextChanged(CharSequence arg0, int arg1, int arg2, int arg3) {} 

         public void onTextChanged(CharSequence arg0, int arg1, int arg2, int arg3) { 
          //attitude_values[ref] = Attitude_Value.getText().toString(); 
         } 
        }); 

       convertView.setTag(holder); 
      } else { 
       holder = (ViewHolder) convertView.getTag(); 
      } 


      holder.ref=position; 
      holder.Attitude_Name.setText(attitude_names[position]); 
      holder.Attitude_Value.setHint(attitude_names[position]); 
      holder.Attitude_Value.setText(myList.get(position)); 




      return convertView; 
     } 

     class ViewHolder { 
      TextView Attitude_Name; 
      EditText Attitude_Value; 
      int ref; 



     } 

     @Override 
     public int getCount() { 
      return attitude_names.length; 
     } 
    } 

在這裏,我已經包括一個HashMap對象,這將繼續對什麼的EditText包含value.And當您滾動列表視圖的眼睛,它會再次呈現通過調用其getView方法。

在這段代碼中,當你第一次加載列表視圖時,所有的edittext都將沒有文本。只要你輸入了一些文本,它會在myList中註明。所以當你再次渲染列表時,你的文本將被阻止。

0

搭乘convertView == null支票,這是其他聲明。你的表現會變差,但它會禁用回收。

2

我剛剛在尋找一個類似的解決方案,發現使用textChangeListener不是最好的方法。我在這裏回答了相關的問題:

https://stackoverflow.com/a/13312282/1812518

這是我的第一篇文章,但我希望它是足夠的幫助。

12

您可以改用setOnFocusChangeListener。 在我的情況,我有擴展列表,它似乎不錯:) 這樣的:

holder.count.setOnFocusChangeListener(new View.OnFocusChangeListener() { 
     public void onFocusChange(View v, boolean hasFocus) { 
      if (!hasFocus) { 
       EditText et =(EditText)v.findViewById(R.id.txtCount); 
       myList.get(parentPos).put(childPos, 
         et.getText().toString().trim()); 
      } 
     } 
    }); 
+1

完美。我嘗試了數以千計的SO代碼片段,只有你的工作似乎。Thanx再次 – 2014-11-12 16:35:27

+0

請定義什麼是您的代碼中的childPos和parentPos我與同一問題卡住 – jyomin 2015-03-19 06:17:45

+0

歡迎@SyamantakBasu和rahul, – amin10043 2015-08-29 08:53:01

4

我有我解決了相關的問題。我的ListView的每一行都有不同的視圖(它包含不同的控件,EditView,ImageView,TextView)。即使控件從屏幕滾動出來,我也希望在這些控件中輸入或選擇的數據保持不變。我使用的解決方案是實現ArrayAdapter下面這個方法:

public int getViewTypeCount() { 
    return getCount(); 
} 

public int getItemViewType(int position) { 
    return position; 
} 

這將確保當getView()被調用它通過一個從getView()在第一次調用返回相同View實例。

public View getView(int position, View convertView, ViewGroup parent) { 

    if (convertView != null) 
    return convertView; 
    else 
    // create new view 
} 
+1

這是一個非常糟糕的黑客攻擊。通過將** getViewTypeCount **設置爲** getCount **,您可以爲ListView中的每個項目創建一個新行,並且不會發生recylcing,如果您有很多項目或舊手機,則可能會出現問題。 – Marko 2015-12-07 12:17:48

0

我的適配器擴展了BaseAdapter和我有類似的情況作爲bickster曾在那裏我有這他們有不同的看法列表視圖(動態的形式類似的情況),並留存數據需要。我的列表視圖是不會太大,所以回收的觀點是不會成爲一個大的資源消耗在我的情況,因此一個簡單的

if (convertView != null) return convertView;

getView開始是足以讓我。不知道它有多高效的解決方案,但這正是我所尋找的。

重要編輯:這是確定當且僅當你有很少的行(無滾動),否則該黑客是可怕的一個。您應該手動處理數據

相關問題