I have an app (based on this tutorial), and it has an activity that allows user to choose several friends to send messages to. Now, I also have the check icon in the upper right corner. When the user clicks on it, selected contacts are sent to parent activity. When the user clicks on a contact in recyclerview, contact's status changes from unselected to selected and vice versa.
Most tutorials and stack overflow answers suggest changing the toolbar on long click, but what I want to do is change it on recyclerview item click, ie. when the user clicks on recyclerview item I want to show the check button if the number of selected users is not 0 (selectedContacts != null), and hide the button if it is 0. I would also like to show hide it when the user starts the activity, based on the same condition. As I said, I have looked at a lot of SO answers, but I couldn't find any that worked for me. Some of the answers I tried: this, this, this, this, this, this...
This is what it looks like:
activity_choose_contacts_action.xml:
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item
android:id="@+id/add"
android:icon="@drawable/ic_icon_check_white"
android:title="@string/add"
app:showAsAction="always" />
</menu>
choose_contacts.xml:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".contactprofile.ChooseContactsActivity">
<android.support.v7.widget.Toolbar
android:id="@+id/chooseContactsToolbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/ppdColorOrange"
android:fitsSystemWindows="true"
android:minHeight="?attr/actionBarSize"
app:theme="@style/ToolbarWhiteBackArrow">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:id="@+id/selectContactTextView"
style="@style/TextAppearance.AppCompat.Widget.ActionBar.Title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/select_contacts"
android:textColor="@color/white" />
</RelativeLayout>
</android.support.v7.widget.Toolbar>
<android.support.v7.widget.RecyclerView
android:id="@+id/contacts_list"
android:layout_width="fill_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:divider="@color/list_divider"
android:dividerHeight="1dp"
app:srcCompat="@drawable/ic_icon_user" />
</LinearLayout>
ChooseContactsActivity.java:
adapter = new ChooseContactsAdapter(contactList, getApplicationContext());
recyclerView.setAdapter(adapter);
recyclerView.addOnItemTouchListener(new RecyclerTouchListener(getApplicationContext(), recyclerView, new ChooseContactsActivity.ClickListener() {
@Override
public void onClick(View view, int position) {
if (selectedContacts != null) {
addContacts.setImageResource(R.drawable.ic_icon_check_white);
} else {
addContacts.setVisibility(View.GONE);
}
}
@Override
public void onLongClick(View view, int position) {
}
}));
recyclerView.addOnItemTouchListener(new RecyclerTouchListener(getApplicationContext(), recyclerView, new ChooseContactsActivity.ClickListener() {
@Override
public void onClick(View view, int position) {
}
@Override
public void onLongClick(View view, int position) {
}
}));
........
Call<ContactsResponse> call = apiService.getMyContact(userId);
call.enqueue(new Callback<ContactsResponse>() {
@Override
public void onResponse(Call<ContactsResponse> call, retrofit2.Response<ContactsResponse> response) {
List<Contact> contact = response.body().getResults();
contactList.addAll(contact);
adapter.notifyDataSetChanged();
RecyclerView recyclerView = findViewById(R.id.contacts_list);
// Checking previously selected contacts
if (selectedContacts != null) {
new Handler(Looper.getMainLooper()).postDelayed(() -> {
List<Integer> selectedIndexes = new ArrayList<>();
// Finding indexes of selected contact ids
for (int i = 0; i < contactList.size(); i++) {
if (selectedContacts.contains(contactList.get(i).getUserId())) {
selectedIndexes.add(i);
}
}
// Triggering click on each selected item
for (int j = 0; j < selectedIndexes.size(); j++) {
recyclerView.getChildAt(selectedIndexes.get(j)).performClick();
}
}, 500);
}
}
........
interface ClickListener {
void onClick(View view, int position);
void onLongClick(View view, int position);
}
private static class RecyclerTouchListener implements RecyclerView.OnItemTouchListener {
private GestureDetector gestureDetector;
private ChooseContactsActivity.ClickListener clickListener;
RecyclerTouchListener(Context context, final RecyclerView recyclerView, final ChooseContactsActivity.ClickListener clickListener) {
this.clickListener = clickListener;
gestureDetector = new GestureDetector(context, new GestureDetector.SimpleOnGestureListener() {
@Override
public boolean onSingleTapUp(MotionEvent e) {
return true;
}
@Override
public void onLongPress(MotionEvent e) {
View child = recyclerView.findChildViewUnder(e.getX(), e.getY());
if (child != null && clickListener != null) {
clickListener.onLongClick(child, recyclerView.getChildLayoutPosition(child));
}
}
});
}
@Override
public boolean onInterceptTouchEvent(RecyclerView rv, MotionEvent e) {
View child = rv.findChildViewUnder(e.getX(), e.getY());
if (child != null && clickListener != null && gestureDetector.onTouchEvent(e)) {
clickListener.onClick(child, rv.getChildLayoutPosition(child));
}
return false;
}
@Override
public void onTouchEvent(RecyclerView rv, MotionEvent e) {
}
@Override
public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) {
}
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.activity_choose_contacts_action, menu);
if (getSupportActionBar() != null) {
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
}
getSupportActionBar().setDisplayShowHomeEnabled(true);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case android.R.id.home:
finish();
return true;
case R.id.add:
ArrayList<String> selectedIds = adapter.selectedIds;
String text = "abc";
Intent intent = new Intent();
intent.putStringArrayListExtra("contacts_added", selectedIds);
setResult(RESULT_OK, intent);
finish();
return true;
}
return super.onOptionsItemSelected(item);
}
ContactsAdapter.java:
holder.itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// toggle selection
toggleSelection(position);
// Change background color of the selected items in list view
holder.itemView.setBackgroundColor(selectedItems.get(position) ? context.getResources().getColor(R.color.ppdColorOrangeSelection) : Color.TRANSPARENT);
if (position != RecyclerView.NO_POSITION) {
Contact contact = contactList.get(position);
applyIconAnimation(holder, position);
String userId = contact.getUserId();
if (!selectedIds.contains(userId)) {
selectedIds.add(userId);
} else {
selectedIds.remove(userId);
}
}
applyIconAnimation(holder, position);
getSelectedItemCount();
getSelectedItems();
resetAnimationIndex();
getSelectedItemCount();
}
});
}
@Override
public int getItemViewType(int position) {
return position;
}
private void applyProfilePicture(ChooseContactsViewHolder holder, Contact contact) {
Picasso.with(context)
.load(AppConfig.URL_PROFILE_PHOTO + contact.getThumbnailUrl())
.placeholder(textDrawable)
.error(textDrawable)
.transform(new CircleTransform())
.into(holder.thumbNail);
}
private void applyIconAnimation(ChooseContactsViewHolder holder, int position) {
if (selectedItems.get(position, false)) {
holder.iconFront.setVisibility(View.GONE);
resetIconYAxis(holder.iconBack);
holder.iconBack.setVisibility(View.VISIBLE);
holder.iconBack.setAlpha(1);
if (currentSelectedIndex == position) {
FlipAnimator.flipView(context, holder.iconBack, holder.iconFront, true);
resetCurrentIndex();
}
} else {
holder.iconBack.setVisibility(View.GONE);
resetIconYAxis(holder.iconFront);
holder.iconFront.setVisibility(View.VISIBLE);
holder.iconFront.setAlpha(1);
if ((reverseAllAnimations && animationItemsIndex.get(position, false)) || currentSelectedIndex == position) {
FlipAnimator.flipView(context, holder.iconBack, holder.iconFront, false);
resetCurrentIndex();
}
}
}
private void toggleSelection(int pos) {
currentSelectedIndex = pos;
if (selectedItems.get(pos, false)) {
selectedItems.delete(pos);
animationItemsIndex.delete(pos);
} else {
selectedItems.put(pos, true);
animationItemsIndex.put(pos, true);
}
//notifyItemChanged(pos);
}
private void clearSelections() {
reverseAllAnimations = true;
selectedItems.clear();
notifyDataSetChanged();
}
@Override
public int getItemCount() {
return contactList.size();
}
private int getSelectedItemCount() {
return selectedItems.size();
}
private List<Integer> getSelectedItems() {
List<Integer> items =
new ArrayList<>(selectedItems.size());
for (int i = 0; i < selectedItems.size(); i++) {
items.add(selectedItems.keyAt(i));
}
return items;
}
So I found a solution. I added this:
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.activity_choose_contacts_action, menu);
if (adapter.getSelectedItemCount() == 0) {
menu.findItem(R.id.add).setVisible(false);
} else {
menu.findItem(R.id.add).setVisible(true);
}
if (getSupportActionBar() != null) {
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
}
getSupportActionBar().setDisplayShowHomeEnabled(true);
return true;
}
.....
// Checking previously selected contacts
if (selectedContacts != null) {
new Handler(Looper.getMainLooper()).postDelayed(() -> {
List<Integer> selectedIndexes = new ArrayList<>();
// Finding indexes of selected contact ids
for (int i = 0; i < contactList.size(); i++) {
if (selectedContacts.contains(contactList.get(i).getUserId())) {
selectedIndexes.add(i);
}
}
// Triggering click on each selected item
for (int j = 0; j < selectedIndexes.size(); j++) {
recyclerView.getChildAt(selectedIndexes.get(j)).performClick();
}
invalidateOptionsMenu();
}, 500);
......
@Override
public void onClick(View view, int position) {
// invalidateOptionsMenu(); (resetting onCreateOptionsMenu) executed with 600 millis delay, otherwise it will happen before the 500 millis
// delay when checking previously selected contacts
new Handler(Looper.getMainLooper()).postDelayed(() -> invalidateOptionsMenu(), 600);
}