I'm implementing cancel and enable functions for my ReyclerView using a Pop up Menu that calls a backend API that interacts with the Database. The API works fine. However, the functions update the last Item on the List as opposed to the one selected. How do I go about this?
I tried to get the Id from the Model definition but also failed. It returned the Id for the last Item.
public void onBindViewHolder(final RecyclerView.ViewHolder holder, int position) {
// Get current position of item in recyclerview to bind data and assign values from list
final MyHolder myHolder= (MyHolder) holder;
current = dataErrand.get(position);
myHolder.service.setText(current.errandservice);
myHolder.date.setText("Date: " + current.erranddate);
myHolder.time.setText("Time: " + current.errandtime);
myHolder.phone.setText("Phone: " + current.errandphone);
myHolder.location.setText("Location: " + current.errandlocation);
myHolder.status.setText("status: " + current.errandstatus);
myHolder.id.setText("Id: "+current.getErrandid());
myHolder.options.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
PopupMenu popup = new PopupMenu(context, myHolder.options);
popup.inflate(R.menu.errand_options);
Menu popMenu = popup.getMenu();
if(current.errandstatus == "Active"){
popMenu.findItem(R.id.errand_reactivate).setVisible(false);
popMenu.findItem(R.id.errand_cancel).setVisible(true);
}
if (current.errandstatus == "Canceled"){
popMenu.findItem(R.id.errand_cancel).setVisible(false);
popMenu.findItem(R.id.errand_reactivate).setVisible(true);
}
popup.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {
#Override
public boolean onMenuItemClick(MenuItem item) {
int menuId = item.getItemId();
if(menuId == R.id.errand_cancel){
//handle menu1 click
//return true;
Toast.makeText(context, " "+current.getErrandid(), Toast.LENGTH_LONG).show();
changeStatus = new ChangeStatus(context);
isChanged = changeStatus.makeChange(current.errandid,0 );
if(isChanged == true){
current.errandstatus = "Canceled";
myHolder.status.setText("status: " + current.errandstatus);
}
//return true;
}
if(menuId ==R.id.errand_reactivate){
Toast.makeText(context, " "+current.getErrandid(), Toast.LENGTH_LONG).show();
changeStatus = new ChangeStatus(context);
isChanged = changeStatus.makeChange(current.errandid, 1);
if(isChanged == true){
current.errandstatus = "Active";
myHolder.status.setText("status: " + current.errandstatus);
}
//return true;
}
return false;
}
});
popup.show();
}
});
OnMenuItemClick should forward the Item Id and the expected change; as either 1 for activate and 2 for cancel, to the backend API.enter image description here
Your current variable will be overridden at every onBindViewHolder call.
You should store the id with your ViewHolder, for example:
holder.options.setTag(position);
and then retrieve the position in the onclick method for example:
int pos = (int) v.getTag();
Hope it helps.
Related
I have one EditText (edModelColor). when user click on edModelColor(EditText) then the custom dialog will be called.Custom dialog consist of RecylerView and searchview and one custom row for each item. Custom row contains ImageView(icon), TextView (colorNames) and checkbox for selection. When user click on any checkbox I passed the colorName and its position in adapter into method checkAndRemove. this method will add or remove the color name according to its adapter position and the colorNames will added into edModelColor(EditText). its working fine but the problem is that once the user click on edModelColor(EditText) again, I want to checked those checkboxes which are already checked inside CustomDialogbox.I have seen some articles online but I could not understand what they meant.
bodyColorDialog:
private void bodyColorDialog() {
TextView txtClose;
TextView tvCancel;
Button btnOk;
bodyColorDialog.setContentView(R.layout.ed_body_color_dialog);
bodyColorDialog.setCancelable(false);
txtClose = bodyColorDialog.findViewById(R.id.txtModelClose);
tvCancel = bodyColorDialog.findViewById(R.id.tvCancel);
btnOk = bodyColorDialog.findViewById(R.id.btnOk);
edBodyColorSearchView = bodyColorDialog.findViewById(R.id.edBodyColorSearchViewColor);
edBodyColorRecylerView = bodyColorDialog.findViewById(R.id.edBodyColorRecylerView);
edBodyColorRecylerView.setLayoutManager(new LinearLayoutManager(getContext()));
bodyColorArrayList.clear();
setUpBodyColorArrayList();
btnOk.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
selectionCMap = new HashMap<>();
selectionCMap = edBodyColorAdapter.selectionColorsMap;
for(String value : selectionCMap.values()){
/* tv.setText(tv.getText() + "\n" + value);*/
edBodyColor.append(value + ",");
}
bodyColorDialog.dismiss();
}
});
txtClose.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
bodyColorDialog.dismiss();
}
});
tvCancel.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
bodyColorDialog.dismiss();
}
});
bodyColorDialog.show();
}
private void setUpBodyColorArrayList() {
bodyColorArrayList.clear();
String bodyColorName[] = getResources().getStringArray(R.array.body_color_array);
int bodyColorIcons[] = {R.drawable.red, R.drawable.black, R.drawable.violet, R.drawable.white,
R.drawable.orange, R.drawable.blue, R.drawable.green, R.drawable.yello};
for(int i =0; i < bodyColorIcons.length; i++)
{
bodyColorArrayList.add(new edModelBodyColor(bodyColorName[i], bodyColorIcons[i]));
}
edBodyColorAdapter = new edBodyColorAdapter(getContext(), bodyColorArrayList);
edBodyColorRecylerView.setAdapter(edBodyColorAdapter);
edBodyColorSearchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
#Override
public boolean onQueryTextSubmit(String queryString) {
edBodyColorAdapter.getFilter().filter(queryString);
return false;
}
#Override
public boolean onQueryTextChange(String queryString) {
edBodyColorAdapter.getFilter().filter(queryString);
return false;
}
});
}
edBodyColorAdapter.java
holder.checkBoxColor.setOnCheckedChangeListener(new
CompoundButton.OnCheckedChangeListener() {
#Override
public void onCheckedChanged(CompoundButton compoundButton, boolean isChecked) {
int position = holder.getAdapterPosition();
clickedColorNamePosition = edBodyColorArrayList.indexOf(filteredArrayList.get(position));
String name = edBodyColorArrayList.get(clickedColorNamePosition).getBodyColorName();
Toast.makeText(context, "name = " + name, Toast.LENGTH_SHORT).show();
//this mthod will check if selected checkbox value is already present or not.
// It present then remove ( means user unchecked box) and if value is not there means user has selected checkbox
checkAndRemove(position,name);
}
});
checkAndRemove:
private void checkAndRemove(int position, String name) {
if(selectionColorsMap.containsKey(position)){
selectionColorsMap.remove(position);
Toast.makeText(context, "removed", Toast.LENGTH_SHORT).show();
}else {
selectionColorsMap.put(position, name);
Toast.makeText(context, "added", Toast.LENGTH_SHORT).show();
}
}
preview:
Conculusion: I want to check these checkboxes values when user click again on edBodyColor dialog..
I as can see, you are initializing the ArrayList of colors every time you are showing the dialog, that's why, you start always at initial state.
Instead, you should initialized the ArrayList inside onCreate() and reuse it every time to maintain the previous state.
While debugging my app, I noticed that my RecyclerView display is inconsistent with the data provided, i.e.
If I set an alarm (TextView in RecyclerView has date set) then scroll my RecyclerView, the date shows up in the wrong positions e.g If I set the date on the 4th item, then the 3rd item also has the date set as well for some reason
I also noticed that at times, e.g. Only the 3rd and 5th -last items in the data set plays an animation while the 4th does not. I checked the logs, and it appears that onBindViewHolder() is not called for the 4th item, only 3rd and 5th. Am I doing something wrong here?
I have looked at the documentation, but am not sure how to patch accordingly. Can you help me?
My onBindViewHolder:
#Override
public void onBindViewHolder(final RecyclerVH recyclerVH, final int position) {
currentNote = data.get(position);
final String currentTitle = currentNote.getTitle();
final String currentContent = currentNote.getContent();
final int currentPosition = currentNote.getPosition();
String currentAlarmDate = currentNote.getAlarm();
Log.d("RecyclerView", "onBindVH called: " + currentTitle);
Log.d("RecyclerView", "Position at: " + currentPosition + " and Adapter Position at: " + recyclerVH.getAdapterPosition());
// final Info currentObject = data.get(position);
// Current Info object retrieved for current RecyclerView item - USED FOR DELETE
recyclerVH.listTitle.setText(currentTitle);
recyclerVH.listContent.setText(currentContent);
Log.d("RecyclerAdapter", "currentAlarmDate is: '" + currentAlarmDate + "'");
if (currentAlarmDate != null && !currentAlarmDate.equals(" ")) {
Log.d("RecyclerAdapter", "Current Alarm set for: " + currentAlarmDate);
recyclerVH.alarm.setText(currentAlarmDate);
}
recyclerVH.pencil.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Log.d("User Interface", "updateNoteInfo called!");
// Opens Dialog to update Note and Alarm
// TODO Open Activity instead
//final View updateButton;
// NEEDS TO BE DECLARED AT TOP, SO IT IS SEEN EVERYWHERE
updateDialog = new MaterialDialog.Builder(context)
.title(R.string.rewrite_note)
.customView(R.layout.note_update_screen, false)
.positiveText(R.string.update)
.negativeText(R.string.nevermind)
.forceStacking(false)
.cancelable(false)
.canceledOnTouchOutside(false)
.onPositive(new MaterialDialog.SingleButtonCallback() {
#Override
public void onClick(MaterialDialog dialog, DialogAction which) {
updatedTitle = updateTitle.getText().toString();
updatedContent = updateContent.getText().toString();
updateNote(updatedTitle, updatedContent, recyclerVH.getAdapterPosition());
}
})
.build();
//noinspection ConstantConditions
updateTitle = (EditText) updateDialog.getCustomView().findViewById(R.id.updateNoteTitle);
updateContent = (EditText) updateDialog.getCustomView().findViewById(R.id.updateNoteContent);
// Set the text for the title using current info
updateTitle.setText(currentTitle);
updateTitle.setSingleLine(false);
updateTitle.setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_FLAG_MULTI_LINE | InputType.TYPE_TEXT_FLAG_CAP_SENTENCES);
updateContent.setText(currentContent);
updateContent.setSingleLine(false);
updateContent.setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_FLAG_MULTI_LINE | InputType.TYPE_TEXT_FLAG_CAP_SENTENCES);
updateButton = updateDialog.getActionButton(DialogAction.POSITIVE);
// TODO Use do-while loop for onTextChanged?
// TODO Use Thread?
updateDialog.show();
// updateButton.setEnabled(false);
}
});
runEnterAnimation(recyclerVH.itemView, position);
}
since RecyclerView reuses or recycles the views, you must always add an else condition to make sure that it works properly. So, add an else block along with your if block.
Remove the setOnClickListener() from onBindViewHolder and set the setOnClickListener() inside your ViewHolder RecyclerVH. To get the position of the clicked item or row call the method getAdapterPosition(). Example:
public class ReservationViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener{
// each data item is just a string in this case
CardView cardView;
public ReservationViewHolder(View v) {
super(v);
cardView = (CardView) v.findViewById(R.id.cv);
cardView.setOnClickListener(this);
}
#Override
public void onClick(View v) {
int position = getAdapterPosition();
// do what you want...
}
}
How can i perform an Onclick functionality for right drawable?
I have a gridview item list in which i set a right drawable to each item so that when user input something in editText then that right drawable will show in background and that drawable is delete icon so i want to perform onClick listener for that drawable only so that when user taps on that delete drawble then action is performed. I write the following code but its not working
keywordslist.setOnTouchListener(new OnTouchListener() {
#Override
public boolean onTouch(final View v, MotionEvent event) {
if(event.getAction() == MotionEvent.ACTION_UP) {
if(event.getRawX() >= (keywordslist.getRight() - keywordslist.getPaddingRight())) {
new AlertDialog.Builder(context)
.setMessage("Remove " + ((TextView) v).getText().toString() + "?")
.setNeutralButton("No", null)
.setPositiveButton("Yes", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
DBkeyword dbkey = new DBkeyword(context);
SQLiteDatabase dbw = dbkey.getWritableDatabase();
String deleteKeyword = "delete from " + "screenedkeywords" + " where " + "keywords" + " = \"" + ((TextView) v).getText().toString() + "\"";
dbw.execSQL(deleteKeyword);
dbw.close();
DisplayKeywords();
}
});
return true;
}
}
return false;
}
});
You have to notify your adapter that the data has changed.
customGridAdapter.notifyDataSetChanged();
I'm not 100 % sure, but shouldn't there be a
ArrayAdapter.getItemCount()
Maybe you didn't change the returning value from 0 to data.size().
I am trying to delete several items from my listview but it just deletes one element(even though i select more than one). The listview implements android.R.layout.simple_list_item_multiple_choice which has delListView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE). I have a button where in the onClick method i would first like to check if there are no items selected if so prompt the user with some message. Else if there are some items selected delete them. This is what i have so far:
public void onClick(View v) {
// TODO Auto-generated method stub
selectItems();
Intent intent = new Intent(); ...
}
selectItems function:
private boolean selectItem()
{
String message = "Please select an item!";
for (int i = 0; i < array.size(); i++)
{
if(array.valueAt(i))
{
String item = delListView.getAdapter().getItem(array.keyAt(i)).toString();
Log.i("my_app", item + " selected");
deleteAdapter.remove(item);
deleteAdapter.notifyDataSetChanged();
return false; //item found
}
}
Toast.makeText(getApplicationContext(), message, Toast.LENGTH_SHORT).show();
return true; //no item found
}
Thank you for your help!
I have managed to solve my problem. My solution was:
private void deleteItems() {
// TODO Auto-generated method stub
for (int i = (array.size()) - 1; i >= 0; i--)
{
if(array.valueAt(i))
{
String selected = deleteAdapter.getItem(array.keyAt(i));
Log.i("my_app", selected + " will be selected");
deleteAdapter.remove(selectat);
}
}
Intent intent = new Intent();
intent.putStringArrayListExtra(BUNDLE_DELETE, deleteList);
setResult(REQUEST_CODE_DELETE_STRING, intent);
getInstance().finish();
}
private boolean selectItem()
{
String message = "Please select an item!";
for (int i = 0; i < array.size(); i++)
{
if(array.valueAt(i))
{
String item = delListView.getAdapter().getItem(array.keyAt(i)).toString();
Log.i("my_app", item + " selected");
deleteItems();
return false;
}
}
Toast.makeText(getApplicationContext(), message, Toast.LENGTH_SHORT).show();
return true;
}
I made a separate method for selecting the items and deleting them. Then i simply called the delete method in the selectItem(). In the onClick method i called the selectItem() method.
Thank you all for your help! :)
Notifydata set changed after all your items have been removed from the data map.
1) In onClick() call ListView.getCheckedItemPositions() to get the positions of the selected items in the list or ListView. getCheckedItemIds() to get the Id's of the selected items.
2) Then delete them.
3) Then call notifyDataSetChanged() on the Adapter to cause the list to be refreshed.
try something like this:
see an example :(Portuguese Link) http://nglauber.blogspot.com.br/2013/07/listview-com-selecao-multipla-actionbar.html
private boolean selectItem() {
String item = delListView.getAdapter().getItem(array.keyAt(i)).toString();
SparseBooleanArray checked = listView.getCheckedItemPositions();
for (int i = checked.size()-1; i >= 0; i--) {
if (checked.valueAt(i)) {
String item = delListView.getAdapter().getItem(checked.valueAt(i)).toString();
deleteAdapter.remove(item);
}
}
deleteAdapter.notifyDataSetChanged();
Toast.makeText(getApplicationContext(), message, Toast.LENGTH_SHORT).show();
return true; //no item found
}
Edited:
I first want to verify(when
pressing a button) if there are no items selected.
mButton.setOnClickListener( new OnClickListener() {
#Override
public void onClick( final View v ) {
SparseBooleanArray checked = listView.getCheckedItemPositions();
if ( checked.size() == 0 ) {
Toast.makeText(getApplicationContext(), message, Toast.LENGTH_SHORT).show();
}
}
} );
I'm new in android .I'm working with gallary.I would like to know how to save previous button state when I click on next gallery item.I want to make default button state off on all images and when button state will select with image it shoud be safe when I click on next one.When I come back on previous image it shoud be show saving button state .I tried to compare image id and button selected image id.But that's not really good work .How to do this?Thanks a lot for feature help.
imageView = (ImageView) findViewById(R.id.ImageSportView);
imageView.setImageResource(imgID[0]);
sportButton = (Button) findViewById(R.id.SportButton1);
gallery = (Gallery) findViewById(R.id.SportGallery);
// creating AddImgadapter
gallery.setAdapter(new AddImgAdapter(this));
#Override
public void onItemClick(AdapterView<?> perent, View view,
int position, long id) {
// getting id position
setSelected(position);
// deselect button on item click
onImageClick(view, position);
Log.d(MY_LOG, "img click");
Log.d(MY_LOG, "img Id" + position);
}
});
}
// deselect button on image click
int itemPosition = 1;
public void onImageClick(View button, int position) {
itemPosition = position;
if (selectedPosition != position) {
sportButton.setSelected(false);
Log.d(MY_LOG, "selected postion " + selectedPosition + " = "
+ "item position" + position);
} else {
if (selectedPosition == position) {
sportButton.setSelected(true);
}
Log.d(MY_LOG, "selected postion " + selectedPosition + " = "
+ "item position " + position);
}
}
// getting Id current item
int selectedPosition = -1;
private void setSelected(int position) {
selectedPosition = position;
imageView.setImageResource(imgID[selectedPosition]);
}
public void onClickButton(View button) {
if (button.isSelected()) {
button.setSelected(false);
Log.d(MY_LOG, "click off");
} else {
// on button click on we select picture id
button.setSelected(true);
if (selectedPosition != -1) {
Log.d(MY_LOG, "selected position " + selectedPosition);
//selectedImage(selectedPosition);
//Intent intent = new Intent(Sport.this, Favorites.class);
}
Log.d(MY_LOG, "click on");
}
}
One way to save the state of the previous button would be to make use of shared preferences in Android . Shared preferences allow key value pairs of data to be stored which can be later retrieved easily . There are one of the dataaccess mechanisms in Android . Others being SqlLite Database & Files .
Android Documentation on Share preference
Video on shared preference
Now coming back to your problem again . I once had to save the state of a checkedbutton . Then later access it again ( which seems to be similar to what you want to do as well )
Part 1 Accessing Share preference Values :
public static final String PREFS_FILE = "MyPreferences";
public static final String PREFS_NAME = "USER_NAME";
public static final String PREFS_CHOICE = "USER_CHOICE";
SharedPreferences sp;
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
chkChoice = (CheckBox)findViewById(R.id.chkChoice);
btnMain = (Button)findViewById(R.id.btnMain);
btnMain.setOnClickListener(this);
// Here i access the shared preference file .
sp = this.getSharedPreferences(PREFS_FILE, MODE_PRIVATE);
// If i have a preference for my checkbox saved then load it else FALSE(unchecked)
chkChoice.setChecked(sp.getBoolean(PREFS_CHOICE, false));
}
Part 2 Setting Share preference from your activity :
sp = this.getSharedPreferences(PREFS_FILE, MODE_PRIVATE);
SharedPreferences.Editor editor = sp.edit();
editor.putString(PREFS_NAME, txtName.getText().toString());
editor.putBoolean(PREFS_CHOICE, chkChoice.isChecked());
editor.commit();
// Close the activity to show that the data is still saved
finish();
The above is for a checkbox . You will have to adapt it for the kind of button information you want to save . Hope this gets you started .