I've been searching for a solution for three days now.
If everyone has an Idea please help me, I don't even think it's actually that difficult to achieve but It's not really my branch, if you can say it like this.
In a RecyclerView containing a list with multiple Items, each having a Title(TextView) and a Cover image(ImageView).
This data is set in the Adapter, in the ViewHolder, more specifically in the OnBind function.
So where's my problem?
I've created a PopUp Window, which contains besides a few buttons, a placeholder ImageView and a placeholder TextView.
I cannot seem to find a way to place the data of the clicked Item in the list inside the placeholders.
I think it's similar to the OnBind method but it doesn't work.
Here's the Adapter (if the code for GameItem is needed I'll gladly post it):
import java.util.ArrayList;
public class GameViewAdapter extends RecyclerView.Adapter<GameViewAdapter.GameViewHolder> {
private ArrayList<GameItem> mGameList;
private OnItemClickListener mListener;
public interface OnItemClickListener{
void onGameClick(int position);
}
public void setOnItemClickListener(OnItemClickListener listener){
mListener =listener;
}
public static class GameViewHolder extends RecyclerView.ViewHolder{
public ImageView Cover;
public TextView Title;
public TextView Description;
public PopupWindow popupWindow;
public ImageView popUpImage;
public TextView PopUpTitle;
public EditText customAmount;
public Button add;
private Button addcustom;
private Button exit;
public GameViewHolder(final View itemView, final OnItemClickListener listener) {
super(itemView);
add = itemView.findViewById(R.id.addaverage);
addcustom = itemView.findViewById(R.id.addcustom);
popUpImage = itemView.findViewById(R.id.popupimg);
PopUpTitle = itemView.findViewById(R.id.popuptitle);
customAmount = itemView.findViewById(R.id.gameamount);
Cover = itemView.findViewById(R.id.GameCover);
Title = itemView.findViewById(R.id.GameTitle);
Description = itemView.findViewById(R.id.GameAmount);
exit = itemView.findViewById(R.id.exit);
itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
showPopUp();
}
});
}
public void showPopUp() {
final View popupView = LayoutInflater.from(itemView.getContext()).inflate(R.layout.popup, null);
final PopupWindow popupWindow = new PopupWindow(popupView, WindowManager.LayoutParams.WRAP_CONTENT, WindowManager.LayoutParams.WRAP_CONTENT);
exit = popupView.findViewById(R.id.exit);
exit.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
popupWindow.dismiss();
}
});
popupWindow.showAtLocation(popupView, Gravity.CENTER, 0, 0);
}
}
public GameViewAdapter(ArrayList<GameItem> gameList){
mGameList = gameList;
}
#Override
public GameViewHolder onCreateViewHolder(#NonNull ViewGroup viewGroup, int i) {
Context context = viewGroup.getContext();
View v = LayoutInflater.from(context).inflate(R.layout.game_entry, viewGroup, false);
GameViewHolder GVH = new GameViewHolder(v, mListener);
return GVH;
}
#Override
public void onBindViewHolder(#NonNull GameViewHolder gameViewHolder, int position){
GameItem currentItem = mGameList.get(position);
Glide.with(gameViewHolder.Cover).load(currentItem.getCover()).into(gameViewHolder.Cover);
gameViewHolder.Title.setText(currentItem.getTitle());
gameViewHolder.Description.setText(currentItem.getDescription());
}
#Override
public int getItemCount() {
return mGameList.size();
}
}
In the OnBind method, the Image and Text are associated to the Items
correctly, through Glide and
gameViewHolder.Title.setText(currentItem.getTitle());. Now, I have
created a PopUp, which should get the Image and the Text from the
clicked item in the RecyclerView.
I've reordered some methods and properties for the sake of clarity and then next, I'll explain.
public class GameViewAdapter extends RecyclerView.Adapter<GameViewAdapter.GameViewHolder> {
private ArrayList<GameItem> mGameList;
private OnItemClickListener mListener;
public GameViewAdapter(ArrayList<GameItem> mGameList, GameViewAdapter.OnItemClickListener mListener) {
this.mGameList = mGameList;
this.mListener = mListener;
}
#Override
public GameViewHolder onCreateViewHolder(#NonNull ViewGroup viewGroup, int i) {
Context context = viewGroup.getContext();
View v = LayoutInflater.from(context).inflate(R.layout.game_entry, viewGroup, false);
GameViewHolder GVH = new GameViewHolder(v, mListener);
return GVH;
}
#Override
public void onBindViewHolder(#NonNull GameViewHolder gameViewHolder, int position){
gameViewHolder.bind(mGameList.get(position));
}
#Override
public int getItemCount() {
return mGameList.size();
}
class GameViewHolder extends RecyclerView.ViewHolder {
private ImageView itemCover;
private TextView itemTitle;
private TextView itemDescription;
private PopupWindow popupWindow;
private ImageView popUpImage;
private TextView PopUpTitle;
private EditText customAmount;
private Button add;
private Button addcustom;
private Button exit;
public GameViewHolder(View itemView, GameViewAdapter.OnItemClickListener mListener) {
super(itemView);
setupViews(itemView);
}
public void bind(GameItem gameItem) {
Glide.with(this.itemCover).load(gameItem.getCover()).into(this.itemCover);
this.itemTitle.setText(gameItem.getTitle());
this.itemDescription.setText(gameItem.getDescription());
itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
showPopUp(itemView, gameItem);
}
});
}
private void setupViews(View itemView) {
add = itemView.findViewById(R.id.addaverage);
addcustom = itemView.findViewById(R.id.addcustom);
popUpImage = itemView.findViewById(R.id.popupimg);
PopUpTitle = itemView.findViewById(R.id.popuptitle);
customAmount = itemView.findViewById(R.id.gameamount);
itemCover = itemView.findViewById(R.id.GameCover);
itemTitle = itemView.findViewById(R.id.GameTitle);
itemDescription = itemView.findViewById(R.id.GameAmount);
exit = itemView.findViewById(R.id.exit);
}
private void showPopUp(View itemView, GameItem gameItem) {
final View popupView = LayoutInflater.from(itemView.getContext()).inflate(R.layout.popup, null);
final PopupWindow popupWindow = new PopupWindow(popupView, WindowManager.LayoutParams.WRAP_CONTENT, WindowManager.LayoutParams.WRAP_CONTENT);
final ImageView popupItemCover = popupView.findViewById(R.id.popupItemCover);
final TextView popupItemTitle = popupView.findViewById(R.id.popupItemTitle);
Glide.with(popupItemCover).load(gameItem.getCover()).into(popupItemCover);
popupItemTitle.setText(gameItem.getTitle());
exit = popupView.findViewById(R.id.exit);
exit.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
popupWindow.dismiss();
}
});
popupWindow.showAtLocation(popupView, Gravity.CENTER, 0, 0);
}
}
public interface OnItemClickListener{
void onGameClick(int position);
}
}
What changed?
First, we now have a method called bind inside our ViewHolder, we took the responsibility from setting the data from our Adapter and delegated it to the ViewHolder.
Second, as that method is called every time onBindViewHolder is called, you'll have the actual GameItem. So? With that item, instead of setting the onClickListener to open the PopUp in the GameViewHolderconstructor, we now set it in the bind method. But, what are the benefits from it? Every time we bind data to its views, we prepare our Popup and then show it.
What should be changed?
For performance purposes, I guess, you should instantiate the constructor and then populate it every time with new data, instead of creating a new instance again every time onBindViewHolder is called.
Edit: As I don't know your popup views IDs, I've created some dummies IDs. Hope you understand.
Best.
Related
I have an activity which consists of a recycler view for generating buttons (from a different layout file) and a layout with elements for confirmation.
I want to make it so when I click on the button "NEW GAME" (in the Recyclerview class), the confirmationLayout (in the MainMenu Activity) shows. But I can't, can someone help me?
MainMenu Class
public class MainMenu extends AppCompatActivity {
private ImageView profileIcon;
private TextView username;
private RelativeLayout newGameConfirmationLayout;
private TextView yesButton, noButton;
private RecyclerView buttonRecyclerView;
private ButtonRecyclerAdapter adapter;
private DataHandler dataHandler;
private ArrayList<String> buttonNames = new ArrayList<>();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main_menu);
newGameConfirmationLayout = findViewById(R.id.newGameConfirmationLayout);
yesButton = findViewById(R.id.yesButton);
noButton = findViewById(R.id.noButton);
buttonRecyclerView = findViewById(R.id.buttonRecyclerView);
buttonRecyclerView.setLayoutManager(new LinearLayoutManager(MainMenu.this));
if(General.infoSaved){buttonNames.add("CONTINUE GAME");}
buttonNames.add("NEW GAME");
buttonNames.add("CHANGE USER");
buttonNames.add("PRACTICE");
buttonNames.add("EXERCISE LIST");
adapter = new ButtonRecyclerAdapter(buttonNames, MainMenu.this);
buttonRecyclerView.setAdapter(adapter);
yesButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
startGame();
}
});
noButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
newGameConfirmationLayout.setVisibility(View.INVISIBLE);
}
});
}
private void startGame(){}
public void show_confirmationLayout(){
newGameConfirmationLayout.setVisibility(View.VISIBLE);
}
RecyclerView Class
public class ButtonRecyclerAdapter extends RecyclerView.Adapter<ButtonRecyclerAdapter.buttonHolder>{
private ArrayList<String> buttonNames;
private Context context;
public ButtonRecyclerAdapter(ArrayList<String> loginButtonNames, Context context) {
this.buttonNames = loginButtonNames;
this.context = context;
}
#NonNull
#Override
public buttonHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.button_block,parent,false);
return new buttonHolder(view);
}
#Override
public void onBindViewHolder(#NonNull buttonHolder holder, int position) {
holder.button.setText(buttonNames.get(position));
holder.button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
String buttonName = holder.button.getText().toString();
switch (buttonName){
case "NEW GAME":
MainMenu mainMenu = new MainMenu();
mainMenu.show_confirmationLayout();
break;
}
}
});
}
#Override
public int getItemCount() {
return buttonNames.size();
}
public class buttonHolder extends RecyclerView.ViewHolder{
private Button button;
public buttonHolder(#NonNull View itemView) {
super(itemView);
button = itemView.findViewById(R.id.buttonblock);
}
}
}
I tried adding it as a class (as above) but I get the error that the layout is a null object / However when I try to write the ame line of code directly in the activity it works.
There's a method I personally use in my RecyclerView's Adapter and ViewHolder is to set the width and height of your item's ViewGroup to 0.
Here's the method you can add to your adapter class which takes item position that you want to hide:
public void hideFeedItem(int position){
RecyclerView.ViewHolder holder = getViewHolderAtPosition(position);
if(holder != null){
ViewGroup.LayoutParams params = holder.itemView.getLayoutParams();
params.height=0;
params.width= 0;
holder.itemView.setLayoutParams(params);
}
}
Where itemview is the root ViewGroup that should be already defined in your ViewHolder in your case should be buttonHolder.
I have a RecyclerView in which I have an ImageView for each item in the form of sendEmail icon. Initially, the ImageView is visible but once I click on it, I hide it using setVisibility(View.GONE) and update the Adapter.
Now, when I click on the sendEmail icon, I hide the icon in that position instantly using reportitems.get(position).setStatus("emailsent");. Now, if, before the search operation, the second item had the ImageView visible and first item did not, then after search if the second item were to be the only item that is relevant, then the ImageView does not show up there in the first position. I am using dynamic search where upon inputting a character, the adapter refreshes instantly and shows the updated RecyclerView. How can I fix this issue?
After search, even though SQ 322 should have the sendEmail icon, it does not show up
Activity code
mAdapter.setOnItemClickListener(new ReportAdapter.OnItemClickListener() {
public void onSendEmailClick(int position){
flightNumber=reportitems.get(position).getFlightNumber();
departureDate=reportitems.get(position).getDepartureDate();
FlightClosureStatus flightClosureStatus=new FlightClosureStatus(flightNumber,departureDate,"emailsent");
flightViewModel.updateFlightClosureStatus(flightClosureStatus);
reportitems.get(position).setStatus("emailsent");
mAdapter.notifyDataSetChanged();
}
}
Adapter Code
public class ReportAdapter extends RecyclerView.Adapter<ReportAdapter.ReportViewHolder> {
private ArrayList<ReportItem> reportlist;
private OnItemClickListener mListener;
private Context mContext;
public ReportAdapter(ArrayList<ReportItem> reportlist, Context context) {
this.reportlist = reportlist;
this.mContext = context;
}
public interface OnItemClickListener {
void onSendEmailClick(int position);
}
public void setOnItemClickListener(OnItemClickListener listener) {
mListener = listener;
}
public static class ReportViewHolder extends RecyclerView.ViewHolder {
public TextView departureDate;
public TextView flightNumber;
public ImageView emailView;
public ReportViewHolder(#NonNull View itemView, OnItemClickListener listener, Context context) {
super(itemView);
departureDate = itemView.findViewById(R.id.departureDaterecyclerview);
flightNumber = itemView.findViewById(R.id.flightnumberrecyclerview);
emailView = itemView.findViewById(R.id.sendemailIcon);
emailView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if(listener != null) {
int position = getAdapterPosition();
if(position != RecyclerView.NO_POSITION) {
listener.onSendEmailClick(position);
}
}
}
});
}
}
#NonNull
#Override
public ReportViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.report_listing_item, parent, false);
ReportViewHolder rvh= new ReportViewHolder(v,mListener,mContext);
return rvh;
}
#SuppressLint("ResourceAsColor")
#Override
public void onBindViewHolder(#NonNull ReportViewHolder holder, int position) {
ReportItem currentItem = reportlist.get(position);
//here i am setting the visibility of the imageview to gone
if(currentItem.getStatus().contentEquals("emailsent")){
holder.emailView.setVisibility(View.GONE);
}
holder.flightNumber.setText(currentItem.getFlightNumber());
holder.departureDate.setText((currentItem.getDepartureDate()));
}
public List<ReportItem> getList() {
return reportlist;
}
}
Replace your onBindViewHolder with below, basically recycler uses items from pool when available, and once the item visibility is GONE and it is never set to VISIBLE again unless you do it
#SuppressLint("ResourceAsColor")
#Override
public void onBindViewHolder(#NonNull ReportViewHolder holder, int position) {
ReportItem currentItem = reportlist.get(position);
//here i am setting the visibility of the imageview to gone
if(currentItem.getStatus().contentEquals("emailsent")){
holder.emailView.setVisibility(View.GONE);
}else{
holder.emailView.setVisibility(View.VISIBLE);
}
holder.flightNumber.setText(currentItem.getFlightNumber());
holder.departureDate.setText((currentItem.getDepartureDate()));
}
I am actually working on a group project and I want to develop a functionnality for our application. My goal is to have a list of several items with their images and when I click on an Item of that list I want to have a text pop in the midle of the screen related to that particular item. I'm afraid I might be using the wrong technical Tools to do so. I am actually using a csv file for the list details, an adapter and a viewHolder for the list. Since I have no idea on what is wrong and what to do I link a big part of my code so you can check how I did until now. I can also give you my xml files if you need to check them out, a really big thanks in advance to all the answers and time spent on my problem
I already managed to have my list of items with the title and the picture (text from csv file) of each list item but I'm stuck on how to show a specific text for each ViewHolder.
this is my Adapter
public class Adapter extends RecyclerView.Adapter<ViewHolder> {
List<Departement> list;
Activity activity;
public Adapter(List<Departement> list, Activity activity) {
this.list = list;
this.activity = activity;
}
#Override
public ViewHolder onCreateViewHolder(ViewGroup viewGroup, int itemType) {
View view = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.departement,viewGroup,false);
return new ViewHolder(view);
}
#Override
public void onBindViewHolder(ViewHolder viewHolder, int position) {
Departement departement = list.get(position);
viewHolder.bind(departement, activity);
}
#Override
public int getItemCount() {
return list.size();
}
}
my ViewHolder
public class ViewHolder extends RecyclerView.ViewHolder {
private TextView textViewView;
private ImageView imageView;
public ViewHolder(View itemView) {
super(itemView);
textViewView = (TextView) itemView.findViewById(R.id.text);
imageView = (ImageView) itemView.findViewById(R.id.image);
}
public void bind(Departement departement, Activity activity){
textViewView.setText(departement.getText());
String uri = departement.getImageUrl();
int imageResource = activity.getResources().getIdentifier(uri, null, activity.getPackageName());
Drawable res = activity.getResources().getDrawable(imageResource);
imageView.setImageDrawable(res);
}
}
each item of the list is a Departement
public class Departement {
private String text;
private String imageUrl;
public Departement(String text, String imageUrl) {
this.text = text;
this.imageUrl = imageUrl;
}
public String getText() {
return text;
}
public String getImageUrl() {
return imageUrl;
}
public void setText(String text) {
this.text = text;
}
public void setImageUrl(String imageUrl) {
this.imageUrl = imageUrl;
}
}
and finally my fragment
public class FragmentEspecesProches extends Fragment {
public final static char SEPARATOR=',';
private RecyclerView recyclerView;
private List<Departement> departementsList = new ArrayList<>();
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
View view = inflater.inflate(R.layout.fragment_especes_proches, container, false);
ajouterDepartements();
recyclerView = (RecyclerView) view.findViewById(R.id.recyclerView);
recyclerView.setLayoutManager(new GridLayoutManager(this,2));
recyclerView.setAdapter(new Adapter(departementsList, getActivity()));
return view;
}
private void ajouterDepartements() {
ArrayList<String> lines = new ArrayList<>();
ArrayList<String[]> data = new ArrayList<>();
String sep = new Character(SEPARATOR).toString();
lines = UtilitaireResultat.readFile(getActivity().getResources().openRawResource(R.raw.departement));
for(String line : lines){
String[] oneData = line.split(sep);
data.add(oneData);
}
for(int i=0 ; i<data.size() ; i++){
String[] tabStr = data.get(i);
departementsList.add( new Departement( tabStr[2]+" - "+tabStr[3] ,"#drawable/"+tabStr[5] ));
}
}
}
you can implement item click listener like this
public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
public TextView tvName;
public TextView tvHometown;
private Context context;
public ViewHolder(Context context, View itemView) {
super(itemView);
this.tvName = (TextView) itemView.findViewById(R.id.tvName);
this.tvHometown = (TextView) itemView.findViewById(R.id.tvHometown);
// Store the context
this.context = context;
// Attach a click listener to the entire row view
itemView.setOnClickListener(this);
}
// Handles the row being being clicked
#Override
public void onClick(View view) {
int position = getAdapterPosition(); // gets item position
// if (position != RecyclerView.NO_POSITION) { // Check if an item was deleted, but the user clicked it before the UI removed it
User user = users.get(position);
// We can access the data within the views
Toast.makeText(context, tvName.getText(), Toast.LENGTH_SHORT).show();
// }
}
}
Use onBindViewHolder to handle any interaction on your list items
#Override
public void onBindViewHolder(ViewHolder viewHolder, int position) {
Departement departement = list.get(position);
viewHolder.bind(departement, activity);
viewHolder.itemView.setOnClickListener(//your action//);
}
ItemView is the whole item; you can access your textviews or imageviews as you use it on your bind method,
You can use your bind method to apply listeners.
Handle on click of the item inside your ViewHolder constructor
like ,
public ViewHolder(View itemView) {
super(itemView);
textViewView = (TextView) itemView.findViewById(R.id.text);
imageView = (ImageView) itemView.findViewById(R.id.image);
itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
int position=getAdapterPosition();
Toast.makeText(context, list.get(position).getText(), Toast.LENGTH_SHORT).show();
}
});
}
Create your onClickListner interface as
interface RecylerViewItemClickListner
{
void onItemClick(Department item)
}
set the listner in Adapter class
private final RecylerViewItemClickListner mOnClickListener;
public Adapter(List<Departement> list, Activity activity) {
this.list = list;
this.activity = activity;
this.mOnClickListener = activity;
}
Now in ViewHolder class
public void bind(final Departement item, final mOnClickListener listener) {
itemView.setOnClickListener(new View.OnClickListener() {
#Override public void onClick(View v) {
mOnClickListener.onItemClick(item);
}
});
}
and change onBindViewHolder as below
#Override
public void onBindViewHolder(ViewHolder holder, int position) {
holder.bind(items.get(position), mOnClickListener);
}
Override onItemClick(Department item) in activity
#override
onItemClick(Department item)
{
//show toast here...
}
implement OnClickListener in your ViewHolder class
public class ViewHolder extends RecyclerView.ViewHolder implements
View.OnClickListener
{
#Override
public void onClick(View v)
{
//do action
}
}
Implement below method in your ViewHolder class.
itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
final User currentItem = users.get(getAdapterPosition());
Toast.makeText(mContext,currentItem.getText()+" is selected!",Toast.LENGTH_SHORT).show();
}
});
In my RecyclerView item, there is a button along with other views. I am hiding the button when it is clicked. Problem is, if I click the button on 1st item, the button on 8th item is auto clicked, if I click button on 2nd item, button on 9th item is auto clicked & so on. How to solve this problem?
Adapter class :
public class Adapter extends RecyclerView.Adapter<Adapter.ViewHolder> {
private List<Model> models;
Model model;
// public MyAdapterListener onClickListener;
SparseBooleanArray mStateButtons = new SparseBooleanArray();
public Adapter(List<Model> models){
this.models = models;
}
#NonNull
#Override
public ViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.single_row, false);
return new ViewHolder(view);
}
#Override
public void onBindViewHolder(#NonNull final ViewHolder holder, final int position) {
String question = models.get(position).getQues();
final String optA = models.get(position).getOptA();
final String optB = models.get(position).getOptB();
final String optC = models.get(position).getOptC();
final String optD = models.get(position).getOptD();
final String answer = models.get(position).getAns();
holder.question.setText(question);
holder.optA.setText(optA);
holder.optB.setText(optB);
holder.optC.setText(optC);
holder.optD.setText(optD);
holder.options.setTag(position);
holder.options.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() {
#Override
public void onCheckedChanged(RadioGroup group, int checkedId) {
int radioButtonID = group.getCheckedRadioButtonId();
int clickedPos = (Integer) group.getTag();
models.get(clickedPos).setChecked(radioButtonID);
}
});
holder.options.check(models.get(position).getChecked());
final int currentPosition = holder.getAdapterPosition();
final Button button = holder.seeAnswer;
if(mStateButtons.valueAt(currentPosition)) {
button.setVisibility(View.GONE);
} else {
button.setVisibility(View.VISIBLE);
}
holder.seeAnswer.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
mStateButtons.put(position, true);
}
});
}
#Override
public int getItemCount() {
return Models.size();
}
class ViewHolder extends RecyclerView.ViewHolder{
TextView question;
RadioButton optA, optB, optC, optD;
Button seeAnswer;
RadioGroup options;
public ViewHolder(View itemView) {
super(itemView);
options = (RadioGroup) itemView.findViewById(R.id.rgMcqOptions);
question = (TextView) itemView.findViewById(R.id.tvMcqQues);
optA = (RadioButton) itemView.findViewById(R.id.rbOptA);
optB = (RadioButton) itemView.findViewById(R.id.rbOptB);
optC = (RadioButton) itemView.findViewById(R.id.rbOptC);
optD = (RadioButton) itemView.findViewById(R.id.rbOptD);
seeAnswer = (Button) itemView.findViewById(R.id.btnSeeAnswer);
}
}
}
You need some way to keep track of which buttons should be hidden and which should not. This is the responsibility of your adapter, so you need to add some form of array to keep track of button states there. A SparseBooleanArray is an efficient and appropriate option:
private SparseBooleanArray hideButtons = new SparseBooleanArray();
In onBindView you need to update the view for the current item being bound, including updating the button visibility:
#Override
public void onBindViewHolder(#NonNull final ViewHolder holder, final int position) {
holder.seeAnswer.setVisibility( hideButtons.get(position, false) ? View.GONE : View.VISIBLE );
...
}
And of course you need to actually set the visibility - and store it in the SparseBooleanArray when clicking the button. Putting this event handler in the ViewHolder is a good option:
class ViewHolder extends RecyclerView.ViewHolder{
Button seeAnswer;
...
ViewHolder(View itemView) {
super(itemView);
seeAnswer = (Button) itemView.findViewById(R.id.btnSeeAnswer);
seeAnswer.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
seeAnswer.setVisibility(View.GONE);
hideButtons.put(getAdapterPosition(), true);
}
});
...
}
}
This is a tested and verified solution, so if you follow this and it still doesn't work, the cause of your problem is somewhere else.
This usually happens because you forgot to keep the state of the Button in case it's being recycled. You can use SparseBooleanArray to store the states. Something like this:
public class YourAdapter ... {
// variable to save the state of buttons.
// we use state true as hidden, false as visible
SparseBooleanArray mStateButtons = new SparseBooleanArray();
...
#Override
public void onBindViewHolder(ContactsAdapter.ViewHolder viewHolder, int position) {
final int currentPosition = viewHolder.getAdapterPosition();
// assume this is your button
Button button = viewHolder.yourButton;
// set the previous state to button
if(mStateButtons.valueAt(currentPosition)) {
// state is true, so the button need to be hide.
button.setVisibility(View.GONE);
} else {
// default value is valse, which is we set as visible.
button.setVisibility(View.VISIBLE);
}
button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
// save the state when clicked
mStateButtons.put(currentPosition, true);
}
});
}
}
UPDATE
Try moving the click handling on ViewHolder, something like this:
public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
...
Button seeAnswer;
public ViewHolder(View itemView) {
super(itemView);
...
seeAnswer = (Button) itemView.findViewById(R.id.btnSeeAnswer);
itemView.setOnClickListener(this);
}
// Handles the row being being clicked
#Override
public void onClick(View view) {
mStateButtons.put(getAdapterPosition(), true);
view.setVisibility(View.GONE);
}
}
then remove the button.setOnClickListener(new View.OnClickListener() in onBindViewHolder.
The problem seems to be that you are not initializing correctly the state of the Button. Cells in a RecyclerView are reused when they appear or hide in the screen. That means that if you hide the 1st position and then this view is recycled to create the 8th, the Button keeps its state, in this case INVISIBLE
Try to assign a value all cases or init the value to VISIBLE.
In my application i have horizontal list view. On Item select I want to change that selected Item background color and it's text view color. i have figured out that part. But how to reset background color and text view color of previously selected item. here's my adapter class.
public class DateRangeListViewAdapter extends RecyclerView.Adapter<DateRangeListViewAdapter.ContentViewHolder> {
private ItemClickListener itemClickListener;
private LayoutInflater inflater;
private ArrayList<String> data;
private Context context;
private int dataType;
private int previousSelectedPosition;
private static final int DATE_TYPE = 1;
private static final int STATUS_TYPE = 2;
public DateRangeListViewAdapter(ArrayList<String> data, Context context,int dataType) {
this.data = data;
this.context = context;
this.dataType = dataType;
inflater = LayoutInflater.from(context);
previousSelectedPosition = -1;
}
public void setItemClickListener(ItemClickListener itemClickListener) {
this.itemClickListener = itemClickListener;
}
#Override
public ContentViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = inflater.inflate(R.layout.custom_date_range_list_item,parent,false);
return new ContentViewHolder(view);
}
#Override
public void onBindViewHolder(ContentViewHolder holder, int position) {
String name = data.get(position);
holder.dateText.setText(name);
}
#Override
public int getItemCount() {
return data.size();
}
public class ContentViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
private FrameLayout main;
private TextView dateText;
public ContentViewHolder(View itemView) {
super(itemView);
itemView.setOnClickListener(this);
main = (FrameLayout) itemView.findViewById(R.id.main_layout);
dateText = (TextView) itemView.findViewById(R.id.date_name);
}
#Override
public void onClick(View v) {
//Selected item color change
main.setBackground(ContextCompat.getDrawable(context,R.drawable.date_range_selected_item_background));
dateText.setTextColor(ContextCompat.getColor(context,R.color.colorPrimary));
if(itemClickListener!=null){
itemClickListener.onItemClick(v,this.getLayoutPosition(),dataType,getOldPosition());
}
}
}
public interface ItemClickListener{
public void onItemClick(View v, int position,int dataType,int oldPosition);
}
}
You basically want to make good use of your int flag, previousSelectedPosition, to keep track of the list item's position that was clicked, invoke notifyDataSetChanged(), and then set the flag as part of a conditional statement within onBindViewHolder() to update ViewHolder's views accordingly as they continuously get binded. Try the following changes:
ViewHolder's onClick():
#Override
public void onClick(View v) {
if (itemClickListener!=null) {
previousSelectedPosition = getAdapterPosition();
notifyDataSetChanged();
itemClickListener.onItemClick(v,this.getLayoutPosition(),dataType,getOldPosition());
}
}
RecyclerView.Adapter's onBindViewHolder():
#Override
public void onBindViewHolder(ContentViewHolder holder, int position) {
String name = data.get(position);
holder.dateText.setText(name);
if (previousSelectedPosition == position) {
main.setBackground(ContextCompat.getDrawable(context,R.drawable.date_range_selected_item_background));
dateText.setTextColor(ContextCompat.getColor(context,R.color.colorPrimary));
} else {
// TODO: Configure the FrameLayout and TextView here for initial runtime as well as back to default
}
}
... and yes, make sure to keep previousSelectedPosition initialized as -1 for the initial runtime just so the condition in onBindViewHolder() wouldn't matter until the flag updates (after a list item is clicked, that is).
Your OnClickListener does not work perfectly. You just need to implements your ViewHolder from you "ItemClickListener" interface. And add this line in onCreateViewHolder :
View view = inflater.inflate(R.layout.custom_date_range_list_item,parent,false);
ContentViewHolder cVh = ContentViewHolder(view);view.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
cVh.onItemClick(v,this.getLayoutPosition(),cVh .dataType,cVh .getOldPosition());
}
});return cVh