2016-12-21 6 views
0

カスタムアダプターを持つカスタムオブジェクトのListViewがあります。リストの個々のアイテムをクリックすると、そのアイテムを更新した結果の新しいアクティビティが開始され、ListViewアイテムの右側に緑色のティックイメージが表示されます。TextViewです。ちょうどrow.setCompoundDrawablesWithIntrinsicBounds(0, 0, R.drawable.tick_green, 0) を使用します。下にスクロールすると、同じドロアブルを持つ別の行が表示されます。前後にスクロールするだけで、このドロアブルがランダムに異なる行に設定されます。ほとんどの答えは、ビューがリサイクルされているためですが、他のアクティビティが結果を返すときに、表示されているかどうかにかかわらず、1つの行を変更する方法は何ですか?リストビューとアクティビティからListViewまたはRecycleViewで1つのアイテムのみを変更する

コード - 提案hereとして

private ItemAdapter adapter; 
private ArrayList<Item> labels; 
private ArrayList<Item> updatedItems; 
private TextView label; 
@Override 
protected void onCreate(Bundle savedInstanceState) { 
    // initializations 

    updatedItems = new ArrayList<>(); 
    adapter = new ItemAdapter(getBaseContext(), R.layout.label_list_item, labels); 
    listView.setAdapter(adapter); 
    listView.setOnItemClickListener(new AdapterView.OnItemClickListener() { 
        @Override 
        public void onItemClick(AdapterView<?> parent, View v, int position, long id) { 
         label = (TextView) listView.getChildAt(position - listView.getFirstVisiblePosition()).findViewById(R.id.text1); 
         Item item = adapter.getItem(position); 
         Intent myIntent = new Intent(ProviderPutawayActivity.this, PutawayScanLocationActivity.class); 
         myIntent.putExtra("ITEM", item); 
         ProviderPutawayActivity.this.startActivityForResult(myIntent, 1); 
        } 
       }); 
} 
@Override 
protected void onActivityResult(int requestCode, int resultCode, Intent data) { 
    if(requestCode == 1) { 
     Item item = (Item) data.getSerializableExtra("ITEM"); 
     label.setCompoundDrawablesWithIntrinsicBounds(0, 0, R.drawable.tick_green, 0); 
} 

v.findViewById(r.id.text1)(TextView) listView.getChildAt(position - listView.getFirstVisiblePosition()).findViewById(R.id.text1)両方が同じ問題を抱えています。

ItemAdapterクラス -

public class ItemAdapter extends ArrayAdapter<Item> { 
    private View v; 

    public ItemAdapter(Context context, int resource, List<Item> items) { 
     super(context, resource, items); 
    } 

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

     v = convertView; 
     TextView label; 

     if(v == null) { 
      LayoutInflater vi; 
      vi = LayoutInflater.from(getContext()); 
      v = vi.inflate(R.layout.label_list_item, null); 
     } 

     Item item = getItem(position); 
     if(item != null) { 
      label = (TextView)v.findViewById(R.id.text1); 
      if(label != null) label.setText(String.valueOf(item.getLabel())); 
     } 
     return v; 
    } 
} 

は、どのように私は私だけクリックされた行を更新してくださいますか?

+0

問題を解決するには、ビューホルダーパターンを実装する必要があります。あなたはそれについて学ぶことができるチュートリアルがたくさんあります。 – Gautam

+0

'ListView'の代わりに' RecyclerView'を使って同じことをしようとしたときに使いましたが、1行だけをクリックした後に2つの別々の行が描画可能を示しました。 –

答えて

0

、あなたがしなければならない答え上記の好きなようにlistviewまたはrecyclerviewの項目行を更新する必要があるときはいつでも、notifiyDataSetchange。だからここに行く

まず、アイテムモデルクラスでsetterとgetterメソッドを作成して、リストビュー行を更新する必要があります。その後setOnItemClickListener中にあなたの活動に続いて、以下の

listView.setOnItemClickListener(new AdapterView.OnItemClickListener() { 
       @Override 
       public void onItemClick(AdapterView<?> parent, View v, int position, long id) { 

        Item item = adapter.getItem(position); 
        item.setIsSelected(true); 
        Intent myIntent = new Intent(ProviderPutawayActivity.this, PutawayScanLocationActivity.class); 
        myIntent.putExtra("ITEM", item); 
        ProviderPutawayActivity.this.startActivityForResult(myIntent, 1); 
       } 
      }); 

のようなあなたの項目のモデルクラスを更新getViewの中にあなたItemAdapterクラスに続いて

public class Item { 
    private boolean mIsSelected; 

