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);
Related
I want to do a RESET button. I already successfully do for Spinner and Seekbar but failed to do for RecyclerView which is my filtering result. There is no error, but as you can see in my output interface, ONLY the recyclerView did not empty...
My coding:-
resetButton.setOnClickListener(new View.OnClickListener() {
final MediaPlayer mediaPlayer = MediaPlayer.create(FilterTuitionCentre.this, R.raw.soundeffect1);
#Override
public void onClick(View v) {
mediaPlayer.start();
spLocation.setSelection(0);
seekbarPrice.setProgress(0);
spAcademicLevel.setSelection(0);
spSubject.setSelection(0);
recyclerView.invalidate();
}
});
My interface output:-
My adapter coding:-
LinearLayoutManager linearLayoutManager = new LinearLayoutManager(getApplicationContext());
recyclerView.setLayoutManager(linearLayoutManager);
recyclerView.setAdapter(mAdapter);
I assume that you have following initialization for your recyclerView :
YourAdapter adapter = new YourAdapter(items);
recyclerView.setLayoutManager(new LinearLayoutManager(this));
recyclerView.setAdapter(adapter);
To clear items(Empty) RecyclerView you need to :
items.clear();
adapter.notifyDataSetChanged();
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
hi i have a RecyclerView adapter as follow :-
public class RecyclerViewAdapter extends RecyclerView.Adapter<ViewHolder> {
List<Data> list = Collections.emptyList();
Context context;
public RecyclerViewAdapter(List<Data> list, Context context) {
this.list = list;
this.context = context;
}
#Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
//Inflate the layout, initialize the View Holder
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.apps_layout, parent, false);
ViewHolder holder = new ViewHolder(v);
return holder;
}
#Override
public void onViewDetachedFromWindow(ViewHolder holder) {
super.onViewDetachedFromWindow(holder);
((ViewHolder)holder).itemView.clearAnimation();
}
#Override
public void onBindViewHolder(ViewHolder holder, int position) {
//Use the provided View Holder on the onCreateViewHolder method to populate the current row on the RecyclerView
holder.title.setText(list.get(position).title);
holder.description.setText(list.get(position).description);
}
public void setFilter(List<Data> searched_data) {
list = new ArrayList<>();
list.addAll(searched_data);
notifyDataSetChanged();
}
#Override
public int getItemCount() {
//returns the number of elements the RecyclerView will display
return list.size();
}
#Override
public void onAttachedToRecyclerView(RecyclerView recyclerView) {
super.onAttachedToRecyclerView(recyclerView);
}
// Insert a new item to the RecyclerView on a predefined position
public void insert(int position, Data data) {
list.add(position, data);
notifyItemInserted(position);
}
// Remove a RecyclerView item containing a specified Data object
public void remove(Data data) {
int position = list.indexOf(data);
list.remove(position);
notifyItemRemoved(position);
}
}
okay now as you can see setFilter method to filter recyclerview list
here is how i call it
searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
#Override
public boolean onQueryTextSubmit(String s) {
return false;
}
#Override
public boolean onQueryTextChange(String s) {
List<Data> filteredModelList = filter(data, s);
adapter.setFilter(filteredModelList);
return true;
}
});
now filter works fine now when i click on it the position is wrong
i know the error coming from the position as the older recyclerview on click has old position index i dont know how to fix it anyway here is onclicklistener
data = appsdata(); // load the list List<Data>
Collections.sort(data); // sorting
recyclerView = (RecyclerView) findViewById(R.id.recyclerview);
final LinearLayoutManager layoutManager = new LinearLayoutManager(this);
layoutManager.setOrientation(LinearLayoutManager.VERTICAL);
recyclerView.setLayoutManager(layoutManager);
adapter = new RecyclerViewAdapter(data, this);
recyclerView.setAdapter(adapter);
recyclerView.setNestedScrollingEnabled(false);
recyclerView.addOnItemTouchListener(new RecyclerItemClickListener(this, recyclerView, new RecyclerItemClickListener.OnItemClickListener() {
#Override
public void onItemClick(View view, int position) {
String s = data.get(position).title;
String ss = data.get(position).description;
Intent intent = new Intent(MainAcitivity.this, Work.class);
intent.putExtra("title", s);
intent.putExtra("desc", ss);
startActivity(intent);
}
}));
i know this line is causing problem
String s = data.get(position).title;
because it is same as old when list was not filtered ,how i can update this recyclerview so that i can get updated index when launching Work.class
okay guys this what works partially for me
i tried updating the data list by adding
data = filteredModelList; // add this line
after filtering and this worked fine
#Override
public boolean onQueryTextChange(String s) {
List<Data> filteredModelList = filter(data, s);
adapter.setFilter(filteredModelList);
data = filteredModelList; // add this line
return true;
}
now i get real index but when i search and clear the list the list is empty because i replaced the data list :(
EDIT :- i fixed it by hack not a nice way but works
as you can see the old list was gone by using above stuff before edit
when i used to change the data list
data = filteredModelList; // add this line
then the new data list has only filtered values and when you clear searchView then that data list is empty because it does not have those all apps list what i did was that i made new list as data_fix and onclicklistener i used datafix instead of data list
see this how
RecyclerItemClickListener method
String s = datafix.get(position).title; // data.get to datafix.get
String ss = datafix.get(position).description; // data.get to datafix.get
now onsetfilter call
i called this
datafix = filteredModelList; // instead of data = filteredModelList;
also i initialize it oncreate so it is not empty on launch of the app by
data = appsdata(); // load the list List<Data>
datafix = appsdata(); // load the list List<Data> added just below it to intialize
now this way the full loaded applist // List data stays full and doesnot clear even if you clear from searchView and index is all right
The logic lies to how you update the recycler view items,
public void setFilter(List<Data> searched_data) {
list = new ArrayList<>();
list.addAll(searched_data);
notifyDataSetChanged();
}
The above line is not necessary, adapter = new RecyclerViewAdapter(data, this); this line is very important to understand. You see when you pass data to the adapter is like this you are creating a symbolic link between the list in the adapter and outside. So therefore any changes made to the outside list, to update the adapter version.Just call adapter.notifyDatasetChange method
do this whenever any changes are made to the data model object.
CHANGE THE FOLLOWING FROM
List<Data> filteredModelList = filter(data, s);
adapter.setFilter(filteredModelList);
data = filteredModelList; // add this line
return true;
TO,
adapter.list.clear();
data = filter(data, s);
adapter.notifyDataSetChange();
I have a RecyclerView with a LinearLayoutManager that is backed by an adapter with items of different height. Is there a way to tell the RecyclerView to set the scroll position so that item X appears (more or less) exactly at the bottom of the screen?
I tried LinearLayoutManager.scrollToPosition() but this will position the item at the top of the view.
MyAdapter mAdapter;
RecyclerView recyclerView;
List<ItemData> data = new ArrayList<>();
LinearLayoutManager llm = new LinearLayoutManager(this);
try this in OnCreate method
recyclerView = (RecyclerView) findViewById(R.id.recycler_view);
recyclerView.setHasFixedSize(true);
recyclerView.setLayoutManager(llm);
llm.setStackFromEnd(true);
mAdapter = new MyAdapter(data, getApplication());
recyclerView.setAdapter(mAdapter);
and when you insert an item try this
mAdapter.notifyItemInserted(data.size() - 1);
llm.scrollToPosition(data.size() - 1);
Try this in mainActivity.class
rv_journey.setAdapter(ca);
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
scrollList();
}
}, 500);
Here is my scroll Method
private void scrollList(){
rv_journey.post(new Runnable() {
#Override
public void run() {
// Call smooth scroll
rv_journey.smoothScrollToPosition(Index);
}
});
}
Set index from Adapter class which extend RecyclerView.Adapter Where You need to scroll...
if (Condition) {
mainActivity.Index=position+1;
}
}
Happy Coding...
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();
}