2017-05-29 4 views
0

Ich habe ein PopupWindow, das eine RecyclerView enthält. Das letzte Element von RecyclerView ist eine Schaltfläche, die am Ende der Liste des Adapters ein neues Element hinzufügt, wenn darauf geklickt wird.RecyclerView Elemente hinzugefügt mit notifyItemInserted nur angezeigt, nachdem die Ansicht neu geladen wurde

Das Problem: Während der ersten Zeit hat mein PopupWindow gestartet fügt die Schaltfläche erfolgreich neue Elemente in die RecyclerView mit notifyItemInserted(dataSize - 1), wenn darauf geklickt, aber die RecyclerView und sie zeigen nicht aktualisiert. Wenn ich das PopupWindow schließe und wieder öffne, werden die zuvor hinzugefügten Elemente ordnungsgemäß im RecyclerView und angezeigt. Es aktualisiert und animiert ordnungsgemäß neue Elemente, die dem Adapter hinzugefügt werden.

Die Frage: Ich bin mir nicht sicher, warum der RecyclerView nicht aktualisiert und die neu hinzugefügten Elemente beim ersten Start des PopupWindow zeigt, aber funktioniert perfekt ab dem zweiten Durchlauf. Wie mache ich es beim ersten Start des PopupWindow funktionieren?

P.S. Es ist erwähnenswert, dass, wenn ich notifyDataSetChanged() verwende, der RecyclerView korrekt funktioniert (zeigt neue Elemente an), sogar beim ersten Start des PopupWindow. Ich möchte einen Weg finden, notifyItemInserted() funktionieren zu lassen, weil es nette Animationen hat, wenn neue Elemente hinzugefügt werden.

UserChordsAdapter.java

public class UserChordsAdapter extends RecyclerView.Adapter<UserChordsAdapter.ChordViewHolder> { 

private Context context; 
private final ListItemClickListener mClickHandler; 
private ArrayList<String> mChordData = new ArrayList<String>(); //contains all user created chords as comma delimited note #s 

/** 
* The interface that receives onClick messages. 
*/ 
public interface ListItemClickListener { 
    void onListItemClick(int clickedItemIndex); 
} 

/** 
* 
* @param clickHandler The on-click handler for this adapter. This single handler is called 
*      when an item is clicked. 
*/ 
public UserChordsAdapter(ListItemClickListener clickHandler) { 
    mClickHandler = clickHandler; 
} 

@Override 
public ChordViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { 
    context = parent.getContext(); 
    int layoutIdForListItem = R.layout.user_chord_list_item; 
    int layoutIdForFooterItem = R.layout.user_chord_add_new; 
    LayoutInflater inflater = LayoutInflater.from(context); 
    boolean shouldAttachToParentImmediately = false; 

    View listItem; 
    ChordViewHolder viewHolder; 

    if (viewType == R.layout.user_chord_list_item) { //inflate chord item 
     listItem = inflater.inflate(layoutIdForListItem, parent, shouldAttachToParentImmediately); 
     viewHolder = new ChordViewHolder(listItem); 
    } 
    else {            //inflate "+ Add new" button (last list item) 
     listItem = inflater.inflate(layoutIdForFooterItem, parent, shouldAttachToParentImmediately); 
     viewHolder = new ChordViewHolder(listItem); 
    } 

    return viewHolder; 
} 

@Override 
public void onBindViewHolder(ChordViewHolder holder, int position) { 
    if (position == mChordData.size()){ 
     holder.mAddChordButton.setOnClickListener(new View.OnClickListener(){ 
      @Override 
      public void onClick(View v) { 
       mChordData.add("1,30,40"); 
       notifyItemInserted(mChordData.size()-1); 
      } 
     }); 
    } 
    else { 
     holder.mChordName.setText("Chord " + Integer.toString(position)); 
    } 
} 

@Override 
public int getItemCount() { 
    if (mChordData == null){ 
     return 1; 
    } 
    return mChordData.size() + 1; // +1 is for footer button (add new) 
} 

class ChordViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener { 

    // Will display which ViewHolder is displaying this data 
    TextView mChordName; 
    Button mAddChordButton; 

    /** 
    * Constructor for our ViewHolder. Within this constructor, we get a reference to our 
    * TextViews and set an onClickListener to listen for clicks. Those will be handled in the 
    * onClick method below. 
    */ 
    public ChordViewHolder(View itemView) { 
     super(itemView); 

     mAddChordButton = (Button) itemView.findViewById(R.id.button_add_new); 
     mChordName = (TextView) itemView.findViewById(R.id.tv_view_holder_instance); 
     itemView.setOnClickListener(this); 
    } 