    public void setIsSelected(boolean isSelected) { 
    mIsSelected = isSelected; 
    } 

    public boolean isSelected() { 
    return mIsSelected; 
    } 
} 

以下()メソッドのように、この

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

     v = convertView; 
     TextView label; 

    if(v == null) { 
     LayoutInflater vi; 
     vi = LayoutInflater.from(getContext()); 
     v = vi.inflate(R.layout.label_list_item, null); 
     } 

    Item item = getItem(position); 
    if(item != null) { 
     label = (TextView)v.findViewById(R.id.text1); 
     label.setText(String.valueOf(item.getLabel())); 
     if (item.isSelected) { 
     label.setCompoundDrawablesWithIntrinsicBounds(0, 0, R.drawable.tick_green, 0); 
     } else { // by default it will be false until you select an item here 
     label.setCompoundDrawablesWithIntrinsicBounds(0, 0, 0, 0); 
     } 

    } 
    return v; 
    } 

好きですかstartActivityResult内でこのようにnotifyDataSetChangedを使用してリストを更新します

  @Override 
     protected void onActivityResult(int requestCode, in resultCode, Intent data) { 
     if(requestCode == 1) { 
     adapter.notifyDataSetChanged(); 
     } 

これで出力が得られます

+0

詳細な回答ありがとう! notifyDataSetChanged()が動作するかどうかは、他のアクティビティにオブジェクトの値を渡していると思っていて、アクティビティ結果のインテントから取得したときに同じオブジェクトか新しいオブジェクトかどうかわからなかったのですか? –

+0

@AnthonyStonemこれは実際にあなたのために働いていますか?私は、 'Serializable'エクストラは、それらを抽出するときに同じオブジェクトインスタンスを生成するとは考えていません。つまり、まだアダプタのデータセットで使用されているインスタンスを変更する必要があります。 – Karakuri

+0

その場合はうまくいかないが、スクロールしても正しい行が更新され、そのまま残る –

1

問題は決してです。ビューをリサイクルするときは、ドロブルが設定されていません。これは、ViewHolderパターンを行うことは何もないので、アイテムを更新する方法と関係しています。

int check = item.isChecked() ? R.drawable.tick_green : 0; 
label.setCompountDrawablesWithIntrinsicBounds(0, 0, check, 0); 

これは、行ビューにアイテムデータをバインドするための正しい方法は次のとおりです。あなたのgetView()方法は、このようなものを持っている必要があります。

ここでは、クリックした行の一部のビューをアクティビティのメンバーフィールドに保存し、onActivityResult()になると一度更新します。問題は、スクロールしてスクロールして戻すと、実際にチェックされている項目を特定することができず、アダプターが正しい状態を表示する方法がないことです。

何が実際のデータソース(この場合はItem、またはItem Sを含む構造)を変更した後、アダプタにnotifyDatasetChanged()を呼び出しているやるべき。これにより、ListViewは行を再構築するため、適切なバインディングロジックが正しい状態を表示するようになります。余談として


RecyclerViewへの切り替えは(もう少し複雑なコストで)多くの利点を持っています。 1つのことは、RecyclerView.Adapterを使用すると、1つのアイテムが変更されたことを通知できるため、1つの行だけが再構築されます。これはListAdapterでは不可能です。別の場合は、視聴者を強制的に使用するようになりますが、これはいずれにしてもパフォーマンスが向上します。

+0

ListViewに固執すると、[The World of ListView](https://www.youtube.com/watch?v=wDBM6wVEO70)をご覧ください。 – Karakuri

+0

ありがとうございます。代わりにRecyclerViewを使用してみます –

0

まず、あなたがあなたの項目に緑色のチェックマーク画像を表す変数(例:boolean isSelected)保存する必要があり、リストビュー

0

を、状態をチェックし、onActivityResultで その後に、isSelectedを更新し、リロード私がいました」このビューリサイクラーのメカニズムにも "犠牲者"!私は下にスクロールするとき

のあなたの問題は、しかし、私は同じ描画可能で、別の行を参照してください。前後にスクロールするだけで、このドロアブルがランダムに異なる行に設定されます。

は、基本的には、もはや表示されている/再利用viewItemsをリサイクルするためのアダプタ時制を持つため

ListViewコントロールです。

detailed-explanationにこの回答を確認してください。あなたのケースでは

、ちょうど(それは、アダプターのビューを設定することになると)あなたの場合のために、他のを置く:

if(label != null) 
    label.setText(String.valueOf(item.getLabel())); 
else 
    label.setText("Default text"); 

・ホープ、このことができます〜

+0

説明は本当にです良い、ありがとう! –

関連する問題