I have a RecyclerView who play the recording when certain item is clicked. I want the behave when a user clicks on item1 that specific recording is playing and button View is changed which is working fine.
But at the same time when item1 recording is playing and user click on item2 then item1 row Button come back to its original position.
Below Image show the View when item1(Row 1) is clicked. (This is working fine)
I have also test this to control the View in inBindViewHolder method.But it is not working because whenever I clicked holder object control the View of current selected row only.
Below Code Section is placed in the ViewHolder
mPlayAudio.setOnClickListener(new View.OnClickListener()
{
#Override
public void onClick(View view)
{
Log.d(TAG, "onClick: Present in onClick mPlayAudio");
if (listener != null)
{
final int position = getAdapterPosition();
if (position != RecyclerView.NO_POSITION)
{
// This section contain the code to play and stop
the audio
// Using below line I only able to change selected
// row button View not other row Button View
mPlayAudio.setImageResource(R.drawable.play);
}
}
}
});
I have also try this with in onBindViewHolder method but still not working.
Below Code added in onBindViewHolder
holder.mPlayAudio.setOnClickListener(new View.OnClickListener(){
#Override
public void onClick(View view)
{
// This section contain code to play and stop audio
//Using below statement I only able to change the
//visibility of current selected row View not others
holder.mPlayAudio.setImageResource(R.drawable.play);
}
}
So I finally was able to try this out on my own project.
Answer
In BindViewHolder, after you have made an item click, save the value of the position of that item. Then call notifyDataSetChanged inside the click event, which will refresh the adapter. Now it obtain your result, inside BindViewHolder have an if statement checking if that value should be set accordingly (or invisible), otherwise display as visible.
Example Code
public class SelectorAdapter extends RecyclerView.Adapter<SelectorAdapter.ItemHolder> implements View.OnClickListener {
private List itemList;
private int selectedKey;
public SelectorAdapter(List list) {
itemList = list;
}
#Override
public void onClick(View v) {
}
/* ViewHolder for each item */
class ItemHolder extends RecyclerView.ViewHolder {
//title
#BindView(R.id.selector_title)
TextView title;
#BindView(R.id.selector_layout)
LinearLayout selector;
ItemHolder(View itemView) {
super(itemView);
ButterKnife.bind(this, itemView);
}
}
#Override
public ItemHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View itemView = LayoutInflater.from(parent.getContext())
.inflate(R.layout.item_layout_selector, parent, false);
return new ItemHolder(itemView);
}
#Override
public void onBindViewHolder(ItemHolder holder, int position) {
String title = (String) itemList.get(position);
holder.title.setText(title);
if (position != selectedKey) {
holder.title.setBackgroundResource(R.drawable.selector);
} else {
holder.title.setBackgroundResource(R.drawable.selector_selected);
}
holder.itemView.setOnClickListener(v -> {
Timber.e("selected item: %s", position);
selectedKey = position;
notifyDataSetChanged();
});
}
#Override
public int getItemCount() {
Timber.e("itemCount: %s", itemList.size());
return itemList.size();
}
}
Here is my own project where when I select an item, it changes the background resource to selected, and then the rest are returned to the default state.
Related
I have a validate button inside each item of a recyclerView in order to change the color to green of the current item. When a new item is added in the recyclerview , I want to set the default background (no background color).
I've tried inside the BindView(position) function so by default when a new item is added in the itemsList, the color of the current element (item 0) is green whether I clicked on validate or not and that's not what I want.
I've also tried in the onBindViewHolder function but it doesnt work.
How can I change the color of this item in this recyclerview and this color remains the same whithout considering the index changing in the List if a new item is added?
I want that each new item of this recyclerview to be in the default color (background color white or no background color) and the item +n to be in the color of the corresponding status (validated = green , reschedulded = grey)
Once the validated button has been clicked I want the item to remains in read only mode.
Here is the code :
The adapter:
private Context context;
private List<RideObject> itemList;
public TestListeAdapter(List<RideObject> itemList, Context context) {
this.itemList = itemList;
this.context = context;
}
#NotNull
#Override
public TestListeAdapter.TestListeViewHolders onCreateViewHolder(ViewGroup parent, int viewType) {
View layoutView = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_testliste, null, false);
RecyclerView.LayoutParams lp = new RecyclerView.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
layoutView.setLayoutParams(lp);
return new TestListeAdapter.TestListeViewHolders(layoutView);
}
#RequiresApi(api = Build.VERSION_CODES.M)
#Override
public void onBindViewHolder(#NotNull TestListeAdapter.TestListeViewHolders holder, final int position) {
holder.bindView(position);
if (holder.validated){
holder.mCard.setCardBackgroundColor(ContextCompat.getColor(context.getApplicationContext(), R.color.teal_700));
}
the viewholder Class :
class TestListeViewHolders extends RecyclerView.ViewHolder {
//MyClickListener listener;
TextView rideId;
ImageView mCheck;
ImageView mreschedulded;
CardView mCard;
TestListeViewHolders(View itemView) {
super(itemView);
mCheck = itemView.findViewById(R.id.validate);
mreschedulded= itemView.findViewById(R.id.reschedulded);
mCard = itemView.findViewById(R.id.card_view);
}
private void bindView(int pos) {
RideObject item = itemList.get(pos);
mCheck.setOnClickListener(view -> {
item.setRDVHour(timePicker.getHour());
item.setRDVMinute(timePicker.getMinute());
validated = true;
item.setValider(true);
item.confirmDriver();
//if (itemList.size() == 1){
//mCard.setCardBackgroundColor(ContextCompat.getColor(context.getApplicationContext(), R.color.teal_700));
//itemView.setBackgroundColor(ContextCompat.getColor(context.getApplicationContext(),R.color.teal_700));
});
mreschedulded.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
timePicker.setEnabled(true);
itemView.setBackgroundColor(ContextCompat.getColor(context.getApplicationContext(),R.color.grey));
}
});
}
}
In the MainActivity:
resultsTestList.add(0, mCurrentRide);
mTestListAdapter.notifyDataSetChanged()
Ive tried the code in the answer but it doesnt work . Currently, the setbackgroundcolor applies just to the first element of the list. I would want that if the first element (item0) goes to second element (item1) the item keep his color background which is not the case with the given answer code
When binding RecyclerView items, you have to think of it as that you need to change the ViewHolder completely disregarding the previous state.
The view holder should not hold key information like validated.
Whether the view holder stays in the validated state or not should depend on the item it is being bind to.
#RequiresApi(api = Build.VERSION_CODES.M)
#Override
public void onBindViewHolder(#NotNull TestListeAdapter.TestListeViewHolders holder, final int position) {
holder.bindView(position);
}
...
private void bindView(int pos) {
RideObject item = itemList.get(pos);
if (item.validated) {
mCard.setCardBackgroundColor(...R.color.teal_700));
else {
mCard.setCardBackgroundColor(...R.color.grey));
mCheck.setOnClickListener(view -> {
item.setRDVHour(timePicker.getHour());
item.setRDVMinute(timePicker.getMinute());
item.validated = true;
item.setValider(true);
item.confirmDriver();
});
mReschedulded.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
timePicker.setEnabled(true);
itemView.setBackgroundColor(ContextCompat.getColor(context.getApplicationContext(),R.color.grey));
}
});
}
}
I need to create an algorithm that set a checked item in a RecyclerView. I have a RecyclerView made with boxes with a TextView and an ImageView, I use the TextView to show nameItems from a List and the ImageView to show a check once the user clicks on it.
What I want to do is that every time the user clicks on an item the check appears and every time he clicks on a checked Item the check disappears.
I create an algorithm which uses a boolean variable (isChecked) set to false, every time user clicks on an item the variable is set to true and vice versa.
In this case, a user has to click on the next item of the list two times to let show the check.
How can I do it?
Thank you so much in advance
Here is my Adapter's class:
public class RecyclerTypeListViewAdapter extends RecyclerView.Adapter<RecyclerTypeListViewAdapter.TypeViewHolder> {
List<TipologiaEvento> eventType;
private boolean isChecked = false;
public RecyclerTypeListViewAdapter (List<TipologiaEvento> typeList){
this.eventType = typeList;
}
public static class TypeViewHolder extends RecyclerView.ViewHolder {
LinearLayout linearLayout;
TextView typeName;
ImageView check_icon;
TypeViewHolder (View view){
super(view);
linearLayout = view.findViewById(R.id.type_listed_linear_layout);
typeName = view.findViewById(R.id.event_type_text_view);
check_icon = view.findViewById(R.id.event_type_checked_icon);
}
}
#Override
public TypeViewHolder onCreateViewHolder(ViewGroup viewGroup, int viewType) {
View view = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.cell_type_listed, viewGroup, false);
TypeViewHolder tvh = new TypeViewHolder(view);
return tvh;
}
#Override
public void onBindViewHolder(final TypeViewHolder typeViewHolder, int position) {
typeViewHolder.typeName.setText(eventType.get(position).getDescrizione());
typeViewHolder.linearLayout.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if(isChecked == false) {
typeViewHolder.check_icon.setVisibility(View.VISIBLE);
Toast.makeText(v.getContext(), "Aggiunto: " + typeViewHolder.typeName.getText().toString(), Toast.LENGTH_SHORT).show();
isChecked = true;
} else {
typeViewHolder.check_icon.setVisibility(View.INVISIBLE);
Toast.makeText(v.getContext(), "Rimosso: " + typeViewHolder.typeName.getText().toString(), Toast.LENGTH_SHORT).show();
isChecked = false;
}
}
});
}
}
Just take one boolean value in the model class of your list. and in bindviewholder.
just put the condition like below
if(list.get(position).ischecked()) {
action of checked
} else {
action of unchecked
}
and on the click of the item you just have to change the flag of object and notify the adapter.
I have ImageView inside of an item in a RecyclerView. Every time I click on an item, I want the image to become visible and the previous clicked item's image becomes invisible.
public static class MyHolder extends RecyclerView.ViewHolder {
private ImageView image_view;
private TextView text_view_name;
private TextView text_view_abilities;
private ImageView heart_image_view;
public MyHolder(#NonNull final View itemView, final OnItemClickListener listener) {
super(itemView);
image_view = itemView.findViewById(R.id.image_view);
text_view_name = itemView.findViewById(R.id.text_view_name);
text_view_abilities = itemView.findViewById(R.id.text_view_abilities);
heart_image_view = itemView.findViewById(R.id.heart_image_view);
heart_image_view.setImageResource(R.drawable.heart);
heart_image_view.setVisibility(View.GONE);
itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (listener != null) {
int position = getAdapterPosition();
if (position != RecyclerView.NO_POSITION) {
listener.onItemClick(position);
heart_image_view.setVisibility(View.VISIBLE);
}
}
});
}
}
#NonNull
#Override
public MyHolder onCreateViewHolder(#NonNull ViewGroup viewGroup, int i) {
View v = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.single_item_layout, viewGroup, false);
MyHolder holder = new MyHolder(v, mlistener);
return holder;
}
#Override
public void onBindViewHolder(#NonNull MyHolder myHolder, int position) {
Item item = myList.get(position);
myHolder.text_view_name.setText(item.getTitle());
stringArray = item.getAbilitiesObj();
StringBuilder builder = new StringBuilder();
for (int i = 0; i < stringArray.size(); i++) {
try {
builder.append(stringArray.get(i));
builder.append(", ");
} catch (NumberFormatException ex) {
ex.printStackTrace();
}
myHolder.text_view_abilities.setText(builder);
}
if (myHolder.image_view != null) {
String photoUrl = item.getImageUrl();
Picasso.with(mContext).load(photoUrl).into(myHolder.image_view);
}
}
In MyHolder class where item.setOnClick, I set the clicked item image visible but then every time I click on another item, the image of the new item becomes visible and the image of the previous item does not get invisible.
You need to have another array of integers in your adapter to keep track of the items which is clicked. At first, initialize the array of integers with all ones.
// Define an array like the following in your adapter
private int[] selectedItems = new int[yourDataList.size()]; // Initialize the array to have the same size as your data list.
Then initialize the array with all ones. Try having a function like this in your adapter.
private void initializeSeledtedItems() {
for(int item : selectedItems) item = 1;
}
Now in your onBindViewHolder, set the visibility of the ImageView in your RecyclerView items based on the value found in the selectedItems array.
if(selectedItems[position] == 1) heart_image_view.setVisibility(View.VISIBLE);
else heart_image_view.setVisibility(View.GONE);
In the onClickListener modify the selectedItems array as such that, only the item selected has the value one and all the others have zeros. Then call notifyDataSetChanged to take your changes into effect.
private void setSelectedItem(int position) {
for(int i = 0; i < selectedItems.length(); i++) {
if(i == position) selectedItems[i] = 1;
else selectedItems[i] = 0;
}
}
itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (listener != null) {
int position = getAdapterPosition();
if (position != RecyclerView.NO_POSITION) {
setSelectedItem(position);
notifyDataSetChanged();
}
}
}
});
Hope that helps!
My code is for setting Visibility on recycler view's item , when you click on recycler views item it set VISIBLE on that particular item and INVISIBLE on other items.
this code works for me for setting visibility on clicked item and hiding previous icon.
initialize
int selecteditem =0;
onBindViewHolder
if(selecteditem==position){
holder.icSelect.setVisibility(View.VISIBLE);
}
else{
holder.icSelect.setVisibility(View.INVISIBLE);
}
holder.itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
selecteditem=position;
holder.icselect.setVisibility(View.VISIBLE);
notifyDataSetChanged();
}
});
i uploaded image for basic idea .
enter image description here
I have a fragment, ButtonSharingFragment, whose layout is called sharing_buttons.xml, it consists of 3 buttons.
I embed it in my NewContact activity with, in the layout of NewContact:
<fragment
android:name="com.example.chris.tutorialspoint.ButtonSharingFragment"
android:id = "#+id/myFragment"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
/>
My App loads up fine, I see the fragment where it is supposed to be. But I am trying to change the colour of one of the buttons in the fragment, when all checkboxes in my recyclerView are unchecked. The recyclerView is in my activity, NewContact. Can you tell me how to do this?
Here is my ButtonSharingFragment code:
public class ButtonSharingFragment extends Fragment{
Button phoneContacts;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup parent, Bundle savedInstanceState) {
// Defines the xml file for the fragment
View buttonView = inflater.inflate(R.layout.sharing_buttons, parent, false);
//return inflater.inflate(R.layout.sharing_buttons, parent, false);
phoneContacts = (Button) buttonView.findViewById(R.id.btnPhoneContacts);
// Defines the xml file for the fragment
return buttonView;
}
}
And the OnBindViewHolder of my adapter, when a checkbox is clicked. What goes into if(count==0) { } ?
#Override
public void onBindViewHolder(final RecyclerView.ViewHolder viewHolder, final int position) {
//The number of rows will match the number of phone contacts
final SelectPhoneContact selectPhoneContact = theContactsList.get(position);
//in the title textbox in the row, put the corresponding name etc...
((MatchingContact) viewHolder).title.setText(selectPhoneContact.getName());
((MatchingContact) viewHolder).phone.setText(selectPhoneContact.getPhone());
((MatchingContact) viewHolder).check.setChecked(theContactsList.get(position).getSelected());
((MatchingContact) viewHolder).check.setTag(position);
((MatchingContact) viewHolder).check.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
//pos is the row number that the clicked checkbox exists in
Integer pos = (Integer) ((MatchingContact) viewHolder).check.getTag();
//NEED THIS TO PRESERVE CHECKBOX STATE
if (theContactsList.get(pos).getSelected()) {
theContactsList.get(pos).setSelected(false);
} else {
theContactsList.get(pos).setSelected(true);
}
//we want to keep track of checked boxes, so when it is '0'
//'Phone Contacts' button in ButtonSharingFragment will change
//HOW TO DO THIS?
int count;
count = 0;
int size = theContactsList.size();
for (int i = 0; i < size; i++) {
if (theContactsList.get(i).isSelected) {
count++;
}
}
Log.i("MyMessage","The count is " + count);
//if 'count' is 0, then change button colour in ButtonSharingFragment fragment
if (count==0){
//CHANGE COLOUR OF phoneContacts button in ButtonSharingFragment
//have tried interface/callback etc, must be doing it wrong
}
}
});
}
EDIT: Modified my code to look like below, but am getting NullPointerException.
I have created a java class called UpdateColorCallback :
public interface UpdateColorCallback {
void onUpdateColorCallback();
}
In my adapter I have included:
public class PopulistoContactsAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder > {
private UpdateColorCallback updateColorCallback;
public void setUpdateLisenter(UpdateColorCallback updateColorCallback) {
this.updateColorCallback = updateColorCallback;
}
And in my ButtonSharingFragment:
public class ButtonSharingFragment extends Fragment implements UpdateColorCallback {
RecyclerView recyclerView;
Button publicContacts;
Button phoneContacts;
Button justMeContacts;
// ArrayList called selectPhoneContacts that will contain SelectPhoneContact info
ArrayList<SelectPhoneContact> selectPhoneContacts;
// The onCreateView method is called when Fragment should create its View object hierarchy,
// either dynamically or via XML layout inflation.
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup parent, Bundle savedInstanceState) {
PopulistoContactsAdapter adapter = new PopulistoContactsAdapter(selectPhoneContacts, getActivity());
adapter.setUpdateListener(this);
View buttonView = inflater.inflate(R.layout.sharing_buttons, parent, false);
//return inflater.inflate(R.layout.sharing_buttons, parent, false);
//for the Public, phoneContacts, justMe, save and cancel buttons
publicContacts = (Button) buttonView.findViewById(R.id.btnPublic);
phoneContacts = (Button) buttonView.findViewById(R.id.btnPhoneContacts);
justMeContacts = (Button) buttonView.findViewById(R.id.btnJustMe);
// Defines the xml file for the fragment
return buttonView;
}
#Override
public void onUpdateColorCallback() {
// TODO: Implement this
//Toast.makeText(getActivity(), "yes, this is working now"", Toast.LENGTH_SHORT).show();
Log.i("MyMessage","yes, this is working now");
}
}
Well, you need to make interface first then pass reference from fragment to adapter. Now when you want to change color or when you match your condition then you need to call.
Make Interface :-
public interface UpdateColorCallback {
void onUpdateColorCallback();
}
Now you need to implement into your fragment
public class ButtonSharingFragment extends Fragment implement UpdateColorCallback{
Button phoneContacts;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup parent, Bundle savedInstanceState) {
// Defines the xml file for the fragment
View buttonView = inflater.inflate(R.layout.sharing_buttons, parent, false);
//return inflater.inflate(R.layout.sharing_buttons, parent, false);
// pass this from here to adapter
adapter.setUpdateLisenter(this);
phoneContacts = (Button) buttonView.findViewById(R.id.btnPhoneContacts);
// Defines the xml file for the fragment
return buttonView;
}
#Override
public void onUpdateColorCallback() {
//change button color
}
}
Adapter code:-
private UpdateColorCallback updateColorCallback;
public void setUpdateLisenter(UpdateColorCallback updateColorCallback) {
this.updateColorCallback = updateColorCallback;
}
#Override
public void onBindViewHolder(final RecyclerView.ViewHolder viewHolder, final int position) {
// when ur condition meet then
if(updateColorCallback != null) {
// this call back call fragment
updateColorCallback. onUpdateColorCallback();
}
}
You can pass the Button instance to your adapter class from fragment and change the button state in the adapter,like:
adapter =new ButtonAdapter(button);
then in the adapter :
Button button1;
ButtonAdapter(Button button)
{
button1=button;
}
if (count==0){
button1.setBackgroundColor(getResources().getColor(R.color.white,null));
}
I have a PopupWindow that contains a RecyclerView. The RecyclerView's last element is a button that adds a new item to the end of the adapter's list when clicked.
The problem:
During the first time my PopupWindow has been launched the button successfully adds new items to the RecyclerView with notifyItemInserted(dataSize - 1) when clicked, but the RecyclerView doesn't update and show them. If I close and re-open the PopupWindow however, the items previously added are properly shown in the RecyclerView and it properly updates and animates new items being added to its adapter.
The Question: I'm not sure why the RecyclerView doesn't refresh and show the newly added items on first run of the PopupWindow, but works perfectly from second run onward. How do I make it work during the first run of the PopupWindow?
P.S. Its worth noting that if I use notifyDataSetChanged() the RecyclerView works correctly (displays new items) even on first launch of the PopupWindow. I want to find a way to make notifyItemInserted() work however, because it has nice animations when new items are added.
UserChordsAdapter.java
public class UserChordsAdapter extends RecyclerView.Adapter<UserChordsAdapter.ChordViewHolder> {
private Context context;
private final ListItemClickListener mClickHandler;
private ArrayList<String> mChordData = new ArrayList<String>(); //contains all user created chords as comma delimited note #s
/**
* The interface that receives onClick messages.
*/
public interface ListItemClickListener {
void onListItemClick(int clickedItemIndex);
}
/**
*
* #param clickHandler The on-click handler for this adapter. This single handler is called
* when an item is clicked.
*/
public UserChordsAdapter(ListItemClickListener clickHandler) {
mClickHandler = clickHandler;
}
#Override
public ChordViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
context = parent.getContext();
int layoutIdForListItem = R.layout.user_chord_list_item;
int layoutIdForFooterItem = R.layout.user_chord_add_new;
LayoutInflater inflater = LayoutInflater.from(context);
boolean shouldAttachToParentImmediately = false;
View listItem;
ChordViewHolder viewHolder;
if (viewType == R.layout.user_chord_list_item) { //inflate chord item
listItem = inflater.inflate(layoutIdForListItem, parent, shouldAttachToParentImmediately);
viewHolder = new ChordViewHolder(listItem);
}
else { //inflate "+ Add new" button (last list item)
listItem = inflater.inflate(layoutIdForFooterItem, parent, shouldAttachToParentImmediately);
viewHolder = new ChordViewHolder(listItem);
}
return viewHolder;
}
#Override
public void onBindViewHolder(ChordViewHolder holder, int position) {
if (position == mChordData.size()){
holder.mAddChordButton.setOnClickListener(new View.OnClickListener(){
#Override
public void onClick(View v) {
mChordData.add("1,30,40");
notifyItemInserted(mChordData.size()-1);
}
});
}
else {
holder.mChordName.setText("Chord " + Integer.toString(position));
}
}
#Override
public int getItemCount() {
if (mChordData == null){
return 1;
}
return mChordData.size() + 1; // +1 is for footer button (add new)
}
class ChordViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
// Will display which ViewHolder is displaying this data
TextView mChordName;
Button mAddChordButton;
/**
* Constructor for our ViewHolder. Within this constructor, we get a reference to our
* TextViews and set an onClickListener to listen for clicks. Those will be handled in the
* onClick method below.
*/
public ChordViewHolder(View itemView) {
super(itemView);
mAddChordButton = (Button) itemView.findViewById(R.id.button_add_new);
mChordName = (TextView) itemView.findViewById(R.id.tv_view_holder_instance);
itemView.setOnClickListener(this);
}
/**
* Called whenever a user clicks on an item in the list.
* #param v The View that was clicked
*/
#Override
public void onClick(View v) {
int clickedPosition = getAdapterPosition();
String chordData = mChordData.get(clickedPosition);
mClickHandler.onListItemClick(clickedPosition);
}
}
/**
* Distinguishes if view is a Chord list item or the last item in the list (add new chord)
* #param position
* #return
*/
#Override
public int getItemViewType(int position) {
return (position == mChordData.size()) ? R.layout.user_chord_add_new : R.layout.user_chord_list_item;
}}
FragmentChordMenu.java
public class FragmentChordMenu extends Fragment implements UserChordsAdapter.ListItemClickListener{
private FloatingActionButton mFAB;
private View mPopupView;
private PopupWindow mUserChordMenu;
private RecyclerView mUserChordsList;
private UserChordsAdapter mRecyclerViewAdapter;
private int numItems = 0; //TODO: dynamically calculate this as # of saved chords + 1(add new)
#Override
public void onActivityCreated(#Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
mRecyclerViewAdapter = new UserChordsAdapter(this);
}
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.menu_fragment_chord, container, false);
LayoutInflater layoutInflater = (LayoutInflater)getActivity().getBaseContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
mPopupView = layoutInflater.inflate(R.layout.menu_popup_set_chords, null);
int menuWidth = (int)(MainActivity.getActualWidth()*.95);
int menuHeight = (int)(MainActivity.getActualHeight()*.90);
mUserChordMenu = new PopupWindow(mPopupView, menuWidth, menuHeight);
mUserChordMenu.setFocusable(true);
mFAB = (FloatingActionButton) v.findViewById(R.id.addChord);
mFAB.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
mUserChordMenu.showAtLocation(mPopupView, Gravity.CENTER, 10, 10);
mUserChordsList = (RecyclerView) mPopupView.findViewById(R.id.rv_userChords);
LinearLayoutManager layoutManager = new LinearLayoutManager(getActivity());
mUserChordsList.setLayoutManager(layoutManager);
mUserChordsList.setAdapter(mRecyclerViewAdapter);
}
});
return v;
}
/**
* Called from UserChordsAdapter's onClick. Only fires on list item clicks, not the add new button
*
* */
#Override
public void onListItemClick(int clickedItemIndex) {
}}
The problem lies with the logic you use to update your views. Currently what you are saying is this, only notify my data when a view is drawn on the screen(OnBind). That is why it always work for the second try, because whenever a view is being drawn(swipe etc). that onBind method will be triggered.What you need to do is to create a method in the Adapter class, that replaces this logic.
holder.mAddChordButton.setOnClickListener(new View.OnClickListener(){
#Override
public void onClick(View v) {
mChordData.add("1,30,40");
notifyItemInserted(mChordData.size()-1);
}
});
So create a method that adds item to the mChorData set object, then call notifyItemInserted(mChordData.size()-1); in that method. This will always update and notify the adapter of any changes, hence triggering redraw automatically.
First create a public method in UserChordsAdapter that accepts an mChordData for its paramter,then in that method call, notifyItemInserted(mChordData.size()-1);. Firstly you need to expose the clickListener outside of that adapter.