    /** 
    * Called whenever a user clicks on an item in the list. 
    * @param v The View that was clicked 
    */ 
    @Override 
    public void onClick(View v) { 
     int clickedPosition = getAdapterPosition(); 
     String chordData = mChordData.get(clickedPosition); 
     mClickHandler.onListItemClick(clickedPosition); 
    } 
} 

/** 
* Distinguishes if view is a Chord list item or the last item in the list (add new chord) 
* @param position 
* @return 
*/ 
@Override 
public int getItemViewType(int position) { 
    return (position == mChordData.size()) ? R.layout.user_chord_add_new : R.layout.user_chord_list_item; 
}} 

FragmentChordMenu.java

public class FragmentChordMenu extends Fragment implements UserChordsAdapter.ListItemClickListener{ 
private FloatingActionButton mFAB; 
private View mPopupView; 
private PopupWindow mUserChordMenu; 
private RecyclerView mUserChordsList; 
private UserChordsAdapter mRecyclerViewAdapter; 
private int numItems = 0; //TODO: dynamically calculate this as # of saved chords + 1(add new) 

@Override 
public void onActivityCreated(@Nullable Bundle savedInstanceState) { 
    super.onActivityCreated(savedInstanceState); 
    mRecyclerViewAdapter = new UserChordsAdapter(this); 
} 

@Nullable 
@Override 
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, Bundle savedInstanceState) { 
    View v = inflater.inflate(R.layout.menu_fragment_chord, container, false); 

    LayoutInflater layoutInflater = (LayoutInflater)getActivity().getBaseContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE); 
    mPopupView = layoutInflater.inflate(R.layout.menu_popup_set_chords, null); 
    int menuWidth = (int)(MainActivity.getActualWidth()*.95); 
    int menuHeight = (int)(MainActivity.getActualHeight()*.90); 
    mUserChordMenu = new PopupWindow(mPopupView, menuWidth, menuHeight); 
    mUserChordMenu.setFocusable(true); 

    mFAB = (FloatingActionButton) v.findViewById(R.id.addChord); 
    mFAB.setOnClickListener(new View.OnClickListener() { 
     public void onClick(View v) { 
      mUserChordMenu.showAtLocation(mPopupView, Gravity.CENTER, 10, 10); 
      mUserChordsList = (RecyclerView) mPopupView.findViewById(R.id.rv_userChords); 
      LinearLayoutManager layoutManager = new LinearLayoutManager(getActivity()); 
      mUserChordsList.setLayoutManager(layoutManager); 
      mUserChordsList.setAdapter(mRecyclerViewAdapter); 
     } 
    }); 
    return v; 
} 


/** 
* Called from UserChordsAdapter's onClick. Only fires on list item clicks, not the add new button 
* 
* */ 
@Override 
public void onListItemClick(int clickedItemIndex) { 
}} 
+0

Von welchen externen Änderungen leiten Sie ab? – Remario

+0

Keine. Dies ist ein Proof of Concept für das Hinzufügen von Platzhalterelementen zu meiner RecyclerView, wenn auf eine Schaltfläche geklickt wird. – Cody

+0

Warum haben Sie das Benachrichtigungsupdate notifyItemInserted (mChordData.size() - 1); in onBind? – Remario

Antwort

0

Das Problem liegt bei der Logik, die Sie Ihre Ansichten aktualisieren verwenden. Derzeit, was Sie sagen, ist dies, nur meine Daten benachrichtigen, wenn eine Ansicht auf dem Bildschirm (OnBind) gezeichnet wird. Deshalb funktioniert es immer beim zweiten Versuch, denn immer wenn eine Ansicht gezeichnet wird (Swipe etc). Die onBind-Methode wird ausgelöst. Sie müssen eine Methode in der Adapter-Klasse erstellen, die diese Logik ersetzt.

holder.mAddChordButton.setOnClickListener(new View.OnClickListener(){ 
      @Override 
      public void onClick(View v) { 
       mChordData.add("1,30,40"); 
       notifyItemInserted(mChordData.size()-1); 
      } 
     }); 

erstellen So ein Verfahren, das Element zum mChorData Set-Objekt fügt hinzu, dann notifyItemInserted(mChordData.size()-1); in dieser Methode aufrufen. Dadurch werden Aktualisierungen immer aktualisiert und der Adapter wird über Änderungen informiert, wodurch automatisch ein Redraw ausgelöst wird.

Zuerst erstellen Sie eine öffentliche Methode in UserChordsAdapter, die eine mChordData für seinen Parameter akzeptiert, dann in diesem Methodenaufruf notifyItemInserted(mChordData.size()-1);. Zuerst müssen Sie den clickListener außerhalb dieses Adapters verfügbar machen.

+0

Wie soll ich diese neue Methode außerhalb der onBind-Logik aufrufen, wenn meine "Add new" -Schaltfläche onClick in onBind ist?Können Sie ein echtes Beispiel geben? – Cody

+0

sicher, gib mir etwas Zeit. – Remario

+0

überprüfen Sie die aktualisierte Antwort, wenn Sie Code möchten, senden Sie einen Sinn, mit mehr Code. – Remario

Verwandte Themen