2016-06-11 9 views
0

私はカスタムArrayAdapterを使用するリストビューを持っています。 ListViewのアイテムはRelativeLayoutsです。 「トラック」オブジェクトの「lightsOnThisTrack」リストに格納されている「ライト」ビューは、その後、対応するRelativeLayoutsに追加されます。ListView内のRelativeLayoutにビューを追加すると、繰り返しのアイテムが返されます

ListViewにアイテムを追加すると、以前にrelativeLayoutsに追加されたビューが新しく追加されたアイテムで繰り返されるようになります。一方、この例のように、TextViewの "trackText"は繰り返されていません。私が他の投稿を読んだので、ViewHolderパターンの実装方法に関連する問題だとわかっていますが、どこに問題があるのか​​分かりません。

Example of the ListView

public class TrackListAdapter extends ArrayAdapter<Track> { 

    private static final String TAG = "TrackListAdapter"; 
    private LayoutInflater layoutInflater; 
    public ArrayList<Track> trackArrayList; 
    Context mContext; 
    RelativeLayout relativeLayout; 

    public TrackListAdapter(Context context, ArrayList<Track> trackArrayList) { 
     super(context, 0, trackArrayList); 

     layoutInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); 
     this.mContext = context; 
     this.trackArrayList = trackArrayList; 
    } 

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

     View rowView = convertView; 
     ViewHolder viewHolder; 

     if (rowView == null) { 

      rowView = layoutInflater.inflate(R.layout.track_list_item, null); 

      viewHolder = new ViewHolder(); 
      viewHolder.relativeLayout = (RelativeLayout) rowView.findViewById(R.id.relativeLayout); 
      viewHolder.trackText = new TextView(mContext); 

      viewHolder.trackText.setTextColor(Color.GRAY); 
      viewHolder.trackText.setX(100); 
      viewHolder.trackText.setY(20); 
      viewHolder.trackText.setTextSize(18); 
      viewHolder.relativeLayout.addView(viewHolder.trackText); 


      rowView.setTag(viewHolder); 

     } else { 

      viewHolder = (ViewHolder) rowView.getTag(); 

     } 

     viewHolder.track = trackArrayList.get(position); 

     if (viewHolder.track.getName() == null) 
      viewHolder.trackText.setText(" NUMBER " + position); 
     else 
      viewHolder.trackText.setText(viewHolder.track.getName()); 


     for (int i = 0; i < viewHolder.track.getNumberOfLights(); i++) { 

      Light light = viewHolder.track.lightsOnThisTrackList.get(i); 

      if (light.getParent() != null) { 
       if (!light.getParent().equals(viewHolder.relativeLayout)) { 
        ViewGroup viewGroup = (ViewGroup) light.getParent(); 
        if (viewGroup != null) viewGroup.removeView(light); 
        viewHolder.relativeLayout.addView(light); 
       } 
      } else { 
       viewHolder.relativeLayout.addView(light); 
      } 

     } 
     notifyDataSetInvalidated(); 
     notifyDataSetChanged(); 

     return rowView; 
    } 

    public static class ViewHolder { 
     Track track; 
     TextView trackText; 
     RelativeLayout relativeLayout; 

    } 

    public View getViewByPosition(int pos, ListView listView) { 
     final int firstListItemPosition = listView.getFirstVisiblePosition(); 
     final int lastListItemPosition = firstListItemPosition + listView.getChildCount() - 1; 

     if (pos < firstListItemPosition || pos > lastListItemPosition) { 
      return listView.getAdapter().getView(pos, null, listView); 
     } else { 
      final int childIndex = pos - firstListItemPosition; 
      return listView.getChildAt(childIndex); 
     } 
    } 
} 

答えて

1

問題がViewHolderではありません。問題は、ビューをリサイクルするときに何が起こるか考慮していないことです。

位置0の場合、Relativelayoutに2つのLightを追加するとします。次に、ユーザーがスクロールし、ビューが別の位置にリサイクルされます(位置は10としましょう)。あなたが何かをする前にRelativeLayoutに既にLightが2つあります。

最初にLightをすべて削除するか、そこにあるものを再利用できるようにする必要があります(作成する行の数が少ない場合には削除する必要があります)Lightすでに存在しているよりも)。

ビューがリサイクルされるたびにTextViewを作成していないため、TextViewは繰り返されません。新しい行が膨らんでいるときにのみ作成します。


いくつかの他の提案:

  • getView()の内側notifyDataSetInvalidated()notifyDataSetChanged()をコールする理由はありません。
  • データモデルにView(この場合はLight秒)の保留リストを使用することをお勧めします。あなたはデータとプレゼンテーションの間に明確な隔たりがなく、私はそれがあなたのコードだけを複雑にすると思います。トラックに必要なライトの数を保存し、実際にViewを処理するほうが簡単です。
  • getView()の内部にViewを作成、追加、削除することも避けようとしています。たとえば、トラックが持つことができるライトの数が限られていることがわかっている場合(5つあると仮定します)、行レイアウトの多くの対応するビューを既に持ち、可視性を適切に切り替えるだけで十分です。または、その番号に描画する方法を知っているカスタムViewを作成して、getView()の番号を変更するだけです。
+0

RelativeLayoutで以前のビューを削除していただきありがとうございました。また、 'notifyDataSetInvalidated()'と 'notifyDataSetChanged()'は、あなたが想像しているように、データセットを変更しているコード部分に配置するだけで、不要なgetView()内であることが判明しました。 – gotramaval

+0

最後に、これらのビューをlistView内で使用しています。ビューのスクロールをコーディングせずにスクロールできるようにしたいのです。あなたはそれをどのように提案しますか?(私は実際には 'Track'にある' Light'の最大数を予測することはできませんし、トラック上でドラッグすることができるので、特定の場所はありません) – gotramaval

+0

@gotramaval私はドンあなたのユースケースに最適なものは分かっていませんが、ListViewはあなたがそれらのライトをドラッグ可能にすることを計画するならあなたの人生を非常に困難にすると思います。 ListViewは、タッチ操作のコントロールについてかなり重いです。代わりに 'RecyclerView'を使用するように切り替えることができれば、それは良いでしょう。 – Karakuri

関連する問題