I use RecyclerView for searching for users.
the search works fine, but the follow button in the ItemView is not.
Whenever I press the follow button, the text on the button is supposed to change from "follow" to "following". and and when I press it again it supposed to change from "following" to "follow". it was working just fine and suddenly it just stopped working!
Whenever I press the button it changes from "follow" to "following" for a sec and then it return to "follow". I couldn't figure out the reason!
Here is my code.
public void onBindViewHolder(#NonNull final ViewHolder holder, final int position) {
final User user = mUsers.get(position);
isFollowing(user.getId(), holder.btn_follow);
holder.btn_follow.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (holder.btn_follow.getText().toString().equals("follow"))
{
FirebaseDatabase.getInstance().getReference().child("Follow").child(firebaseUser.getUid())
.child("following").child(user.getId()).setValue(true);
FirebaseDatabase.getInstance().getReference().child("Follow").child(user.getId())
.child("followers").child(firebaseUser.getUid()).setValue(true);
addNotifications(user.getId());
}
else
{
FirebaseDatabase.getInstance().getReference().child("Follow").child(firebaseUser.getUid())
.child("following").child(user.getId()).removeValue();
FirebaseDatabase.getInstance().getReference().child("Follow").child(user.getId())
.child("followers").child(firebaseUser.getUid()).removeValue();
// FirebaseDatabase.getInstance().getReference("Notifications").child(user.getId()).removeValue();
}
}
});
}
Here is the isFollowing function:
private void isFollowing(final String userid, final Button button) {
DatabaseReference reference = FirebaseDatabase.getInstance().getReference()
.child("Follow").child(firebaseUser.getUid()).child("following");
reference.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
if (dataSnapshot.child(userid).exists()) {
button.setText("following");
button.setBackgroundResource(R.drawable.buttonafter);
} else {
button.setText("follow");
button.setBackgroundResource(R.drawable.buttonbefore);
}
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
}
});
}
It keeps returning to the default "follow" text on the button, so it is not allowing me to follow anyone.
Please help if you know what's causing this problem.
Move your implementation of onClickListener() of your button from onBindViewHolder() method to your ViewHolder class of your RecyclerView. It's not a good idea to implement listeners in onBindViewHolder().
Related
I have a RecyclerView with post cards. So there is a like button in every post card. When I tap on a like button. Sometimes it works fine and updates on current item. But after some scroll when I tap on like button it updates on another item simultaneously.
It doesn't send that data to server. But, only the view is updated. Then when I scroll up and down again. The data goes back to normal.
Problem is in the following onClick method:-
FirebaseDatabase.getInstance().getReference().child("topics").child("likes").child(data.getId()).child(username).addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
if (dataSnapshot.child("like").exists()){
holder.like.setImageResource(R.drawable.ic_favorite_red_500_36dp);
holder.like.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
FirebaseDatabase.getInstance().getReference().child("topics").child("likes").child(data.getId()).child(username).child("like").removeValue();
}
});
}else if(dataSnapshot.child("dislike").exists()) {
holder.like.setImageResource(R.drawable.brokenheart);
holder.like.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
FirebaseDatabase.getInstance().getReference().child("topics").child("likes").child(data.getId()).child(username).child("dislike").removeValue();
}
});
}else{
holder.like.setImageResource(R.drawable.ic_favorite_border_red_500_36dp);
holder.like.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
FirebaseDatabase.getInstance().getReference().child("topics").child("likes").child(data.getId()).child(username).child("dislike").removeValue();
FirebaseDatabase.getInstance().getReference().child("topics").child("likes").child(data.getId()).child(username).child("like").setValue(true);
}
});
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
holder.like.setOnLongClickListener(new View.OnLongClickListener() {
#Override
public boolean onLongClick(View view) {
FirebaseDatabase.getInstance().getReference().child("topics").child("likes").child(data.getId()).child(username).child("like").removeValue();
FirebaseDatabase.getInstance().getReference().child("topics").child("likes").child(data.getId()).child(username).child("dislike").setValue(true);
return true;
}
});
Full Adapter class https://pastebin.com/UnFGahWT
Try the following:-
Set Your on click listeners in the public ViewHolder(View itemView) method and make Your ViewHolder class implement the View.OnClickListener.
In Adapter add:
public Topic getItem(int position) {
return topics.get(position);
}
In ViewHolder's onClick method add:
int position = getAdapterPosition();
if (position == RecyclerView.NO_POSITION) return;
item = getItem(position);
Thus You will get the exact object You need to change or do something with it.
I have a RecylerView which contains a textView as individual item. Based on the requirement, the background image of the textView will be changed on click after checking the present image.
In simple:
onClick textView TV--> check for the background image of the textview TV--> check if the background image of TV is a, then make it b and viceversa
Please find my code below:
viewHolder.addRemove.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if(viewHolder.clicked==0)
{
viewHolder.addRemove.setBackgroundResource(R.mipmap.added);
viewHolder.clicked=1;
groupSlcArray.add(model.getName().trim());
Log.d("groupArr", Arrays.toString(groupSlcArray.toArray()));
}
else
{
viewHolder.addRemove.setBackgroundResource(R.mipmap.addslcgroup);
viewHolder.clicked=0;
groupSlcArray.remove(model.getName().trim());
Log.d("groupArr", Arrays.toString(groupSlcArray.toArray()));
}
}
});
I am unable to find anyway to get the background resource of the textView for checking.Need your help.This question might seem too simple for some. So please before Outvoting, try to give a solution because I have tried all the possible solutions that I found.Thanks in advance
Try following code :
holder.textview.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
if (holder.textview.getBackground() == getResources().getDrawable(R.drawable.a)){
holder.textview.setBackground(R.drawable.b);
}
else{
holder.textview.setBackground(R.drawable.a);
}
}
});
You have to understand about getView.
Sometimes If you scroll in ListView, This is not an exact Color
So I would like to recommand following ways like this:
1. Add Code on getView
if (groupSlcArray.contain(odel.getName().trim())) {
viewHolder.addRemove.setBackgroundResource(R.mipmap.addslcgroup);
} else {
viewHolder.addRemove.setBackgroundResource(R.mipmap.added);
}
2. Change OnClickListener Event Code
viewHolder.addRemove.setOnClickListener(new View.OnClickListener()
{
#Override
public void onClick (View v){
if (groupSlcArray.contain(odel.getName().trim())) {
viewHolder.addRemove.setBackgroundResource(R.mipmap.addslcgroup);
groupSlcArray.remove(model.getName().trim());
Log.d("groupArr", Arrays.toString(groupSlcArray.toArray()));
} else {
viewHolder.addRemove.setBackgroundResource(R.mipmap.added);
groupSlcArray.add(model.getName().trim());
Log.d("groupArr", Arrays.toString(groupSlcArray.toArray()));
}
}
});
Here is a solution that you can use for change background image of each RecyclerView item.
For example, currently, each row of your RecyclerView is a Item, you need to create 1 more field name textViewBackGround for hold the back ground of each row like this
public class Item{
...
public int textViewBackGround = R.drawable.a; // default image a
}
Then in your adapter
public class MyRecyclerViewAdapter extends RecyclerView.Adapter < MyRecyclerViewAdapter.CustomViewHolder > {
private List < Item > itemList;
private Context mContext;
public MyRecyclerViewAdapter(Context context, List < Item > itemList) {
this.itemList = itemList;
this.mContext = context;
}
#Override
public void onBindViewHolder(CustomViewHolder viewHolder, int i) {
Item item = itemList.get(i);
viewHolder.textView.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
// don't need to get the background of your TextView then change the background, just need to check the datasource. Later on, you absolutely will know that check the datasource for change background of item is a correct way not check the background resource
if (item.textViewBackGround == R.drawable.a) {
viewHolder.textView.setBackgroundResource(R.drawable.b);
item.textViewBackGround = R.drawable.b;
} else {
viewHolder.textView.setBackgroundResource(R.drawable.a);
item.textViewBackGround = R.drawable.a;
}
}
});
viewHolder.textView.setBackgroundResource(item.textViewBackGround); // need to set the background image for `TextView` everytime bind ViewHolder because RecyclerView item will recycle when you scroll (if you don't understand it, you can remove this line, run your app, scroll up/down and you will understand it)
...
}
class CustomViewHolder extends RecyclerView.ViewHolder {
protected TextView textView;
public CustomViewHolder(View view) {
super(view);
...
}
}
}
I'm making something like a social app.
I would like that if someone has already viewed something before, that the button in the view will change colors.
I have a method to check if someone has viewed this list before. It works in the clickListener, and will say "Already pressed."
I'm having a hard time figuring out how to change the color of the button, maybe on the onCreate method. I've tried passing it as an argument, but the color will change on the second time the list is pulled up...
This is how I call up my dialog and pass it the list ID.
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View r = inflater.inflate(R.layout.list_view_dialog_layout, container, false);
checklistView = (UserlistView) r.findViewById(R.id.user_list);
checklistview.getList(getArguments().getString("list_id")); // Can be modified
return r;
}
in that function getList, I make my call to my database to get the info of the list.
public void getList(final String listID) {
// TODO fetch list information from params and fill fields
Event.requestEvent(listID, "AuthToken", new List.ListReceivedListener() {
#Override
public void onListReceived(lissts... lissteses) {
List lst = lissteses[0];
setInfo(lst);
LISTID = listID;
}
});
}
public void setInfo(List lst){
listTitleView.setText(lst.listName);
viewsCount.setText(Integer.toString(lst.views));
}
I have a checker function to see if the user has already clicked the "have viewed"
public static boolean viewed(String id, final String user){
DatabaseReference rootref = FirebaseDatabase.getInstance().getReference("views").child(id);
rootref.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
if(dataSnapshot.hasChild(user)){
result = true;
}
else{
result = false;
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
return result;
}
then, I wanted to call it in the getList() as such
if(viewed(lstID, curuser){
viewButton.setColorFilter(R.color.blue);
}
this doesn't work for the first time the view is created, and so, if the user has already clicked view, logs out and logs back in, and click view again, messing up the view count.
int flag=0;
button.setOnClickLitener(new OnClickListener()){
#Override
public void onClick(View arg0) {
flag++;
}
});
if(flag>0){
button.setBackgroundColor(getResources().getColor(R.color.yourColor));
}
Another solution is this.
button.setBackgroundColor(getResources().getColor(R.color.youCustomColor));
I have a recyclerview with simple items - an item has an image, title and a button. When the user clicks on the button it needs to change its layout -> indicating that button is clicked (similar to checkbox functionality).
Problem is that when I click on a button, for example the second item, it behaves weirdly when I scroll - multiple items are toggled or the original one is untoggled. You can check it out in image here:
GIF PREVIEW
#Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position)
{
holder.button.setOnClickListener(view -> {
toggleButtonStyle((Button)view);
});
}
public void toggleButtonStyle(Button toggle)
{
Context ctx = toggle.getContext();
if (toggle.isActivated()) {
toggle.setActivated(false);
toggle.setBackground(ContextCompat.getDrawable(ctx, R.drawable.btn_purple_corners));
toggle.setTextColor(ContextCompat.getColor(ctx, R.color.purple_light));
} else {
toggle.setActivated(true);
toggle.setBackground(ContextCompat.getDrawable(ctx, R.drawable.btn_purple));
toggle.setTextColor(ContextCompat.getColor(ctx, R.color.white));
}
}
You need to specify position for a onBindView method, because it's called multiple times. If you are using AutoValue immutable types, you can try to make an Array of booleans where you'll be storing toggled states (true/false). Then in onBindViewMethod check a value of current position and style a button.
private boolean[] toggledChoices = new boolean[yourListWithItems.size()];
#Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
if (toggledChoices[position]) {
toggleButtonStyle(true, holder.toggleButton);
} else {
toggleButtonStyle(false, holder.toggleButton;
}
holderVote.bToggleItem.setOnClickListener(v -> {
if (!toggledChoices[position]) {
toggledChoices[position] = true;
} else {
toggledChoices[position] = false;
}
});
}
I had some strange behavior too in the past.
For me it was solved by simply calling
toggle.invalidate();
after your if/else block. This forces the redraw. Try it, I was surprised too, that this fixed it for me.
Check Out my code
#Override
public void onBindViewHolder(GifGridAdapter.ViewHolder holder, final int position) {
final DataModel model = arrayList.get(position);
if (model.isToggle()) {
//Code for changing the button background color and text color
} else {
//Code for changing the button background color and text color
}
holder.ivGif.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
model.setToggle(!model.isToggle());
notifyDataSetChanged();
}
});
}
i facing a problem in recyclerview's item.
My Adapter's code :
#Override
public void onBindViewHolder(final RecyclerView.ViewHolder holder, int position) {
Profile item = mListChatting.get(position);
Log.d("TAG", "CEK : " + viewable);
if(viewable==true){
holder.mFormBookingan.setVisibility(View.GONE);
holder.mDetailBookingan.setVisibility(View.VISIBLE);
}else{
//assume that one way is show first as default
holder.mViewOneWay.setVisibility(View.VISIBLE);
holder.mViewRoundTrip.setVisibility(View.GONE);
holder.mOneOway.setBackgroundResource(R.drawable.round_just_left_white_focus);
holder.mRoundTrip.setBackgroundResource(R.drawable.state_pressed_booking_button_left);
holder.mSendBooking.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
viewable = true;
Log.d("TAG", "CEK 2 : " + viewable);
}
});
}
Like my code above, I want to hide mFormBookingan after mSendBooking has pressed. mFormBookingan never show anymore until user calls it again.
I have tried with a lot of ways but still can't find like what i need. After i press mSendBooking the form hide, but when i send new item to recyclerview, the from mFormBookingan that has been hide, appears again.
My Question, how to hide mFormBookingan forever? Until user call it again.
Thank in advance, i will appreciate anyone who help me for this one.
I not sure what the clear situation you want.
But if you want to set View invisible you can try this code then check it.
You need to add ismFormBookingVisible in viewHolder class as a boolean attribute.
#Override
public void onBindViewHolder(final RecyclerView.ViewHolder holder, int position) {
Profile item = mListChatting.get(position);
Log.d("TAG", "CEK : " + viewable);
if(holder.ismFormBookingVisible==true){
holder.mFormBookingan.setVisibility(View.GONE);
holder.mDetailBookingan.setVisibility(View.VISIBLE);
}else{
//assume that one way is show first as default
holder.mViewOneWay.setVisibility(View.VISIBLE);
holder.mViewRoundTrip.setVisibility(View.GONE);
holder.mOneOway.setBackgroundResource(R.drawable.round_just_left_white_focus);
holder.mRoundTrip.setBackgroundResource(R.drawable.state_pressed_booking_button_left);
holder.mSendBooking.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
holder.ismFormBookingVisible = false;
Log.d("TAG", "CEK 2 : " + viewable);
}
Try this :
Create a boolean in your model class "Profile" to keep track of visibility of button : say boolean isBookingVisible;
#Override
public void onBindViewHolder(final RecyclerView.ViewHolder holder, int position) {
Profile item = mListChatting.get(position);
if(!item.isBookingVisible){
holder.mFormBookingan.setVisibility(View.GONE);
holder.mDetailBookingan.setVisibility(View.VISIBLE);
}else{
//assume that one way is show first as default
holder.mViewOneWay.setVisibility(View.VISIBLE);
holder.mViewRoundTrip.setVisibility(View.GONE);
holder.mOneOway.setBackgroundResource(R.drawable.round_just_left_white_focus);
holder.mRoundTrip.setBackgroundResource(R.drawable.state_pressed_booking_button_left);
holder.mSendBooking.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
item.isBookingVisible = false;
//Use notiyItemChanged(position); or notifyDataSetChanged(); here as per your selection criterion
Log.d("TAG", "CEK 2 : " + viewable);
}
});
}
You may have to call notifyDataSetChanged() after changing the value of viewable.
onBindViewHolder will be called when you notify your data set.
So you need to save the viewable in mListChatting. When you click the button, change the viewable in the mListChatting.
And then, change the code in onBindViewHolder
holder.mFormBookingan.setVisibility(item.getViewable() ? View.VISIBLE : View.GONE);
On refresh android will destroy the view and create new view with new adapter data. So you have to track the current state (visibility) of mFormBookingan. You can use a simple visibility list. When mFormBookingan state (visibility) change update it in visibility list so that whenever the list is refreshed, you can use it to check and set the last state (visibility) of your mFormBookingan. Here is an example
private ArrayList<Boolean> isVisible;
public MyAdapter(ArrayList<Boolean> isVisible){
// initial state list of mFormBookingan for each row of list
this.isVisible = isVisible;
}
public void onBindViewHolder(final MyViewHolder holder, final int position) {
if (isVisible.get(position)) {
holder.mFormBookingan.setVisibility(View.VISIBLE);
}else {
holder.mFormBookingan.setVisibility(View.GONE);
}
holder.mSendBooking.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (holder.mFormBookingan.getVisibility() == View.GONE){
holder.mFormBookingan.setVisibility(View.VISIBLE);
isVisible.set(position, true);
}else {
holder.mFormBookingan.setVisibility(View.GONE);
isVisible.set(position, false);
}
}
});
}
when you click mSendBooking the mFormBookingan visibility will change and it will remain same after sending new item to recyclerview.