I must implement comments list with replies. I use same Item for comment and it's reply. But when I have multiple replies for comment and scroll up to it Recycler View lost position while binding that item.
public void setItem(Adaptable item) {
super.setItem(item);
this.comment = (Comment) item;
binding.setComment(comment);
binding.setViewHolder(this);
binding.tvMessage.setText(getFormattedText());
initReplies();
}
private void initReplies() {
if (comment.repliesCount <= 0) {
binding.recyclerView.setVisibility(View.GONE);
return;
}
binding.recyclerView.setVisibility(View.VISIBLE);
binding.recyclerView.setNestedScrollingEnabled(false);
if (adapter == null) {
LinearLayoutManager layoutManager = new LinearLayoutManager(fragment.getContext(), LinearLayoutManager.VERTICAL, true);
binding.recyclerView.setLayoutManager(layoutManager);
adapter = new RecyclerViewAdapter(fragment, Pages.ID_COMMENTS_REPLY, false);
}
adapter.clear();
adapter.addItems(new ArrayList<>(comment.replies), getCommentMeta());
binding.recyclerView.setAdapter(adapter);
}
setItem method I call from onBindViewHolder
Related
I want to make a custom insert animation in RecyclerView when adding items. This is what I got so far:
private void init(View view, Context context) {
recyclerView = view.findViewById(R.id.messagesList);
layoutManager = new LinearLayoutManager(context);
layoutManager.setStackFromEnd(true);
recyclerView.setLayoutManager(layoutManager);
recyclerView.setAdapter(adapter);
recyclerView.setItemAnimator(new DefaultItemAnimator() {
#Override
public boolean animateAdd(RecyclerView.ViewHolder holder) {
holder.itemView.setScaleY(0);
holder.itemView.animate().scaleY(1).setDuration(3000).start();
return super.animateAdd(holder);
}
});
}
private void onNewItem(Item item){
adapter.onNewItem(item);
layoutManager.smoothScrollToPosition(recyclerView, null, adapter.getItemCount());
}
Then in the adapter
private void onNewItem(Item item){
items.addItem(item);
notifyItemInserted(items.size());
}
The item just appears when it's added, there is no scroll nor custom animation.
Replacing smoothScrollToPosition with scrollToPosition solved the problem.
Also I had a bug calling to notifyItemInserted(items.size()); instead of notifyItemInserted(items.size() - 1);
I set up my recyclerView with a SnapHelper in the standard way. That works fine. However, I need to be notified when an item has been "snapped" into place so that I can update a TextView with that index. I've tried setting setOnFlingListener on the recyclerView, but snapHelper has already set an instance of it so an exception is thrown.
RecyclerView recyclerView = (RecyclerView) findViewById(R.id.recyclerview);
layoutManager = new LinearLayoutManager(this, LinearLayoutManager.HORIZONTAL, false);
recyclerView.setLayoutManager(layoutManager);
adapter = new PlantAdapter(this, Globals.getPlants());
recyclerView.setAdapter(adapter);
snapHelper = new snapHelper(this);
snapHelper.attachToRecyclerView(recyclerView);
Is there another way to know exactly when, and which, item has been snapped?
I have figured it out. I added an onScrollListener to the recyclerview, then get the position in onScrollStateChanged when the scroll state is SCROLL_STATE_IDLE.
recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
#Override
public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
if(newState == AbsListView.OnScrollListener.SCROLL_STATE_IDLE) {
View centerView = snapHelper.findSnapView(layoutManager);
if (centerView != null) {
int pos = layoutManager.getPosition(centerView);
updateAdapterPosition(pos);
}
else {
updateAdapterPosition(markers.size() - 1);
}
}
}
});
I have a RecyclerView list of CardViews. New CardViews are inserted at the top of the list.
If the View is currently at the bottom of the CardView list and I click my "Add" button to create a new CardView, I want the RecyclerView to then show the new CardView at the top of the list. Currently, when the new CardView is created the RecyclerView just returns to the previous View at the bottom of the list.
I've tried many things, without any luck, including:
recyclerView.getLayoutManager().scrollToPosition(0);
recyclerView.scrollToPosition(0);
linearlayoutmanager.scrollToPositionWithOffset(0,0)
Adapter.java
public void add(Contact item) {
if (contactList.size()==0) {
contactList.clear();
notifyDataSetChanged();
}
contactList.add(item);
notifyItemInserted(0);
}
public void addAll(List<Contact> contactList) {
for (Contact contact : contactList) {
add(contact);
}
}
Activity.java
...
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
EmptyRecyclerView recyclerView = (EmptyRecyclerView)findViewById(R.id.list_recyclerview);
recyclerView.setHasFixedSize(true);
LinearLayoutManager layoutManager = new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false);
recyclerView.setLayoutManager(layoutManager);
recyclerView.setEmptyView(findViewById(R.id.empty_view));
contactListAdapter = new ContactListAdapter(this);
contactListAdapter.setOnItemClickListener(this);
recyclerView.setAdapter(contactListAdapter);
#Override
protected void onStart() {
super.onStart();
loadData();
}
void loadData(){
List<Contact> contactList = new ArrayList<>();
Cursor cursor = sqLiteDB.retrieve();
Contact contact;
try {
if (cursor.getCount() > 0) {
cursor.moveToFirst();
while (!cursor.isAfterLast()) {
do {
contact = new Contact();
contact.setI(cursor.getInt(0));
contact.setC(cursor.getInt(1));
contact.setT(cursor.getString(2));
contact.setN1(cursor.getString(3));
contact.setN2(cursor.getString(4));
contact.setD(cursor.getString(5));
contact.setDt(cursor.getString(6));
contact.setTm(cursor.getLong(7));
// add the item to the top of the List.
contactList.add(0, contact);
} while (cursor.moveToNext());
}
}
} finally {
if (cursor != null && !cursor.isClosed()) {
cursor.close();
}
}
contactListAdapter.clear();
contactListAdapter.addAll(contactList);
do like this
recyclerview.post(new Runnable() {
#Override
public void run() {
LinearLayoutManager layoutManager = (LinearLayoutManager) mRecyclerView.getLayoutManager();
layoutManager.scrollToPositionWithOffset(0, 0);
}
});
if this does not work check where are you calling this and control executes this statement or not.
I use this with a "scroll to top" button, you can try work your way around with it :
LinearLayoutManager mlayoutManager = (LinearLayoutManager) rv.getLayoutManager();
mlayoutManager.scrollToPositionWithOffset(0, 0);
I am using a RecyclerView to show the data that is retrieved after parsing from the web services. The problem is notifydatasetchanged is not working at all. For solving that thing, I am setting the adapter again.
I am having two problems using this technique:
There is a screen blink while setting a new adapter again.
Also the recycler view points to first item of the recycler view. (I just want to append the new data at the end of the existing list.Array list size is updating. But the only problem, the list is started from the zeroth position.)
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_book_mag_list_child, container, false);
recyclerView = (RecyclerView) view.findViewById(R.id.bookMagRecyclerViewList);
bookMagDataList = new ArrayList<>();
adapter = new BookMagListRecyclerViewAdapter(getActivity(), bookMagDataList);
recyclerView.setAdapter(adapter);
LinearLayoutManager linearLayoutManager = new LinearLayoutManager(getActivity());
//linearLayoutManager.setStackFromEnd(true);
recyclerView.setLayoutManager(linearLayoutManager);
recyclerView.setOnScrollListener(new EndlessRecyclerScrollListener(linearLayoutManager) {
#Override
public void onLoadMore(int current_page) {
Log.d("Do Something", "Do Something" + current_page);
params.setStart("" + current_page);
dataModel.init(params);
}
});
return view;
}
#Override
public void update() {
if (dataModel.getFragmentData(subScreenId) != null) {
bookMagDataList = dataModel.getFragmentData(subScreenId);
Log.d("MyDataListSize: ", "" + bookMagDataList.size());
adapter = new BookMagListRecyclerViewAdapter(getActivity(), bookMagDataList);
recyclerView.setAdapter(adapter);
}
}
Please check what is the issue and let me know if it can be solved.
The problem is in your update function. You are overriding the bookMagDataList list with new instance everytime your update. You should have use .addAll() function to add in new element. Then call adapter.notifyDataSetChanged() after that. Make changes as below.
#Override
public void update() {
if (dataModel.getFragmentData(subScreenId) != null) {
bookMagDataList.addAll(dataModel.getFragmentData(subScreenId));
Log.d("MyDataListSize: ", "" + bookMagDataList.size());
adapter.notifyDataSetChanged();
}
}
since u didnt posted your adapter code u have to use styx approach:
#Override
public void update() {
if (dataModel.getFragmentData(subScreenId) != null) {
bookMagDataList.addAll(dataModel.getFragmentData(subScreenId));
Log.d("MyDataListSize: ", "" + bookMagDataList.size());
adapter.notifyDataSetChanged();
}
}
answer is given by styx so credits to him
my solution is below
if (adapter == null) {
adapter = new BookMagListRecyclerViewAdapter(getActivity(), bookMagDataList);
recyclerView.setAdapter(adapter);
} else {
adapter.bookMagDataList.clear();
adapter.bookMagDataList = bookMagDataList;
myAdapter.notifyDataSetChanged()
}
Don't instantiate adapter again, only you should add new data in arrayList then invoke notifyDatasetChanged()
like--
bookMagDataList.add("YOUR ITEM");
adpter.notifyDatasetChanged();
you have to do like below in update method,
if(adapter == null){
adapter = new BookMagListRecyclerViewAdapter(getActivity(), bookMagDataList);
recyclerView.setAdapter(adapter);
}else{
myAdapter.notifyDataSetChanged();
}
I create a RecyclerView containing list of items with vertical orientation.
I added another RecyclerView inside a single node in the parent RecyclerView to show a grid of items inside each cell.
I added a click listener for the grid item in the cell as like : mRvHomeMosaic.setOnClickListener(this); inside view holder, but it's not getting triggered by a click.
Please help me, if anyone has the same problem. Or anyone who use Nested RecyclerView.
My Holder class and onBindView() is given below
class HomeViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
RecyclerView mRvHomeMosaic;
public HomeViewHolder(View itemView) {
super(itemView);
this.mRvHomeMosaic = (RecyclerView) itemView.findViewById(R.id.rv_home_mosaic_image);
mRvHomeMosaic.setEnabled(true);
mRvHomeMosaic.setOnClickListener(this);
}
#Override
public void onClick(View view) {
if (clickListener != null) {
clickListener.itemClickListner(view, getPosition());
}
}
}
#Override
public void onBindViewHolder(final HomeViewHolder holder, int position) {
if (mDataList.get(position).getmMosaicModelList() != null &&
mDataList.get(position).getmMosaicModelList().size() > 0) {
holder.mRvHomeMosaic.setEnabled(true);
HomeSubAdapter adapter = new HomeSubAdapter(mContext, mDataList.get(position).
getmMosaicModelList());
holder.mRvHomeMosaic.setAdapter(adapter);
StaggeredGridLayoutManager mLayoutManager = new StaggeredGridLayoutManager(3,
StaggeredGridLayoutManager.VERTICAL);
holder.mRvHomeMosaic.setLayoutManager(mLayoutManager);
} else {
holder.mRvHomeMosaic.setEnabled(true);
List<MosaicTileModel> modelList = new ArrayList<>();
MosaicTileAdapter adapter = new MosaicTileAdapter(mContext, modelList);
holder.mRvHomeMosaic.setAdapter(adapter);
StaggeredGridLayoutManager mLayoutManager = new StaggeredGridLayoutManager(3,
StaggeredGridLayoutManager.VERTICAL);
holder.mRvHomeMosaic.setLayoutManager(mLayoutManager);
}
}`
The single node has some other items also. Click listener is properly triggered that items. But in the case of Inner Recylcerview object it's not getting triggered.