Android, List of items not showing correctly - java

Got a list (recyclerview) that should show an image for certain types of Class X, everything is working perfectly, the thing is that after I start another activity and finish to go back to it, all of the images are removed, except for the ones that don't have a type 1 after them, so it seems there is a reason that causes if type 1 doesn't make its image only gone, but all the previous
private class XHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
private ImageView mImageView;
private X mX;
private XHolder(View v) {
super(v);
v.setOnClickListener(this);
mImageView = (ImageView) v.findViewById(R.id.imageview);
}
public void bindX(X x){
mX = x;
if(mX.getType() == 1) {
mImageView.setVisibility(View.GONE);
}
}
#Override
public void onClick(View v) {
xClickEvent(mX);
}
}

Add else condition too, like:
if (mX.getType() == 1) {
mImageView.setVisibility(View.GONE);
} else {
mImageView.setVisibility(View.VISIBLE);
}
RecyclerView does not inflate your View every time, it rather uses the View going out of the screen in the onBindViewHolder() for the next item to appear. So you need to handle if and else condition both each time.

Related

How to change background colour to specific viewholder items in a RecycleView?

I am trying to change background color in specific item(s) in a RecycleView.
Because I need to set text too, I have the following code that works fine:
protected void populateViewHolder(RankingViewHolder viewHolder, final Ranking model, int position)
{
final Context mContext = getActivity().getApplicationContext();
viewHolder.txt_name.setText(model.getUserName());
viewHolder.txt_score.setText(String.valueOf(model.getScore()));
viewHolder.txt_class.setText(model.getUser_class());
Picasso.with(mContext).load(model.getAvatarUrl()).error(R.drawable.ic_people_black_24dp).into(viewHolder.personPhoto);
int totalRanking = adapter.getItemCount();
int realRank = totalRanking - viewHolder.getAdapterPosition();
viewHolder.ranknumber.setText("# "+String.valueOf(realRank));
}
This works as I want and realRanktakes the correct values, and the viewHolder.ranknumber.setText("# "+String.valueOf(realRank));
Sets the right text with no problem.
Now I am trying (as I got a number/text result correct, to make an if statement like this:
if(adapter.getItemCount() -viewHolder.getAdapterPosition() == 0)
{
viewHolder.itemView.setBackgroundColor(Color.GREEN);
}
if(adapter.getItemCount() -viewHolder.getAdapterPosition() == 1)
{
viewHolder.itemView.setBackgroundColor(Color.YELLOW);
}
if(adapter.getItemCount() -viewHolder.getAdapterPosition() == 2)
{
viewHolder.itemView.setBackgroundColor(Color.BLUE);
}
(I tried with String.valueOf(realRank)equality, with realRankequality too)
In all cases I have the same result. The color changes as its should at positions 1,2,3 BUT it changes at positions 7,8,9 and 14,15,16 and 21,22,23 etc.
What am I missing here?
public class RankingViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener
{
private ItemClickListener itemClickListener;
public TextView txt_name, txt_score, txt_class, ranknumber;
public ImageView personPhoto;
public RankingViewHolder(View itemView)
{
super(itemView);
txt_name = itemView.findViewById(R.id.txt_name);
txt_score = itemView.findViewById(R.id.txt_score);
personPhoto = itemView.findViewById(R.id.person_photo);
txt_class = itemView.findViewById(R.id.txt_class);
ranknumber = itemView.findViewById(R.id.ranknumber);
itemView.setOnClickListener(this);
}
public void setItemClickListener(ItemClickListener itemClickListener) {
this.itemClickListener = itemClickListener;
}
#Override
public void onClick(View view) {
itemClickListener.onClick(view , getAdapterPosition(),false);
}
}
The adapter:
adapter = new FirebaseRecyclerAdapter<Ranking, RankingViewHolder>(
Ranking.class,
R.layout.layout_ranking,
RankingViewHolder.class,
rankingTbl.orderByChild("score").limitToFirst(100)
)
This line of code int realRank = totalRanking - viewHolder.getAdapterPosition();gives a number (1,2,3,4,5,6 etc.) Why i cannot use this number to check equality?
Notice
Keeping this code for NOT working solution, just for future reference:
if(position == 0){
viewHolder.itemView.setBackgroundColor(Color.GREEN);
}
else if(position == 1){
viewHolder.itemView.setBackgroundColor(Color.YELLOW);
}
else if(position == 2){
viewHolder.itemView.setBackgroundColor(Color.BLUE);
}
else{
viewHolder.itemView.setBackgroundColor(Color.WHITE);
}
This changes the color BUT not for only 3 first items. As you scroll down, changes the color for every 3 first viewable items like before, meaning 1,2,3, 7,8,9, etc.
Update:
I dont use a custom adapter, i use FirebaseRecyclerAdapter.
Thanks to #Muhammad Haroon comment i checked that has getItemViewType. So now i m trying with it like
position =adapter.getItemViewType( 0);
if(position == 0){
viewHolder.itemView.setBackgroundColor(Color.GREEN);
}
Not working for now, but i think its the correct direction...
Update 2
With position its not possible as RecycleView recycles the views so i have the same result. The working code is
if (linearLayoutManager.findFirstVisibleItemPosition() > 0) {
viewHolder.itemView.setBackgroundResource(R.drawable.blackframe);
}
else{
viewHolder.itemView.setBackgroundResource(R.drawable.goldframe);
}
Works fine except that after scrolling loosing the change of background.
So as we want and need the perfection, any idea for keeping even after scroll?
hi try add this in your Adapater it may solve your problem.
#Override
public int getItemViewType(int position) {
return position;
}
Please give this a try
override in your custom adapter
#Override
public long getItemId(int position) {
return position;
}
and in in your adapter object:
myAdapter.setHasStableIds(true);
In populateViewHolder add these line of code
if(position == 0){
viewHolder.itemView.setBackgroundColor(Color.GREEN);
}
else if(position == 1){
viewHolder.itemView.setBackgroundColor(Color.YELLOW);
}
else if(position == 2){
viewHolder.itemView.setBackgroundColor(Color.BLUE);
}
else{
viewHolder.itemView.setBackgroundColor(Color.WHITE);
}
position is a parameter in populateViewHolder.

Click listener inside OnBindViewHolder

I have the following code for the recyclerview adapter for an android app that I'm working on right now:
#Override
public void onBindViewHolder(final FeedViewHolder contactViewHolder, final int i) {
final FeedInfo ci = feedInfoList.get(i);
//Set the text of the feed with your data
contactViewHolder.feedText.setText(ci.getFeed());
contactViewHolder.surNameText.setText(ci.getSurName());
contactViewHolder.nameText.setText(ci.getFirstName());
contactViewHolder.feedDate.setText(ci.getDate());
contactViewHolder.numberOfGoingText.setText(ci.getNumber_of_going());
contactViewHolder.numberOfInterestedText.setText(ci.getNumber_of_interested());
//seteaza fotografia de profil in postare
new ProfilePictureDownloadImage(contactViewHolder.profilePicture).execute(ci.getProfileImageURL());
ImageButton interestedButton = contactViewHolder.interestedButton;
interestedButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
int position = i;
FeedInfo fi = feedInfoList.get(position);
int displayedNumberOfInterested = Integer.parseInt(ci.getNumber_of_interested()) + 1;
contactViewHolder.numberOfInterestedText.setText(Integer.toString(displayedNumberOfInterested));
System.out.println("emilutzy interested from within" + fi.getPostID());
contactViewHolder.surNameText.setText("kk");
}
});
}
The problem is the click listener. In theory the button I press should increment the number right next to it. However, since I have to declare onBindViewHolder's arguments as final, only the first click works, the rest of the clicks do not change the value of the number. I am new to Android, so could you please help me find a better solution?
There's a nice method called getAdapterPosition() that you can use in your RecyclerView's ViewHolder.
Instead of setting the click listener in onBindViewHolder, set it in the constructor of your ViewHolder like so:
public class FeedViewHolder extends RecyclerView.ViewHolder {
private TextView feedText;
private TextView surNameText;
private Button interestedButton;
// ... the rest of your viewholder elements
public FeedViewHolder(View itemView) {
super(itemView);
feedtext = itemView.findViewById(R.id.feedtext);
// ... find your other views
interestedButton.setOnClickListener(new View.OnClickListener() {
final FeedInfo fi = feedInfoList.get(getAdapterPosition());
int numInterested = Integer.parseInt(ci.getNumber_of_interested()) + 1;
// setting the views here might work,
// but you will find that they reset themselves
// after you scroll up and down (views get recycled).
// find a way to update feedInfoList,
// I like to use EventBus to send an event to the
// host activity/fragment like so:
EventBus.getDefault().post(
new UpdateFeedInfoListEvent(getAdapterPosition(), numInterested));
// in your host activity/fragment,
// update the list and call
// notifyDatasetChanged/notifyDataUpdated()
//on this RecyclerView adapter accordingly
});
}
}
Don't set your position in onBindViewHolder to final (Android Studio will warn you why).
I'm not sure how the object FeedInfo looks like but you could also at a method called for example increaseNumberOfInterested() which would increase the value of Number_of_interested by one and would persist in the object when the recyclerview recycle the cell. it would like kind of like below
#Override
public void onBindViewHolder(final FeedViewHolder contactViewHolder, final int i) {
final FeedInfo ci = feedInfoList.get(i);
//Set the text of the feed with your data
contactViewHolder.numberOfInterestedText.setText(ci.getNumber_of_interested());
contactViewHolder.interestedButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
//Increase the number of interested in the object, so it can be persisted when cell is reclycled
ci.setNumberOfInterested(ci.getNumber_of_interested()) + 1);
//Get new value and display
contactViewHolder.numberOfInterestedText.setText(Integer.toString(ci.getNumber_of_interested()));
}

