2016-04-20 6 views
1

Ich muß in einem RecyclerView und die Daten, die eine Art von Besuchern Protokollen anzeigen zu Anzeige von einem von Datetime (Spalte enter_time, UNIX-Wert) -ordered DESCSQLiteDatabase kommt. Ich habe bereits eine einfache CursorAdapter implementiert und kann Daten in der RecyclerView anzeigen.Mehrere Zeilenlayouts in Cursor basierend auf nächstem Punkt

Im nächsten Schritt verschiedene Ansichten zu machen, so dass der erste Eintrag eines jeden Tages ein Layout mit einem zusätzlichen Header mit dem Datum verwendet:

enter image description here

Im Innern der CursorAdapter implementiert I getItemViewType(int) Methode, wo ich brauche füge meine Logik hinzu und wähle den richtigen Gegenstandstyp aus.

Die Logik ist einfach:

  • Wenn nächster Punkt in Cursor selben Tag wie die aktuelle hat, dann wählen Sie das einfache Layout
  • Wenn nächster Punkt in Cursor anderes Datum als das aktuelle hat, wählen Sie dann die Layout mit Kopf

Hier kommt das Problem: ich muß nächstes Element in den Cursor der CursorAdapter überprüfen, aber die Das angezeigte Ergebnis ist falsch und ich kann nicht sagen warum. Der Code sieht für mich korrekt aus, aber das Layout wird nach dem Zufallsprinzip zugewiesen.

public static class VisitorsRecyclerAdapter extends RecyclerView.Adapter<VisitorsRecyclerAdapter.VisitorViewHolder> { 

    CustomCursorAdapter mCursorAdapter; 
    Context mContext; 
    private static final int NO_HEADER_LAYOUT = 1; 
    private static final int HEADER_LAYOUT = 0; 

    public VisitorsRecyclerAdapter(Context context, Cursor c) { 
     mContext = context; 
     mCursorAdapter = new CustomCursorAdapter(mContext, c, 0); 
    } 

    public static class VisitorViewHolder extends RecyclerView.ViewHolder { 

     public TextView textName; 
     public TextView textCats; 

     public VisitorViewHolder(View v) { 
      super(v); 
      textName = (TextView) v.findViewById(R.id.item_visitor_name); 
      textCats = (TextView) v.findViewById(R.id.item_visitor_category); 
     } 
    } 

    public static class HeaderViewHolder extends RecyclerView.ViewHolder { 

     public TextView textName; 
     public TextView textCats; 

     public HeaderViewHolder(View v) { 
      super(v); 
      textName = (TextView) v.findViewById(R.id.item_visitor_name); 
      textCats = (TextView) v.findViewById(R.id.item_visitor_category); 
     } 
    } 

    private class CustomCursorAdapter extends CursorAdapter { 


     public CustomCursorAdapter(Context context, Cursor c, int flags) { 
      super(context, c, flags); 
     } 

     @Override 
     public int getViewTypeCount() { 
      return 2; 
     } 

     @Override 
     public int getItemViewType(int position) { 

      Cursor cursor = (Cursor) mCursorAdapter.getItem(position); 
      cursor.moveToNext(); 

      // date of current item 
      Date date0 = new Date(Long.parseLong(cursor.getString(cursor.getColumnIndex(DatabaseConst.VisitorEntry.COLUMN_NAME_ENTER))) * 1000); 

      if(position == -1) return HEADER_LAYOUT; 
      cursor = (Cursor) mCursorAdapter.getItem(position - 1); 
      cursor.moveToNext(); 

      // date of item that temporary comes after 
      Date date1 = new Date(Long.parseLong(cursor.getString(cursor.getColumnIndex(DatabaseConst.VisitorEntry.COLUMN_NAME_ENTER))) * 1000); 

      SimpleDateFormat format = new SimpleDateFormat("ddMMyyyy", Locale.ENGLISH); 

      return format.format(date0).equals(format.format(date1)) ? NO_HEADER_LAYOUT : HEADER_LAYOUT; 
     } 

     @Override 
     public View newView(final Context context, Cursor cursor, ViewGroup parent) { 
      View v = null; 
      int position = cursor.getPosition(); 
      int type = getItemViewType(position); 
      RecyclerView.ViewHolder viewHolder = null; 

      switch (type) { 
       case HEADER_LAYOUT: 
        v = LayoutInflater.from(parent.getContext()) 
          .inflate(R.layout.item_day, parent, false); 
        viewHolder = new HeaderViewHolder(v); 
        break; 
       case NO_HEADER_LAYOUT: 
        v = LayoutInflater.from(parent.getContext()) 
          .inflate(R.layout.item_visitor, parent, false); 
        viewHolder = new VisitorViewHolder(v); 
        break; 
      } 
      assert v != null; 
      v.setTag(viewHolder); 
      return v; 
     } 

     @Override 
     public void bindView(View view, Context context, Cursor cursor) { 
      final int viewType = getItemViewType(cursor.getPosition()); 

      switch (viewType) { 
       case HEADER_LAYOUT: 
        HeaderViewHolder holder = (HeaderViewHolder) view.getTag(); 
        holder.textName.setText(DateFormat.getDateTimeInstance().format(new Date(Long.parseLong(cursor.getString(cursor.getColumnIndex(DatabaseConst.VisitorEntry.COLUMN_NAME_ENTER))) * 1000))); 
        holder.textCats.setText(cursor.getString(cursor.getColumnIndex(DatabaseConst.VisitorEntry.COLUMN_NAME_FIRST_NAME))); 
        break; 
       case NO_HEADER_LAYOUT: 
        VisitorViewHolder holder0 = (VisitorViewHolder) view.getTag(); 
        holder0.textName.setText(DateFormat.getDateTimeInstance().format(new Date(Long.parseLong(cursor.getString(cursor.getColumnIndex(DatabaseConst.VisitorEntry.COLUMN_NAME_ENTER))) * 1000))); 
        holder0.textCats.setText(cursor.getString(cursor.getColumnIndex(DatabaseConst.VisitorEntry.COLUMN_NAME_FIRST_NAME))); 
        break; 
      } 

     } 

    } 

