[英]RecyclerView Items added with notifyItemInserted only display after View is reloaded
I have a PopupWindow that contains a RecyclerView. 我有一个包含RecyclerView的PopupWindow。 The RecyclerView's last element is a button that adds a new item to the end of the adapter's list when clicked.
RecyclerView的最后一个元素是一个按钮,单击该按钮可将新项目添加到适配器列表的末尾。
The problem : During the first time my PopupWindow has been launched the button successfully adds new items to the RecyclerView with notifyItemInserted(dataSize - 1)
when clicked, but the RecyclerView doesn't update and show them. 问题 :在我的PopupWindow第一次启动时,该按钮在单击时成功地通过
notifyItemInserted(dataSize - 1)
将新项目添加到RecyclerView中,但是RecyclerView不会更新并显示它们。 If I close and re-open the PopupWindow however, the items previously added are properly shown in the RecyclerView and it properly updates and animates new items being added to its adapter. 但是,如果我关闭并重新打开PopupWindow,则先前添加的项目会正确显示在RecyclerView中, 并且它会正确更新并设置要添加到其适配器中的新项目的动画。
The Question : I'm not sure why the RecyclerView doesn't refresh and show the newly added items on first run of the PopupWindow, but works perfectly from second run onward. 问题 :我不确定为什么RecyclerView在第一次运行PopupWindow时不会刷新并显示新添加的项目,但是从第二次运行起就可以完美地工作了。 How do I make it work during the first run of the PopupWindow?
如何在PopupWindow的第一次运行中使其工作?
PS Its worth noting that if I use notifyDataSetChanged()
the RecyclerView works correctly (displays new items) even on first launch of the PopupWindow. PS值得注意的是,如果我使用
notifyDataSetChanged()
则即使在第一次启动PopupWindow时,RecyclerView notifyDataSetChanged()
正常工作(显示新项目)。 I want to find a way to make notifyItemInserted()
work however, because it has nice animations when new items are added. 我想找到一种使
notifyItemInserted()
工作的方法,因为当添加新项目时它具有漂亮的动画。
UserChordsAdapter.java 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 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) {
}}
The problem lies with the logic you use to update your views. 问题在于您用来更新视图的逻辑。 Currently what you are saying is this, only notify my data when a view is drawn on the screen(OnBind).
目前您的意思是,仅在屏幕上绘制视图时通知我的数据(OnBind)。 That is why it always work for the second try, because whenever a view is being drawn(swipe etc).
这就是为什么它总是可以第二次尝试的原因,因为无论何时绘制视图(滑动等)。 that onBind method will be triggered.What you need to do is to create a method in the Adapter class, that replaces this logic.
该onBind方法将被触发。您需要做的是在Adapter类中创建一个方法,以替换此逻辑。
holder.mAddChordButton.setOnClickListener(new View.OnClickListener(){
@Override
public void onClick(View v) {
mChordData.add("1,30,40");
notifyItemInserted(mChordData.size()-1);
}
});
So create a method that adds item to the mChorData set object, then call notifyItemInserted(mChordData.size()-1);
因此,创建一个将项目添加到mChorData集合对象的方法,然后调用
notifyItemInserted(mChordData.size()-1);
in that method. 用这种方法。 This will always update and notify the adapter of any changes, hence triggering redraw automatically.
这将始终更新并通知适配器任何更改,从而自动触发重绘。
First create a public method in UserChordsAdapter
that accepts an mChordData
for its paramter,then in that method call, notifyItemInserted(mChordData.size()-1);
首先在
UserChordsAdapter
中创建一个公共方法,该方法接受mChordData
作为其参数,然后在该方法中调用notifyItemInserted(mChordData.size()-1);
. 。 Firstly you need to expose the clickListener outside of that adapter.
首先,您需要在适配器之外公开clickListener。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.