favorite button in android not working properly

Hii i'm making an app where i have small heart image onclick of that image i've set an onclick listener so when i click on that image it is replaced by another red coloured heart image.
so my problem is when i again click on red heart image it doesnt turn to its normal state which is blank heart vector image as i'm new in android i dont have much knowledge please if someone can guide.
my code for image onclick
#Override
public void onBindViewHolder(FeedViewHolder holder, int position) {
int image_id = images[position];
//holder.background_image_layout.setImageDrawable(null);
//holder.background_image_layout.setImageResource(image_id);
holder.background_image.setBackgroundResource(image_id);
}
#Override
public int getItemCount() {
return images.length;
}
public static class FeedViewHolder extends RecyclerView.ViewHolder {
CustomTextViewMedium first_text,second_text,third_text,fourth_text,fifth_text,sixth_text,
seventh_text;
ImageView favourite_image;
CardView primary_card;
LinearLayout background_image;
ImageView background_image_layout;
CircleImageView profile_image;
public FeedViewHolder(View itemView) {
super(itemView);
background_image = (LinearLayout)itemView.findViewById(R.id.background_image);
primary_card = (CardView)itemView.findViewById(R.id.primary_card);
first_text = (CustomTextViewMedium)itemView.findViewById(R.id.first_text);
second_text = (CustomTextViewMedium)itemView.findViewById(R.id.second_text);
third_text = (CustomTextViewMedium)itemView.findViewById(R.id.third_text);
fourth_text = (CustomTextViewMedium)itemView.findViewById(R.id.fourth_text);
fifth_text = (CustomTextViewMedium)itemView.findViewById(R.id.fifth_text);
sixth_text = (CustomTextViewMedium)itemView.findViewById(R.id.sixth_text);
seventh_text = (CustomTextViewMedium)itemView.findViewById(R.id.seventh_text);
favourite_image = (ImageView)itemView.findViewById(R.id.favourite_image);
background_image_layout = (ImageView) itemView.findViewById(R.id.background_image_layout);
profile_image = (CircleImageView)itemView.findViewById(R.id.profile_image);
favourite_image.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if(favourite_image.isPressed()){
favourite_image.setImageResource(R.drawable.ic_heart);
favourite_image.setScaleType(ImageView.ScaleType.CENTER_CROP);
}
else {
favourite_image.setImageResource(R.drawable.ic_favorite_border_black_24dp);
favourite_image.setScaleType(ImageView.ScaleType.CENTER_CROP);
}
}
});
}
}
Use if condition like this :-
first globally define like this :-
boolean imageChange = true;
then do this in setOnClickListener like this :-
favourite_image.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if(imageChange ){
favourite_image.setImageResource(R.drawable.ic_heart);
favourite_image.setScaleType(ImageView.ScaleType.CENTER_CROP);
imageChange = false;
}else {
favourite_image.setImageResource(R.drawable.ic_favorite_border_black_24dp);
favourite_image.setScaleType(ImageView.ScaleType.CENTER_CROP);
imageChange = true;
}
}
});
Problem is that favourite_image.isPressed() is not persistent state of the View. It will be true only while user holds its finger on the view.
To overcome this you have two similar options:
Option #1
Instead of checking isPressed you can check some other state, for example isSelected. Since this is ImageView you probably need to set the state manually on click.
public void onClick(View v) {
if(favourite_image.isSelected()){
favourite_image.setImageResource(R.drawable.ic_heart);
favourite_image.setScaleType(ImageView.ScaleType.CENTER_CROP);
favourite_image.setSelected(false)
}
else {
favourite_image.setImageResource(R.drawable.ic_favorite_border_black_24dp);
favourite_image.setScaleType(ImageView.ScaleType.CENTER_CROP);
favourite_image.setSelected(true)
}
}
Options #2
Use some simple boolean to keep track of the selected state, and set/chec its values similarity to above code.

