I have a HorizontalGridView and all is working well, however I am loading images with Picasso and whenever an image loads, the HorizontalGridView snaps back to the first item/starting scroll position. I also have a map fragment on the activity and notice that when the map is interacted with, the HorizontalGridView displays the the same behavior. Below is the adapter code. Please help, have been stuck on this one for a couple of days now...
public class GridElementAdapter extends RecyclerView.Adapter<GridElementAdapter.SimpleViewHolder>{
private Context context;
private Deal[] mDeals;
public GridElementAdapter(Context context, Deal[] deals){
this.context = context;
this.mDeals = deals;
}
public static class SimpleViewHolder extends RecyclerView.ViewHolder {
public final ImageView dealImage;
public final TextView dealTitle;
public final TextView dealSubtitle;
public final TextView dealPrice;
public final TextView dealTime;
public final TextView dealDays;
public SimpleViewHolder(View view) {
super(view);
dealImage = (ImageView) view.findViewById(R.id.gridDealImageView);
dealTitle = (TextView) view.findViewById(R.id.gridTitleLabel);
dealSubtitle = (TextView) view.findViewById(R.id.gridSubtitleLabel);
dealPrice = (TextView) view.findViewById(R.id.gridPriceLabel);
dealTime = (TextView) view.findViewById(R.id.gridAvailableTimeLabel);
dealDays = (TextView) view.findViewById(R.id.gridAvailableDaysLabel);
}
}
#Override
public SimpleViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
final View view = LayoutInflater.from(this.context).inflate(R.layout.deal_grid_item, parent, false);
return new SimpleViewHolder(view);
}
#Override
public void onBindViewHolder(SimpleViewHolder holder, final int position) {
String dealImageUrl = "http://api.cheapeat.com.au/deals/" + mDeals[position].getPhotoId() + "/photo";
Context context = holder.dealImage.getContext();
Picasso.with(context).load(dealImageUrl).placeholder(R.drawable.deal_image_placeholder).into(holder.dealImage);
holder.dealTitle.setText(mDeals[position].getName());
holder.dealPrice.setText(mDeals[position].getPriceData());
holder.dealSubtitle.setText(mDeals[position].getDescription());
holder.dealTime.setText(mDeals[position].getAvailabilityTime());
holder.dealDays.setText(mDeals[position].getFormattedAvailableDays(mDeals[position].getAvailabilityDay()));
}
#Override
public long getItemId(int position) {
return position;
}
#Override
public int getItemCount() {
return this.mDeals.length;
}
}
So I finally managed to solve this one. Turns out I hadn't set the LayoutManager for the HorizontalGridView. Specifically, in the activity where I set the adapter:
// Had this
horizontalGridView = (HorizontalGridView) findViewById(R.id.gridView);
GridElementAdapter adapter = newGridElementAdapter(VenueProfileActivity.this, mDeals);
horizontalGridView.setAdapter(adapter);
// This needed to be added
HorizontalGridView.LayoutManager layoutManager = new LinearLayoutManager(VenueProfileActivity.this, LinearLayoutManager.HORIZONTAL, false);
horizontalGridView.setLayoutManager(layoutManager);
horizontalGridView.setHasFixedSize(true);
Hopefully this saves some headaches, as I've seen this question floating around with no correct solution yet.
Related
I am building a simple blog feature and using picasso to load images into recyclerview in android studio but the images don't load, Please can someone help me understand why. See the related code section below:
public class BlogRecyclerViewAdapter extends RecyclerView.Adapter {
private Context context;
private List blogList;
// Constructor
public BlogRecyclerViewAdapter(Context context, List<Blog> blogList) {
this.context = context;
this.blogList = blogList;
}
#NonNull
#Override
public ViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext())
.inflate(R.layout.post_row, parent, false);
return new ViewHolder(view, context);
}
#Override
public void onBindViewHolder(#NonNull ViewHolder holder, int position) {
// Now bind the views and the data
Blog blog = blogList.get(position);
String imageUrl = null;
holder.title.setText(blog.getTitle());
holder.desc.setText(blog.getDesc());
DateFormat dateFormat = DateFormat.getDateInstance();
String formattedDate = dateFormat.format(new Date(Long.valueOf(blog.getTimeStamp())).getTime());
holder.timeStamp.setText(formattedDate);
imageUrl = blog.getImage();
//TODO: Use Picasso library to load image
Picasso.get().load(imageUrl).into(holder.image);
}
#Override
public int getItemCount() {
return blogList.size();
}
public class ViewHolder extends RecyclerView.ViewHolder {
public TextView title;
public TextView desc;
public TextView timeStamp;
public ImageView image;
String userId;
public ViewHolder(#NonNull View view, Context ctx) {
super(view);
context = ctx;
title = (TextView) view.findViewById(R.id.postTitleList);
desc = (TextView) view.findViewById(R.id.postTextList);
image = (ImageView) view.findViewById(R.id.postImageList);
timeStamp = (TextView) view.findViewById(R.id.timeStampList);
userId = null;
view.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// We can go to the next activity
}
});
}
}
}
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.
As you can see in the screenshot, my project contains a RecyclerView (for categories of food) which contains more RecyclerViews (for the ingredients). But iv'e got a problem, my RecyclerView is messing up the order. I debuged the project and the parameters are just fine but the RecyclerView is displaying them wrong. As you can see in the picture, Fruits ingredients are displayed in the Dairy category.
IngredientSectionAdapter.Java
(the main adapter,which contain more RecyclerViews)
class SectionViewHolder extends RecyclerView.ViewHolder {
private TextView sectionBtn;
private RecyclerView itemRecyclerView;
public SectionViewHolder(View itemView) {
super(itemView);
sectionBtn = (TextView) itemView.findViewById(R.id.text_category);
itemRecyclerView = (RecyclerView) itemView.findViewById(R.id.ingredientsRecycler);
}
}
private Context context;
private ArrayList<IngredientSectionModel> sectionModelArrayList;
ArrayList<IngredientItemAdapter> adapters;
public IngredientSectionAdapter(Context context, ArrayList<IngredientSectionModel> sectionModelArrayList) {
this.context = context;
this.sectionModelArrayList = sectionModelArrayList;
adapters = new ArrayList<IngredientItemAdapter>();
}
#Override
public SectionViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
LayoutInflater inflater = LayoutInflater.from(context);
View v = inflater.inflate(R.layout.parent_list,null);
return new SectionViewHolder(v);
}
#Override
public void onBindViewHolder(SectionViewHolder holder, int position) {
final IngredientSectionModel sectionModel = sectionModelArrayList.get(position);
holder.itemRecyclerView.setTag(holder.itemRecyclerView.getVisibility());
final RecyclerView sectionList = holder.itemRecyclerView;
holder.sectionBtn.setText(sectionModel.getSectionLabel());
//recycler view for items
holder.itemRecyclerView.setHasFixedSize(true);
holder.itemRecyclerView.setNestedScrollingEnabled(false);
/* set layout manager on basis of recyclerview enum type */
StaggeredGridLayoutManager staggeredGridLayoutManager = new StaggeredGridLayoutManager(3,1);
adapters.add(new IngredientItemAdapter(context, sectionModel.getItemArrayList()));
int resId = R.anim.grid_layout_animation_from_bottom;
//LayoutAnimationController animation = AnimationUtils.loadLayoutAnimation(context, resId);
holder.itemRecyclerView.setLayoutManager(staggeredGridLayoutManager);
holder.itemRecyclerView.setAdapter(adapters.get(position));
//holder.itemRecyclerView.setLayoutAnimation(animation);
//toggle visibilty of inner RecyclerView (ingredients, not categories)
holder.sectionBtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (sectionList.getVisibility() == View.VISIBLE){
sectionList.setVisibility(View.GONE);
}
else
{
sectionList.setVisibility(View.VISIBLE);
}
}
});
}
What can cause this?
Every time onBindViewHolder is called you create a new IngredientItemAdapter and add it to your adapters, and then you call holder.itemRecyclerView.setAdapter(adapters.get(position)). However, adapters.get(position) is not the adapter you just created. Your adapter will get bigger and bigger. Try this
IngredientItemAdapter adapter = adapters.get(position);
adapter.setIngredients(sectionModel.getItemArrayList());
holder.itemRecyclerView.setAdapter(adapter);
#Override
public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) {
Collections.swap(queuee, viewHolder.getAdapterPosition(), target.getAdapterPosition());
// and notify the adapter that its dataset has changed
adapterr.notifyItemMoved(viewHolder.getAdapterPosition(), target.getAdapterPosition());
return true;
}
With the above code i m able to swap the items in the recyclerview ,but now the problem is i also want to make the same respective changes to database.
How to go about?
queuee receives the all the data from the database
queuee is a arraylist which is used to set the recyclerview adapter
Regards
Thanks
Adapter:
public class QueueAdapter extends RecyclerView.Adapter<QueueAdapter.MyViewHolder> {
private Context mContext;
public ArrayList<Music> queue;
MediaPlayer mPlayer = new MediaPlayer();
public class MyViewHolder extends RecyclerView.ViewHolder {
public TextView title,tt,artist;
public Button play,stop;
public ImageButton option;
public MyViewHolder(View view) {
super(view);
title = (TextView) view.findViewById(R.id.songtitle1);
artist = (TextView)view.findViewById(R.id.artist1);
// play = (Button) view.findViewById(R.id.play);
// stop = (Button) view.findViewById(R.id.stop);
// tt = (TextView) view.findViewById(R.id.song_name);
option = (ImageButton) view.findViewById(R.id.option1);
}
}
public QueueAdapter(Context mContext, ArrayList<Music> queue) {
this.mContext = mContext;
this.queue = queue;
}
#Override
public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View itemView = LayoutInflater.from(parent.getContext())
.inflate(R.layout.queue_card, parent, false);
return new MyViewHolder(itemView);
}
#Override
public void onBindViewHolder(final MyViewHolder holder, final int position) {
Music mu1 = queue.get(position);
holder.title.setText(mu1.getTitle());
holder.artist.setText(mu1.getArtist());
final String link =mu1.getUrl();
final String SongName = mu1.getTitle();
}
#Override
public int getItemCount() {
return queue.size();
}
public void removeItem(int position) {
queue.remove(position);
notifyItemRemoved(position);
notifyItemRangeChanged(position, queue.size());
}
}
activity:
recyclerView = (RecyclerView) findViewById(R.id.recyclerqueue);
recyclerView.setHasFixedSize(true);
layoutManager = new LinearLayoutManager(this);
recyclerView.setLayoutManager(layoutManager);
recyclerView.setItemAnimator(new DefaultItemAnimator());
adapterr = new QueueAdapter(this,queuee);
recyclerView.addItemDecoration(new DividerItemDecoration(this, LinearLayoutManager.VERTICAL));
// adapterr.
recyclerView.setAdapter(adapterr);
initSwipe();
In my opinion, you can do it on OnDestroy method in your Activity. Specifically speaking, firstly, you can get all your data from your adapter, and then delete datas in your database, at last, you can save your data obtained from your adapter again. In this moment, the sequence of your datas is what you want, and this way is easy to code. I'd rather you don't
update your database during onMove, because it's too frequently during your drag, and operates all data is easier than two datas in database.
I need a solution of how to do the following thing using Android Recycler View.
I have Multiple Images and i need to select only one image like how the radio button works. Now i can select all the images that i have, but i need to restrict the current working behavior to work like the radio button (E.g.) If one is selected the other images that i have should not be selected.
I have tried with the below code but no luck for me. Can anyone rectify the mistake and make the code workable as per my need.
public class StarCountAdapter extends RecyclerView.Adapter<StarCountAdapter.StarCountHolder> {
Context context;
LayoutInflater inflater;
List<StarCount> starCounts = new ArrayList<>();
public StarCountAdapter(Context context, List<StarCount> starCounts) {
this.context = context;
this.inflater = LayoutInflater.from(context);
this.starCounts = starCounts;
}
#Override
public StarCountHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = inflater.inflate(R.layout.star_count_row,parent,false);
return new StarCountHolder(view);
}
#Override
public void onBindViewHolder(StarCountHolder holder, int position) {
StarCount model = starCounts.get(position);
Picasso.with(context)
.load("http://"+model.getImagePath())
.into(holder.starImage);
holder.actorName.setText(model.getName());
holder.counts.setText(""+model.getCount());
}
#Override
public int getItemCount() {
return starCounts.size();
}
public class StarCountHolder extends RecyclerView.ViewHolder {
ImageView starImage;
TextView actorName,counts;
StarCount modelCount;
public StarCountHolder(View itemView) {
super(itemView);
starImage = (ImageView) itemView.findViewById(R.id.starCountIv);
actorName = (TextView) itemView.findViewById(R.id.acterName);
counts = (TextView) itemView.findViewById(R.id.counts);
}
}
}
help needed to solve this issue since i am struck up for more than a Day. Share thoughts to rectify my Error in the code and rectify my error.
public int selectedPosition = -1
public class StarCountHolder extends RecyclerView.ViewHolder {
ImageView starImage;
TextView actorName,counts;
StarCount modelCount;
public StarCountHolder(View itemView) {
super(itemView);
starImage = (ImageView) itemView.findViewById(R.id.starCountIv);
actorName = (TextView) itemView.findViewById(R.id.acterName);
counts = (TextView) itemView.findViewById(R.id.counts);
itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
selectedPosition = getLayoutPosition());
notifyDatasetChanged();
}
});
}
}
Now you are done with the selected item position, change it in your binder
#Override
public void onBindViewHolder(StarCountHolder holder, int position) {
StarCount model = starCounts.get(position);
Picasso.with(context)
.load("http://"+model.getImagePath())
.into(holder.starImage);
holder.actorName.setText(model.getName());
holder.counts.setText(""+model.getCount());
if(selectedPosition == position){
// do whatever you want to do to make it selected.
}
}
Now to get the selected item in your activity, you can do something like this...
inside activity
StartCount startC = starCounts.get(adapter.selectedPosition);
hope it helps