Good morning,
I have a ListView in a first activity (main_activity), when I click on a selected item, I have a new activity (details_activity) that opens with more informations and details, and the user had to check it, then the (details_activity) is closed and back to the main_activity with the same list.
I want to disable the click on listView's rows that are already checked by the user.
I tried to get the position from main_activity to details_activity to use it in SQL to get the informations, it's working.
Then I sent it back, in the main_activity I used this code:
mPrr = getSharedPreferences("reponse",Context.MODE_PRIVATE);
int IDs = mPrr.getInt("ID",-1);
String rep =mPrr.getString("reponse","");
if(IDs != -1) {
lst.getChildAt(IDs).setFocusable(false);
}
Is there any help please?
Create a ArrayList in adapter than whenever perform click on that row check that row position if position not in list than add position to the array list and perform click else nothing to do.
private ArrayList<String> positionClicked = new ArrayList<>();
public void onBindViewHolder(final MyViewHolder holder, final int position) {
if (!positionClicked.contains(String.valueOf(position))) {
positionClicked.add(String.valueOf(position));
//perform Click
}else {
//
}
}
Write setClickable(false) instead of setFocusable(false);
Create custom ArrayAdapter, find the position of item you want to disable click and #Overide isEnabled method
#Override
public boolean isEnabled(int position) {
if(position == positionYouWannaDisableClick)
return false;
return true;
}
Related
I have a method to add favorites from a search list.
This code allows to click on listview and call listener accordingly weather it is search listview or mytour Listview.
holder.imgaddFavourite.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (tourList.get(position).getFav().equalsIgnoreCase("0")) {
listener.onFavourited(tourList.get(position), true);
holder.imgaddFavourite.setImageResource(R.drawable.faved);
} else {
listener.onFavourited(tourList.get(position), false);
holder.imgFavourite.setImageResource(R.drawable.not_faved);
}
}
});
Below is the code for mytourList which works perfectly:
#Override
public void onFavourited(final Tour tour, final boolean fav) {
new SetFavourite(new SetFavourite.OnFavouriteSet() {
#Override
public void onFavouriteSet(Boolean response) {
int index = listTour.indexOf(tour);
tour.setFav(fav ? "1" : "0");
listTour.set(index, tour);
}
}, fav).execute(tour.getId(), application.getUser().getUid());
}
This code persist favourite state and got no problem.
Below is my code for adding favorites for search items list.
public void onFavourited(final Tour tour, final boolean fav) {
int index = searchOptions.getSearchedTours().indexOf(tour);
tour.setFav(fav ? "1" : "0");
searchOptions.getSearchedTours().get(index).setFav(fav ? "1" : "0");
searchOptions.getSearchedTours().set(index, tour);
}
I am able to click on and add it to favorites, but if I open another tab and reopen that list again, the state is lost. I guess it is cause it's not saving state globally. I've searched for similar answers but none of them helped.
Any help would be appreciated.
You are storing the state of wheather an item is favourite or not in a Boolean variable which is not a persistent storage. It will not be same when you close and reopen the app.
You should store the favourite items on SharedPreferences or in SQL Database which are persistent storage. In that way you can add and remove the data anytime you want, and it will be persisted.
Hope this helps, if you have any doubt, do let me know.
I think you are using ViewPager to handle fragments and always create new fragment when page changed. Therefore state cannot be retained. Try below method in the adapter of ViewPager:
Add variable to keep your desired fragment.
SearchTourFragment searchTourFragment = null;
In getItem(), create your desired fragment only when it is null.
if(searchTourFragment == null){
searchTourFragment = SearchTourFragment.newInstance();
}
return searchTourFragment;
Avoid deleting your desired fragment by override destroyItem().
#Override
public void destroyItem(ViewGroup container, int position, Object object) {
if(position != POSITION_OF_SEARCHTOURFRAGMENT) container.removeView((View)object);
}
This is trying to keep your desired fragment from page change. But if you start another Activity and then back, the fragment may not be retained. Hope that helps!
I have a RecyclerView with rows that have views that when clicked will be disabled for that row position.
The problem is after I update the adapter like this:
adapterData.clear();
adapterData.addAll(refreshedAdapterData);
notifyDataSetChanged();
After refreshing the data, the disabled views at the previous recycler position still remain disabled even though the data is refreshed.
How can I reset the views to the original state after refreshing adapter data.
Use below code.
adapterData.clear();
adapterData.addAll(refreshedAdapterData);
adapter.notifyDataSetChanged();
OR
recyclerView.invalidate();
When you call notifyDataSetChanged(), the onBindViewHolder() method of every view is called. So you could add something like this in the onBindViewHolder() of your Adapter method:
#Override
public void onBindViewHolder(final RecyclerView.ViewHolder viewHolder, final int position) {
if (refreshedAdapterData.get(position).isInDefaultState()) {
//set Default View Values
} else {
//the code you already have
}
}
I have resolved this by putting a conditional statement inside onBindViewHolder method instructing all positions to reset the disabled views if data meets the required conditions for a refreshed data.
#Christoph Mayr, thanks for your comments. It helped point me in the right direction.
I cleared the data then notify change but the selected checkbox doesn't reset but just moves up one position. Let say I selected item #1 , move out of the RecyclerView, came back and it will auto select item #0.
So, I created new adapter again at onResume(), i worked for me but i don't know if it's the right way to handle this situation.
#Override
public void onResume() {
super.onResume();
if(selectedItems != null && selectedItems.size() > 0){
selectedItems.clear(); // if no selected items before then no need to reset anything
if(adapter != null && recyclerView != null){
// to remove the checked box
adapter = null;
adapter = new MyAdapter(items, new MyAdapter.MyAdapterListener() {
#Override
public void onSelected(int pos) {
selectedItems.add(items.get(pos));
}
#Override
public void onUnSelected(int pos) {
selectedItems.remove(items.get(pos));
}
});
recyclerView.setAdapter(adapter);
}
}
}
I want know that how to highlight recyclerView item.when the user close the app and open app in next time then change the color recyclerView item whos read the uesr.how it is possible?
Store the Item positions that the user reads and then in the onBindViewHolder method of the RecylerViewAdapter try this following code
#Override
public void onBindViewHolder(RecylerViewAdapter.ViewHolder holder, final int position) {
//some code....
if(isRead(position)){
holder.mView.setBackgroundColor(Color.RED);
}else
holder.mView.setBackgroundColor(Color.TRANSPARENT);
}
// readList is the positions that you stored in some array
// you can use the sqlite database or other logic whatever you prefer to store the positions
private void isRead(int position){
for(int i = 0;i<readList.length;i++){
if(readList[i]==position)
return true;
}
return false;
}
I'll show the code and after the steps to get the problem.
I have a recyclerview inside a tabbed fragment that takes the dataset from a custom object:
mRecyclerView = (RecyclerView) v.findViewById(R.id.recyclerview);
mRecyclerView.setLayoutManager(mLayoutManager);
mRecyclerAdapter = new MyRecyclerAdapter(mMes.getListaItens(), this, getActivity());
mRecyclerView.setAdapter(mRecyclerAdapter);
I set the longclick behavior of the list items in onBindViewHolder() of the adapter:
#Override
public void onBindViewHolder(final ViewHolder holder, final int position) {
ItemMes item = mListaItens.get((position));
holder.descricao.setText(item.getDescrição());
holder.valor.setText(MainActivity.decimalFormatWithCod.format(item.getValor()));
...
holder.itemView.setOnLongClickListener(new View.OnLongClickListener() {
#Override
public boolean onLongClick(View v) {
new MaterialDialog.Builder(mContext)
.title(holder.descricao.getText().toString())
.items(R.array.opcoes_longclick_item)
.itemsCallbackSingleChoice(-1, new MaterialDialog.ListCallbackSingleChoice() {
#Override
public boolean onSelection(MaterialDialog dialog, View view, int which, CharSequence text) {
switch (which) {
case 0:
mParentFragment.showUpdateItemDialog(position);
return true;
case 1:
mParentFragment.showDeleteItemDialog(position);
return true;
}
return false;
}
})
.show();
return true;
}
});
}
Then, the methods in the fragment that take care of delete the item itself:
public void showDeleteItemDialog(int position) {
final ItemMes item = mMes.getListaItens().get(position);
new MaterialDialog.Builder(getActivity())
.title("Confirmar Remoção")
.content("Tem certeza que deseja remover " + item.getDescrição() + "?")
.positiveText("Sim")
.negativeText("Cancelar")
.onPositive(new MaterialDialog.SingleButtonCallback() {
#Override
public void onClick(#NonNull MaterialDialog dialog, #NonNull DialogAction which) {
deleteItem(item);
}
})
.show();
}
public void deleteItem(ItemMes item) {
getMainActivity().deleteItemFromDatabase(item.getID());
int position = mMes.getListaItens().indexOf(item);
mMes.getListaItens().remove(position);
mRecyclerAdapter.notifyItemRemoved(position);
atualizaFragment();
}
And finally the method in activity that do the DB operation:
public int deleteItemFromDatabase(long id) {
SQLiteDatabase db = dataBaseHelper.getWritableDatabase();
String where = DBHelper.COLUNA_ID + " = ?";
String[] args = {String.valueOf(id)};
int rowsAffected = db.delete(DBHelper.TABELA_ITEM, where, args);
db.close();
return rowsAffected;
}
Now i'll reproduce the steps:
I'm showing 3 itens in the listview. Then I try to remove the first:
1 - The longclick is intercepted passing the correct index:
2 - The item is correctly deleted from the database:
3 - After all this, as expected, the adapter is storing and showing 2 items...
SO, if I try to delete the first item of this 2 item list I get the wrong position (should be 0, is 1):
And also if I try to delete the last item of this 2 item list I get the wrong position (should be 1, is 2):
The question is: If I have a dataset of size 2 (and the adapter knows it), how can it call onBindViewHolder(ViewHolder holder, int [last index +1])?
I have no idea what could be wrong. So I ask help cause I'm thinking about give up this project cause I do everything right but always something dont works, and Im tired.
Thanks in advance.
I've noticed that in method onBindViewHolder(VH holder, int position) while the position was comming wrong, the holder.getAdapterPosition() gives me always the correct position.
So I changed my code from:
ItemMes item = mListaItens.get((position));
...
mParentFragment.showUpdateItemDialog(position);
...
mParentFragment.showDeleteItemDialog(position);
....
To:
ItemMes item = mListaItens.get((holder.getAdapterPosition()));
...
mParentFragment.showUpdateItemDialog(holder.getAdapterPosition());
...
mParentFragment.showDeleteItemDialog(holder.getAdapterPosition());
....
And everything works well. This is very strange but...
Thanks everybody.
Took a look at the adapter code you provided in the comment and it's pretty straightforward. Try this: rather than call notifyItemRemoved(), call notifyDataSetChanged(). This is rather expensive as it will cause your adapter to re-bind the data set (and re-create ViewHolders), but since you're using an ArrayList where you are removing an element, it's really the simplest way to do it. Otherwise you'll have to track the position of the items and when an item is removed it cannot change the position of other items - or handle the case where items shift their position in the data set.
Try this code in onBindViewHolder()
int adapterPos=holder.getAdapterPosition();
if (adapterPos<0){
adapterPos*=-1;
}
ItemMes item = mListaItens.get((adapterPos));
mParentFragment.showUpdateItemDialog(adapterPos);
Use adapterPos instead of position variable.
According to RecyclerView's getAdapterPosition documentation:
RecyclerView does not handle any adapter updates until the next layout traversal. This
may create temporary inconsistencies between what user sees on the screen and what
adapter contents have. This inconsistency is not important since it will be less than
16ms but it might be a problem if you want to use ViewHolder position to access the
adapter. Sometimes, you may need to get the exact adapter position to do
some actions in response to user events. In that case, you should use this method which
will calculate the Adapter position of the ViewHolder.
So in case of implementing user events, using getAdapterPosition is a recommended way to go.
I have a listview in fragment.
When I select a listview item, it gets highlighted and then I open another fragment.
Now, what I want is, when I move back to previous fragment, the list item should stay selected.
How can I do that?
I have implemented like
add this two methods in your Adapter
private int selectedIndex = ListView.NO_ID;
public int getSelectedIndex() {
return selectedIndex;
}
public void setSelectedIndex(int index) {
this.selectedIndex = index;
// Re-draw the list by informing the view of the changes
notifyDataSetChanged();
}
and in your Adapter getView(...) do
// Highlight the selected item in the list
if (selectedIndex != -1 && selectedIndex == position) {
YourView.setBackgroundResource(R.color.lightred);
}
and implement in Fragment in setOnItemClickListener onItemClick(...) like
adapter.setSelectedIndex(position);
save this selected value in some preferences and when you come back again call in Fragment on resume(...)
adapter.setSelectedIndex(selectedIndex);
OK let's do this
declare one field in your adapter say
private int selectedPosition=-1;
now create a setter for this
private void setSelectedPosition(int position)
{
selectedPosition=position;
}
Now in your getView method
if(position==selectedPosition)
{
listItemView.setSelected(true);
//OR
listItemView.setBackgroundColor(<Some Color>);
}
Now after setting the adapter when user tap and your OnItmeSelected called
adapter.setSelectedPosition(<your desired selected item position>);
adapter.notifyDataSetChanged();