    @Override 
    public int getItemCount() { 
     if(mCursorAdapter == null) return 0; 

     return mCursorAdapter.getCount(); 
    } 

    @Override 
    public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { 
     mCursorAdapter.getCursor().moveToPosition(position); 
     mCursorAdapter.bindView(holder.itemView, mContext, mCursorAdapter.getCursor()); 
    } 

    @Override 
    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { 
     View v = mCursorAdapter.newView(mContext, mCursorAdapter.getCursor(), parent); 
     RecyclerView.ViewHolder viewHolder = null; 
     switch (viewType){ 
      case HEADER_LAYOUT: 
       viewHolder = new HeaderViewHolder(v); 
       break; 
      case NO_HEADER_LAYOUT: 
       viewHolder = new VisitorViewHolder(v); 
       break; 
     } 

     return viewHolder; 
    } 
} 

Dies ist die eigentliche falsche Ergebnis:

enter image description here

ich SO sah über, aber ich kann ähnliches Szenario nicht finden, wo es Daten von benachbarten Elemente benötigt erholen (Ich bin nicht Event sicher ist das das Problem). Was würden Sie vorschlagen, um dieses Problem zu beheben?

+0

statt iterieren den Cursor über und immer wieder würde ich 'SparseBooleanArray' verwenden, um die Positionen von" Header "Ansichten zu halten – pskink

+0

@pskink netter Vorschlag, ich werde es implementieren, nachdem ich aus diesem – fillobotto

Antwort

1

Zwei verschiedene Probleme traten auf.

Artikel

Der Adapter wurde das Recycling Ansichten Recycling, die für einen anderen Elementtyp aufgeblasen wurden, daher trat eine Ausnahme während bindend, da die view.getTag() einen falschen ViewHolder Typ enthalten. Um es zu beheben, setze ich StableIds auf false.

@Override 
    public void setHasStableIds(boolean hasStableIds) { 
     super.setHasStableIds(false); 
    } 

Typ Zuordnungslogik

Logisch, richtig war, aber ich war, nachdem es auf den vorherigen Wert Einstellung hat beendete die Position des Cursors Tweaking ohne.

 @Override 
     public int getItemViewType(int pos) { 
      Integer position = pos; 
      // with -1 position you can return whatever you want 
      if(position.equals(-1)) { return HEADER_LAYOUT; } 

      Cursor cursor = mCursorAdapter.getCursor(); 
      if(!position.equals(0)) { 
       cursor.moveToPosition(position); 
       Date date0 = new Date(Long.parseLong(cursor.getString(cursor.getColumnIndex(DatabaseConst.VisitorEntry.COLUMN_NAME_ENTER))) * 1000); 

       cursor.moveToPosition(position - 1); 
       Date date1 = new Date(Long.parseLong(cursor.getString(cursor.getColumnIndex(DatabaseConst.VisitorEntry.COLUMN_NAME_ENTER))) * 1000); 

       SimpleDateFormat format = new SimpleDateFormat("ddMMyyyy", Locale.ENGLISH); 

       cursor.moveToPosition(position); 
       return ((format.format(date0).equals(format.format(date1))) ? NO_HEADER_LAYOUT : HEADER_LAYOUT); 
      } else { 
       // position = 0 -> first item in list always need header 
       cursor.moveToPosition(position); // important! 
       return HEADER_LAYOUT; 
      } 
     } 

Wie Sie sehen können, bevor sie aus dem Verfahren zurückkehrt, ich bin Einstellung wieder die Cursor-Position.

1

Es scheint ganz richtig, bis Sie den Wert von getItemViewType zurückgegeben haben. Sie haben nur einzelne ViewHolder erstellt, also VisitorViewHolder. Aber es gibt einen anderen besseren Weg, dies zu erreichen, Erstellen Sie mehrere ViewHolder Klasse und schalten Sie sie in onCreateViewHolder.

Ändern wie diese,

@Override 
    public VisitorViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { 

    switch (viewType){ 
     case HEADER_LAYOUT: 
     View v = mCursorAdapter.newView(mContext, mCursorAdapter.getCursor(), parent); 
     final VisitorViewHolder holder = new VisitorViewHolder(v);  
     return holder; 

     case NO_HEADER_LAYOUT: 
       //Return you another viewholder which contains view with no header 
     } 
} 

here für weitere Referenz Siehe Das wird Ihre Aufgabe noch leichter machen.

+0

Bitte bearbeitet Wenn ich 'view.getTag()' in 'bindView()' caste, versucht es, in den falschen ViewHolder-Typ zu konvertieren, als ob die Ansicht wiederverwendet wird und ihr Tag jetzt einem anderen Element angehört. – fillobotto

+0

More: Happt only beim Rendern von Objekten nach einem Bildlauf nach unten – fillobotto

+0

@fillobotto Wann passiert es, nachdem Sie Scrolling oder in der Initialisierungsphase zu starten? Sie müssen es in 'onBindViewHolder' und nicht in' bindView' umwandeln. Und ich denke, Sie können auch versuchen, "newView" Override-Methode zu entfernen –

Verwandte Themen