RecyclerView, pass multiple views via onClickListener to cycle through options

I have the following which lets the user click on an image and it turns the image invisible:
holder.redView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
ManualPlayingChange.notToPlaying(view);
}
});
public static void notToPlaying(View a) {
if(a.isShown()) {
a.setVisibility(View.INVISIBLE);
// b.setVisibility(View.VISIBLE);
}
}
What I want to do, is pass through another View, so that a different Ciew also changes on the same click.
The views I have:
public ViewHolder(View p) {
super(p);
playerView = p.findViewById(R.id.aPlayerInTheList);
greenView = p.findViewById(R.id.isPlaying);
amberView = p.findViewById(R.id.mightBePlaying);
redView = p.findViewById(R.id.notPlaying);
}
So I just want to be able to cycle through the 3 images.
You can just pass the holder (i.e ViewHolder) itself in notToPlaying() method instead of single view and then access all the views like:
public static void notToPlaying(ViewHolder holder){
// now you can access all the views
holder.playerView.setVisibility(View.VISIBLE);
holder.redView.setVisibility(View.GONE); // and so on.
}

How to set OnClickListener to get position of different ArrayLists using same Adapter java class?

I am making an Android app, and currently have 3 different activities. One that displays 'Recent' images from Flickr in a Recyclerview, another that displays 'Interesting' images from Flickr in a Recyclerview, as well as a 'Details' activity which displays a larger image view and more information about a particular photo when it is clicked.
I have two ArrayLists: recentImageList and interestingImageList, which use the same Adapter class to display the different images and their attributes (title, owner etc.) in their Recyclerviews, depending on the activity.
I have these two activities working and showing the correct content, and when I click on a 'recent' photo, it displays the same 'recent' photo on the 'details' page.
However my problem is that when an 'interesting' image is clicked, it passes the position of the 'recent' image to the Intent instead of the position of the 'interesting' image I clicked on. Therefore this displays the 'recent' image in the 'Details' activity, and not the 'interesting' photo I clicked on.
I am unsure how to pass the correct position of the interestingImageList array item in my onClickListener, so that the correct corresponding image is shown in my 'details' activity. Do I need some sort of if statement in my OnClickListener to determine which arraylist position is passed to the intent?
I'd be grateful for any help you guys can give. See the code for my ImageListAdapter class below:
public class ImageListAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private Context context;
ArrayList<ImageInfo> recentImageList;
ArrayList<ImageInfo> interestingImageList;
private int whichActivity;
public ImageListAdapter(Context context, ArrayList<ImageInfo> recentImageList,
ArrayList<ImageInfo> interestingImageList, int whichView) {
this.context = context;
this.recentImageList = recentImageList;
this.interestingImageList = interestingImageList;
whichActivity = whichView;
}
#Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View itemView = LayoutInflater.from(context).inflate(R.layout.cell_image_card, parent, false);
return new ImageViewHolder(itemView);
}
#Override
public void onBindViewHolder(RecyclerView.ViewHolder viewHolder, int position) {
if (whichActivity == 0) {
((ImageViewHolder) viewHolder).populate(recentImageList.get(position));
ImageInfo recentInfo = recentImageList.get(position);
} else if (whichActivity == 1) {
((ImageViewHolder) viewHolder).populate(interestingImageList.get(position - recentImageList.size()));
ImageInfo interestingInfo = interestingImageList.get(position);
}
}
#Override
public int getItemCount() {
return recentImageList.size() + interestingImageList.size();
}
public class ImageViewHolder extends RecyclerView.ViewHolder {
public TextView imageTitle, ownerTitle, tags;
public NetworkImageView mainImage, ownerImage;
public ImageViewHolder(View itemView) {
super(itemView);
imageTitle = (TextView) itemView.findViewById(R.id.imageTitle);
ownerTitle = (TextView) itemView.findViewById(R.id.ownerTitle);
mainImage = (NetworkImageView) itemView.findViewById(R.id.mainImage);
mainImage.setOnClickListener(onClick);
ownerImage = (CircularNetworkImageView) itemView.findViewById(R.id.ownerImage);
}
public void populate(ImageInfo imageInfo) {
ownerTitle.setText(imageInfo.owner);
imageTitle.setText(imageInfo.title);
mainImage.setImageUrl(imageInfo.url_m, NetworkMgr.getInstance(context).imageLoader);
ownerImage.setImageUrl(imageInfo.ownerPic, NetworkMgr.getInstance(context).imageLoader);
}
View.OnClickListener onClick = new View.OnClickListener() {
#Override
public void onClick(View v) {
Intent intent = new Intent(context, DetailsActivity.class);
int position = ImageViewHolder.this.getLayoutPosition();
intent.putExtra("PHOTO_POSITION", position);
context.startActivity(intent);
}
};
}
}
You need two different instances of your adapter, each one for each list this seems like a wrong implementation
Each recyclerview should have its own adapter instance.
e.g.
new
ImageListAdapter(this, recentImageList, null, whichView);
and
new
ImageListAdapter(this, null , interestingImageList,whichView);
For two different RecyclerView you will need two instance of the adapter. To go to the details activity, it will be better to get the selected or clicked item position in activity and start the details activity from present activity. To get the selected position from the adapter you can use interface. Here is an open source RecyclerView-Listener library to get the selected item position. You can use it or understand the concept and implement yourself.
Thank you everyone for your help! I've fixed it!
I realised that my original code was correct, however the line in my Details Activity:
photo = NetworkMgr.getInstance(this).recentImageList.get(photoPosition);
was the problem, as this line retrieved only the position for the recent images and didn't account for the interesting images. Therefore, in my OnClickListener I used an if statement for the two whichActivitys and putExtra a number to determine which arraylist needs to have its position retrieved in Details activity. See below:
ImageListAdapter -
View.OnClickListener onClick = new View.OnClickListener() {
#Override
public void onClick(View v) {
if (whichActivity == 0) {
Intent intent = new Intent(context, DetailsActivity.class);
int position = ImageViewHolder.this.getLayoutPosition();
int imageListCode = 1;
intent.putExtra("PHOTO_POSITION", position);
intent.putExtra("IMAGELIST_CODE", imageListCode);
context.startActivity(intent);
}
else if (whichActivity == 1) {
Intent intent = new Intent(context, DetailsActivity.class);
int position = ImageViewHolder.this.getLayoutPosition();
int imageListCode = 2;
intent.putExtra("PHOTO_POSITION", position);
intent.putExtra("IMAGELIST_CODE", imageListCode);
context.startActivity(intent);
}
}
};
DetailsActivity -
Intent intent = getIntent();
photoPosition = intent.getIntExtra("PHOTO_POSITION", 0);
code = intent.getIntExtra("IMAGELIST_CODE", 0);
if (code == 1) {
photo = NetworkMgr.getInstance(this).recentImageList.get(photoPosition);
}
else if (code == 2) {
photo = NetworkMgr.getInstance(this).interestingImageList.get(photoPosition);
}

Categories