Align messages left/right - java

I using the firebase API. to send and retrieve messages. However I am having trouble in trying to set layout for the sender/retriever so Messages will align left/right. At the moment I only have one layout which both the sender/retriever is using, but not sure on how to set different layouts.
public class MessageAdapter extends RecyclerView.Adapter<MessageViewHolder> {
private List<Message> messagesList;
private DatabaseReference databaseReference;
private DatabaseReference userDatabaseRef;
private FirebaseAuth firebaseAuth;
private Context context;
private String imageUrl;
public MessageAdapter(List<Message> messagesList) {
this.messagesList = messagesList;
}
#Override
public MessageViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
Message c = messagesList.get(viewType);
String sender = c.getFrom();
databaseReference = FirebaseDatabase.getInstance().getReference().child("Users").child(sender);
View v = LayoutInflater.from(parent.getContext())
.inflate(R.layout.messages_layout, parent, false);
return new MessageViewHolder(v);
}
#Override
public void onBindViewHolder(final MessageViewHolder viewHolder, final int index) {
final Message c = messagesList.get(index);
final String sender = c.getFrom();
databaseReference = FirebaseDatabase.getInstance().getReference().child("Users").child(sender);
databaseReference.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
imageUrl = dataSnapshot.child("image").getValue(String.class);
viewHolder.setUserimage(context,imageUrl);
String name = dataSnapshot.child("name").getValue().toString();
viewHolder.displayName.setText(name);
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
viewHolder.messageText.setText(c.getMessage());
viewHolder.time.setText(EpochtimeToDateAndTimeString(c.getTime()));
}
#Override
public int getItemCount() {
return messagesList.size();
}
public String EpochtimeToDateAndTimeString(long time) {
Date date = new Date(time);
DateFormat format = new SimpleDateFormat("dd/MM/yyyy HH:mm:ss");
format.setTimeZone(TimeZone.getTimeZone("Etc/UTC"));
String formatted = format.format(date);
return formatted;
}
}
MessageViewHolder
public class MessageViewHolder extends RecyclerView.ViewHolder {
public TextView messageText;
public TextView displayName;
public TextView time;
public ImageView showImage;
public MessageViewHolder(View view) {
super(view);
messageText = (TextView) view.findViewById(R.id.messagetext);
displayName = (TextView) view.findViewById(R.id.displayname);
time = (TextView) view.findViewById(R.id.timestamp);
showImage = (ImageView) view.findViewById(R.id.imageview_post_userimage3);
}

You should use different view holders for sender's and receiver's messages.
Create two layouts: R.layout.sender_message_layout and R.layout.receiver_message_layout
Create two viewholders: SenderMessageHolder and ReceiverMessageHolder.
Define view type integer constants:
public static final int VIEW_TYPE_SENDER = 1;
public static final int VIEW_TYPE_RECEIVER = 2;
Implement getItemViewType(int position) on your adapter:
if(messageList.get(position).getFrom().equals(...)) {
return VIEW_TYPE_SENDER;
} else {
return VIEW_TYPE_RECEIVER;
}
In onCreateViewHolder() function check view type and create different holders for different senders:
View v;
if(viewType == VIEW_TYPE_SENDER) {
v = LayoutInflater.from(parent.getContext())
.inflate(R.layout.sender_message_layout, parent, false);
return new SenderMessageHolder(v);
} else {
v = LayoutInflater.from(parent.getContext())
.inflate(R.layout.receiver_message_layout, parent, false);
return new ReceiverMessageHolder(v);
}
In onBindViewHolder() check holder instance to bind values to views accordingly:
if(holder instanceof SenderMessageHolder) {
((SenderMessageHolder) holder).textView.setText(...);
...
} else {
((ReceiverMessageHolder) holder).textView.setText(...);
...
}
Hope that it helps!

There are a couple of ways to do this. The way I would recommend is by overriding the public int getItemViewType(int position) for your adapter. You must implement logic here to help you determine the layout file to return and returning a view type constant.
public static int INCOMING = 1;
public static int OUTGOING = 2;
#Override
public int getItemViewType(int position) {
int viewType = -1;
Message m = messagesList.get(position)
//Logic here determining if m is left or right aligned and
// return either
// MessageAdapter.OUTGOING OR MessageAdapter.INCOMING
return viewType;
}
Create a left-aligned layout file and a right-aligned layout file. Your new onCreateviewHolder() adapter method will look something like this:
#Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
Message c = messagesList.get(viewType);
String sender = c.getFrom();
databaseReference = FirebaseDatabase.getInstance().getReference().child("Users").child(sender);
View v;
if( viewType == MessageAdapter.INCOMING ) {
v = LayoutInflater.from(parent.getContext())
.inflate(R.layout.messages_layout_left, parent, false);
}else if ( viewType == MessageAdapter.OUTGOING) {
v = LayoutInflater.from(parent.getContext())
.inflate(R.layout.messages_layout_right, parent, false);
}
return new MessageViewHolder(v);
}

Related

How can i modify getItemViewType() with adapter input as a string and cursor?

I have created a recycler view and want to put two lists in it.
The first list is just a string that gets changed into fonts, which I have implemented in the onBindView method.
The second list is the cursor which includes the favorite fonts of the users.
I followed this answer on SO but I don't have any idea how I'm going to modify the getItemViewType() method so that I can get to know which list type is currently calling for view.
My adapter code
here data is the class that contains the list of fonts
public class MyAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private final int VIEW_TYPE_TEXTVIEW = 0;
private final int VIEW_TYPE_ITEM_1 = 1;
private int total_no_of_row;
private Context context;
private String str;
private Cursor cursor;
private final LayoutInflater inflater;
public MyAdapter(Context context, int total_no_of_row, String str , Cursor cursor) {
this.context = context;
this.total_no_of_row = total_no_of_row;
this.str = str;
this.cursor = cursor;
inflater = LayoutInflater.from(context);
}
#Override
public int getItemViewType(int position) {
return super.getItemViewType(position);
}
#NonNull
#Override
public RecyclerView.ViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
if(viewType == VIEW_TYPE_TEXTVIEW) {
View view = inflater.inflate(R.layout.row_layout, parent, false);
return new Item1Holder(view);
}
else if (viewType == VIEW_TYPE_ITEM_1){
View view = inflater.inflate(R.layout.row_layout, parent, false);
return new Item2Holder(view);
}
return null;
}
#Override
public void onBindViewHolder(#NonNull RecyclerView.ViewHolder holder, int position) {
if(holder instanceof Item1Holder){
data d = new data();
cursor.moveToPosition(position);
Log.d("this2",cursor.getInt(1)+"");
String temp = d.Convert(str, cursor.getInt(1));
((Item1Holder)holder).textView.setText(temp);
((Item1Holder)holder).rowNumber.setText("⚫");
((Item1Holder)holder).fav.setImageResource(R.drawable.ic_baseline_favorite_24);
}else if(holder instanceof Item2Holder){
data d = new data();
String temp = d.Convert(str, position);
((Item2Holder)holder).textView.setText(temp);
((Item2Holder)holder).rowNumber.setText((position + 1) + ".");
if (util.COPY) {
if (position == util.CURRENT_POSITION) {
((Item2Holder)holder).imageView.setBackgroundResource(R.drawable.background_when_row_clicked);
} else {
((Item2Holder)holder).imageView.setBackgroundResource(R.drawable.background_when_row_clicked_two);
}
}
}
}
#Override
public int getItemCount() {
return total_no_of_row + cursor.getCount();
}
class Item1Holder extends RecyclerView.ViewHolder {
TextView textView;
ImageView imageView , fav;
TextView rowNumber;
public Item1Holder(#NonNull View itemView) {
super(itemView);
textView = itemView.findViewById(R.id.text_body);
imageView = itemView.findViewById(R.id.copy_png);
rowNumber = itemView.findViewById(R.id.row_number);
fav = itemView.findViewById(R.id.fav);
}
}
class Item2Holder extends RecyclerView.ViewHolder {
TextView textView;
ImageView imageView , fav;
TextView rowNumber;
public Item2Holder(#NonNull View itemView) {
super(itemView);
textView = itemView.findViewById(R.id.text_body);
imageView = itemView.findViewById(R.id.copy_png);
rowNumber = itemView.findViewById(R.id.row_number);
fav = itemView.findViewById(R.id.fav);
}
}
}
in main activity
here temp is the string that users want to convert into the fonts
Cursor cursor = show();
myAdapter = new MyAdapter(this , 500 , temp , cursor);
recyclerView.setAdapter(myAdapter);
LinearLayoutManager linearLayoutManager = new LinearLayoutManager(this);
recyclerView.setLayoutManager(linearLayoutManager);
I'm not a professional android developer I'm still learning the stuff. so sorry if my code is too bad to understand
You are passing null in the onCreateViewHolder() method, and not specified position in getItemViewType() method. All you have to do is, update your code. do not pass the null value in the onCreateViewHolder method. Below code, I've tried, and works perfectly. Happy coding...
private static final int CATEGORY = 1;
private static final int NAME = 2;
private Collection<CategorizedName> data;
#Override
public int getItemViewType(int position) {
if (items.get(position) instanceof Category) {
return CATEGORY;
} else if (items.get(position) instanceof Name) {
return NAME;
}
throw new RuntimeException('error');
}
#Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup viewGroup, int viewType) {
RecyclerView.ViewHolder viewHolder;
LayoutInflater inflater = LayoutInflater.from(viewGroup.getContext());
switch (viewType) {
case CATEGORY:
View categoryView = inflater.inflate(R.layout.viewholder_category, viewGroup,
false);
viewHolder = new CategoryViewHolder(categoryView);
break;
case NAME:
View nameView = inflater.inflate(R.layout.viewholder_name, viewGroup, false);
viewHolder = new NameViewHolder(nameView);
break;
}
return viewHolder;
}
#Override
public void onBindViewHolder(RecyclerView.ViewHolder viewHolder, int position) {
switch (viewHolder.getItemViewType()) {
case USER:
CategoryViewHolder categoryViewHolder = (CategoryViewHolder) viewHolder;
bindCategoryViewHolder(categoryViewHolder, position);
break;
case IMAGE:
NameViewHolder nameViewHolder = (NameViewHolder) viewHolder;
bindNameViewHolder(nameViewHolder, position);
break;
}
}
Replace your getItemViewType() with this
#Override
public int getItemViewType(int position){
if(position < total_no_of_row){
return VIEW_TYPE_TEXTVIEW;
}
if(position - total_no_of_row < cursor.getCount()){
return VIEW_TYPE_ITEM_1;
}
return -1;
}
you can also refer to my answer this

RecyclerView: different ViewType by different button

I have a recycler view to show an activity timeline and three floating buttons that click to add activity. How can I code three buttons to a different view? How can I pass the condition to the Adapter?
Now I can show only one viewType.
thx a lot.
Adapter.java
public class TripAdapter extends RecyclerView.Adapter<TripAdapter.TripHolder> {
private List<Trip> trips = new ArrayList<>();
private OnItemClickListener listener;
#NonNull
#Override
public TripHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View itemView = LayoutInflater.from(parent.getContext()).inflate(R.layout.trip_item, parent, false);
return new TripHolder(itemView);
}
#Override
public void onBindViewHolder(#NonNull TripHolder holder, int position) {
Trip currentTrip = trips.get(position);
holder.textViewLodgingTitle.setText(currentTrip.getLodgingTitle());
holder.textTextViewLodgingCheckInDateTime.setText(currentTrip.getLodgingCheckInDateTime());
holder.textTextViewLodgingCheckOutDateTime.setText(currentTrip.getLodgingCheckOutDateTime());
holder.textViewLodgingAddress.setText(currentTrip.getLodgingAddress());
}
#Override
public int getItemCount() {
return trips.size();
}
public void setTrips(List<Trip> trips) {
this.trips = trips;
notifyDataSetChanged();
}
public Trip getTripAt(int position) {
return trips.get(position);
}
class TripHolder extends RecyclerView.ViewHolder {
//lodging
private TextView textViewLodgingTitle;
private TextView textTextViewLodgingCheckInDateTime;
private TextView textTextViewLodgingCheckOutDateTime;
private TextView textViewLodgingAddress;
private TextView textViewLodgingPhone;
private TextView textViewLodgingWebsite;
private TextView textViewLodgingEmail;
public TripHolder(#NonNull View itemView) {
super(itemView);
context = itemView.getContext();
textViewLodgingTitle = itemView.findViewById(R.id.text_view_title);
textTextViewLodgingCheckInDateTime = itemView.findViewById(R.id.text_view_start_date_time);
textTextViewLodgingCheckOutDateTime = itemView.findViewById(R.id.text_view_end_date_time);
textViewLodgingAddress = itemView.findViewById(R.id.text_view_description);
itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
int position = getAdapterPosition();
if (listener != null && position != RecyclerView.NO_POSITION) {
listener.onItemClick(trips.get(position));
}
}
});
}
}
public interface OnItemClickListener {
void onItemClick(Trip trip);
}
public void setOnItemClickListener(OnItemClickListener listener) {
this.listener = listener;
}
}
MainActivity.java
//adapter
RecyclerView recyclerView = findViewById(R.id.recycler_view);
recyclerView.setLayoutManager(new LinearLayoutManager(this));
recyclerView.setHasFixedSize(true);
final TripAdapter adapter = new TripAdapter();
recyclerView.setAdapter(adapter );
tripViewModel = new ViewModelProvider(this, ViewModelProvider.AndroidViewModelFactory.getInstance(this.getApplication())).get(TripViewModel.class);
tripViewModel.getAllTrips().observe(this, new Observer<List<Trip>>() {
#Override
public void onChanged(#Nullable List<Trip> trips) {
adapter.setTrips(trips);
}
});
//this on onActivityResult()
else if (requestCode == ADD_LODGING && resultCode == Activity.RESULT_OK) {
//get data from lodging activity
String lodgingTitle = data.getStringExtra(LodgingEditActivity.EXTRA_LODGING_TITLE);
String lodgingCheckInDateTime = data.getStringExtra(LodgingEditActivity.EXTRA_LODGING_CHECK_IN_DATE_TIME);
String lodgingCheckOutDateTime = data.getStringExtra(LodgingEditActivity.EXTRA_LODGING_CHECK_OUT_DATE_TIME);
String lodgingDescription = data.getStringExtra(LodgingEditActivity.EXTRA_LODGING_DESCRIPTION);
String lodgingAddress = data.getStringExtra(LodgingEditActivity.EXTRA_LODGING_ADDRESS);
String lodgingPhone = data.getStringExtra(LodgingEditActivity.EXTRA_LODGING_PHONE);
String lodgingWebsite = data.getStringExtra(LodgingEditActivity.EXTRA_LODGING_WEBSITE);
String lodgingEmail = data.getStringExtra(LodgingEditActivity.EXTRA_LODGING_EMAIL);
String lodgingImagePath = "test";
Trip lodging = new Trip(lodgingTitle, lodgingCheckInDateTime, lodgingCheckOutDateTime,lodgingDescription, lodgingAddress, lodgingPhone, lodgingWebsite, lodgingEmail,lodgingImagePath);
tripViewModel.insert(lodging);
Toast.makeText(this, "lodging save", Toast.LENGTH_SHORT).show();
}
My application I adapt from codinginflow channel.
https://codinginflow.com/tutorials/android/room-viewmodel-livedata-recyclerview-mvvm/part-1-introduction

Add static default item in RecyclerView

I have a horizontal RecyclerView that displays 7 images from the users device (changing as user keeps taking pictures). I would like to add a default icon at the end of the 7 images, with an onclick capability. How can I go about doing this?
Something like this:
In the image above the plus icon should be the default icon, however it should be at the end of the images.
UPDATED:
RecentPhotosAdapter.java
public class RecentPhotosAdapter extends RecyclerView.Adapter<RecentPhotosAdapter.ViewHolder> {
// Variables
private Context mContext;
private ArrayList<String> mImage;
private int VIEW_TYPE_DEFAULT = 0;
private int VIEW_TYPE_IMAGE = 1;
// Limit the recent photo selection
int RECENT_PHOTO_LIMIT = 7;
public RecentPhotosAdapter(Context mContext, ArrayList<String> mImage) {
this.mContext = mContext;
this.mImage = mImage;
}
#NonNull
#Override
public ViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
if (viewType == VIEW_TYPE_IMAGE) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.recent_photos_item, parent, false);
return new ViewHolder(view);
}
else {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.default_select_photos_item, parent, false);
return new ViewHolder(view);
}
}
#Override
public void onBindViewHolder(#NonNull ViewHolder holder, int position) {
if(position < Math.min(mImage.size(), RECENT_PHOTO_LIMIT)){
String images = mImage.get(position);
// Recent Photos
Glide.with(mContext)
.load(images)
.placeholder(R.drawable.background_gallery_placeholder)
.transform(new CenterCrop(), new RoundedCorners(30))
.into(holder.recent_photos_iv);
// Default select photos
holder.recent_photos_iv.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
// Do something here
// Take user to image select slider
}
});
}
else {
//code for default view
}
}
#Override
public int getItemViewType(int position) {
return (position == mImage.size()) ? VIEW_TYPE_DEFAULT : VIEW_TYPE_IMAGE;
}
#Override
public int getItemCount() {
return Math.min(mImage.size(), RECENT_PHOTO_LIMIT) + 1;
}
public class ViewHolder extends RecyclerView.ViewHolder{
ImageView recent_photos_iv;
ImageView default_select_photo_iv;
public ViewHolder(View itemView) {
super(itemView);
recent_photos_iv = itemView.findViewById(R.id.recent_photos_iv);
default_select_photo_iv = itemView.findViewById(R.id.default_select_photo_iv);
}
}
}
You can achieve this by making the default icon as a "ViewType" of your adapter.
Override getItemViewType to return a different value for your last item.
#Override
public int getItemViewType(int position) {
return (position == mData.size()) ? VIEW_TYPE_DEFAULT : VIEW_TYPE_IMAGE;
}
Now in the onCreateViewHolder, handle both the view Types.
#Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
if (viewType == VIEW_TYPE_IMAGE) {
//Create viewholder for your images
}
else {
//Create viewholder for default view
}
}
Add 1 to your ItemList size to accomodate this extra view:
#Override
public int getItemCount() {
return mData.size() + 1;
}
Your Updated code:
public class RecentPhotosAdapter extends RecyclerView.Adapter<RecentPhotosAdapter.ViewHolder> {
// Variables
private Context mContext;
private ArrayList<String> mImage;
private int VIEW_TYPE_DEFAULT=0;
private int VIEW_TYPE_IMAGE=1;
public RecentPhotosAdapter(Context mContext, ArrayList<String> mImage) {
this.mContext = mContext;
this.mImage = mImage;
}
#NonNull
#Override
public ViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
if (viewType == VIEW_TYPE_IMAGE) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.recent_photos_item, parent, false);
return new ViewHolder(view);
}
else {
//Create viewholder for default view
}
}
#Override
public int getItemViewType(int position) {
return (position == Math.min(mImage.size(), RECENT_PHOTO_LIMIT)) ?VIEW_TYPE_DEFAULT : VIEW_TYPE_IMAGE;
}
#Override
public void onBindViewHolder(#NonNull ViewHolder holder, int position) {
if(position < Math.min(mImage.size(), RECENT_PHOTO_LIMIT)){
String images = mImage.get(position);
Glide.with(mContext)
.load(images)
.placeholder(R.drawable.background_gallery_placeholder)
.transform(new CenterCrop(), new RoundedCorners(30))
.into(holder.recent_photos_iv);
holder.recent_photos_iv.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
// Do something here
// Take user to image select slider
}
});
}
else {
//code for default view
}
}
#Override
public int getItemCount() {
// Limit the recent photo selection
int RECENT_PHOTO_LIMIT = 7;
return Math.min(mImage.size(), RECENT_PHOTO_LIMIT)+1;
}
public class ViewHolder extends RecyclerView.ViewHolder{
ImageView recent_photos_iv;
public ViewHolder(View itemView) {
super(itemView);
recent_photos_iv = itemView.findViewById(R.id.recent_photos_iv);
}
}
}

Show different view at end of recyclerview in every section like paytm

I have a created this design. Which consists of list of list.
Now I wanted to add a view as "See All" in every section at the end of every recycler view. I wanted like this which is done by paytm.
Here is my code. I have two recyclerview one is vertical and another is horizontal. Here is my BaseRowAdapter which contains another recyclerview.
BaseRowAdapter.java
public class BaseRowAdapter extends RecyclerView.Adapter<BaseRowAdapter.ViewHolder> {
public ArrayList<MainType> types;
private Context context;
private LayoutInflater layoutInflater;
public BaseRowAdapter(ArrayList<MainType> types, Context context) {
this.types = types;
this.context = context;
this.layoutInflater = LayoutInflater.from(context);
}
#Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = layoutInflater.inflate(R.layout.vertical_scroll_single_entry, parent, false);
return new ViewHolder(view);
}
#Override
public void onBindViewHolder(ViewHolder holder, int position) {
holder.recyclerView.setAdapter(new BaseRowItemAdapter(context, types.get(position).list));
holder.recyclerView.setLayoutManager(new LinearLayoutManager(context, LinearLayoutManager.HORIZONTAL, false));
holder.recyclerView.setHasFixedSize(true);
holder.tvHeading.setText(types.get(position).name);
}
#Override
public int getItemCount() {
return types.size();
}
public class ViewHolder extends RecyclerView.ViewHolder {
RecyclerView recyclerView;
TextView tvHeading;
public ViewHolder(View itemView) {
super(itemView);
recyclerView = (RecyclerView) itemView.findViewById(R.id.rvItems);
tvHeading = (TextView) itemView.findViewById(R.id.tvHeading);
}
}
}
And for Inner recyclerview I have to show see more layout at the end. I have done something like this. which result into crashing app.
BaseRowItemAdapter.java
public class BaseRowItemAdapter extends RecyclerView.Adapter<BaseRowItemAdapter.CustomViewHolder> {
private Context context;
private ArrayList<SubType> subTypes;
private LayoutInflater inflater;
public BaseRowItemAdapter(Context context, ArrayList<SubType> subTypes) {
this.context = context;
this.subTypes = subTypes;
this.inflater = LayoutInflater.from(context);
}
#Override
public int getItemViewType(int position) {
return (position == subTypes.size()) ? R.layout.see_more : R.layout.single_item_card;
}
#Override
public CustomViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view;
if (viewType == R.layout.single_item_card) {
view = inflater.inflate(R.layout.single_item_card, parent, false);
} else {
view = inflater.inflate(R.layout.see_more, parent, false);
}
return new CustomViewHolder(view);
}
#Override
public void onBindViewHolder(CustomViewHolder holder, int position) {
SubType subType = subTypes.get(position);
if (position != subTypes.size()) {
holder.tvProductName.setText(subType.name);
Picasso.with(context).load(subType.image).into(holder.ivProduct);
if (!subType.disc.equals("0")) {
holder.tvDiscountPercentage.setText(subType.disc + "%");
holder.tvActualAmount.setPaintFlags(holder.tvActualAmount.getPaintFlags() | Paint.STRIKE_THRU_TEXT_FLAG);
int a = Integer.parseInt(subType.amount);
float b = Float.parseFloat(subType.disc) / 100;
holder.tvActualAmount.setText("₹ " + subType.amount);
int c = (int) (a * b);
holder.tvDiscountAmount.setText("₹ " + c);
} else {
holder.tvDiscountPercentage.setBackgroundColor(Color.parseColor("#ffffff"));
holder.tvActualAmount.setText("₹ " + subType.amount);
}
} else {
holder.seeMore.setText("See More >>");
}
}
#Override
public int getItemCount() {
return subTypes.size()+1;
}
public class CustomViewHolder extends RecyclerView.ViewHolder {
public ImageView ivProduct;
public TextView tvProductName, tvActualAmount, tvDiscountAmount, tvDiscountPercentage, seeMore;
public CustomViewHolder(View itemView) {
super(itemView);
tvProductName = (TextView) itemView.findViewById(R.id.tvProductName);
tvActualAmount = (TextView) itemView.findViewById(R.id.tvActualAmount);
tvDiscountAmount = (TextView) itemView.findViewById(R.id.tvDiscountAmount);
tvDiscountPercentage = (TextView) itemView.findViewById(R.id.tvDiscountPercentage);
ivProduct = (ImageView) itemView.findViewById(R.id.ivProduct);
seeMore = (TextView) itemView.findViewById(R.id.seeMore);
}
}
}
Here are my both model classes.
public class SubType {
public int id;
public String typeId;
public String name;
public String image;
public String unit;
public String amount;
public String disc;
}
public class MainType {
public int id;
public String name;
public ArrayList<SubType> list;
}
My few logcat details
java.lang.IndexOutOfBoundsException: Invalid index 2, size is 2
at java.util.ArrayList.throwIndexOutOfBoundsException(ArrayList.java:255)
at java.util.ArrayList.get(ArrayList.java:308)
at com.ashishkudale.linksolution.adapters.BaseRowItemAdapter.onBindViewHolder(BaseRowItemAdapter.java:54)
at com.ashishkudale.linksolution.adapters.BaseRowItemAdapter.onBindViewHolder(BaseRowItemAdapter.java:23)
It is crashing because of IndexOutOfBoundsException. I don't know how to solve this please help.
Change your onBindViewHolder
#Override
public void onBindViewHolder(CustomViewHolder holder, int position) {
if (position != subTypes.size()) {
SubType subType = subTypes.get(position);
holder.tvProductName.setText(subType.name);
Picasso.with(context).load(subType.image).into(holder.ivProduct);
if (!subType.disc.equals("0")) {
holder.tvDiscountPercentage.setText(subType.disc + "%");
holder.tvActualAmount.setPaintFlags(holder.tvActualAmount.getPaintFlags() | Paint.STRIKE_THRU_TEXT_FLAG);
int a = Integer.parseInt(subType.amount);
float b = Float.parseFloat(subType.disc) / 100;
holder.tvActualAmount.setText("₹ " + subType.amount);
int c = (int) (a * b);
holder.tvDiscountAmount.setText("₹ " + c);
} else {
holder.tvDiscountPercentage.setBackgroundColor(Color.parseColor("#ffffff"));
holder.tvActualAmount.setText("₹ " + subType.amount);
}
} else {
holder.seeMore.setText("See More >>");
}
}

Recycler View linear layout manager returning null

I have a recycler view which contains multiple items and each item in the recycler view contains a horizontal recycler view.The problem I am encountering is that the layout manager is null.
java.lang.NullPointerException: Attempt to invoke virtual method 'void android.support.v7.widget.RecyclerView.setLayoutManager(android.support.v7.widget.RecyclerView$LayoutManager)' on a null object reference
This is my code so far.I have checked that the data I am receiving is intact.
RecipeAdapter ( The main adapter )
public class RecipeAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private Context context;
private List<Object> items;
private final int RECIPE = 0, JOKE = 1;
public RecipeAdapter(Context context) {
this.context = context;
this.items = new ArrayList<>();
}
public void setItems(List<Object> items) {
this.items = items;
}
public void add(Object object) {
items.add(object);
notifyItemInserted(items.size());
}
#Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
RecyclerView.ViewHolder viewHolder;
final LayoutInflater inflater = LayoutInflater.from(parent.getContext());
switch (viewType) {
case RECIPE:
View recipe = inflater.inflate(R.layout.item_recipe, parent, false);
viewHolder = new ViewHolder_Recipe(recipe);
break;
case JOKE:
View joke = inflater.inflate(R.layout.item_joke, parent, false);
viewHolder = new ViewHolder_Joke(joke);
break;
default:
View recipe_default = inflater.inflate(R.layout.item_recipe, parent, false);
viewHolder = new ViewHolder_Recipe(recipe_default);
break;
}
return viewHolder;
}
#Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
switch (holder.getItemViewType()) {
case RECIPE:
ViewHolder_Recipe viewHolderRecipe = (ViewHolder_Recipe) holder;
configureRecipeHolder(viewHolderRecipe, position);
break;
case JOKE:
ViewHolder_Joke viewHolderJoke = (ViewHolder_Joke) holder;
configureJokeHolder(viewHolderJoke, position);
break;
default:
ViewHolder_Recipe viewHolder_recipe_default = (ViewHolder_Recipe) holder;
configureRecipeHolder(viewHolder_recipe_default, position);
break;
}
}
private void configureJokeHolder(ViewHolder_Joke viewHolderJoke, int position) {
}
private void configureRecipeHolder(ViewHolder_Recipe viewHolderRecipe, int position) {
RecipeDetailed recipe = (RecipeDetailed) items.get(position);
Glide.with(context)
.load(recipe.getImage())
.into(viewHolderRecipe.getRecipe_image());
viewHolderRecipe.getRecipe_name().setText(recipe.getTitle());
viewHolderRecipe.getRecipe_prep().setText(recipe.getReadyInMinutes());
viewHolderRecipe.getRecipe_serves().setText(recipe.getServings());
viewHolderRecipe.getIngredientAdapter().setIngredients(recipe.getExtendedIngredients());
}
#Override
public int getItemViewType(int position) {
if (items.get(position) instanceof RecipeDetailed) {
return RECIPE;
} else if (items.get(position) instanceof Joke) {
return JOKE;
}
return super.getItemViewType(position);
}
#Override
public int getItemCount() {
return items.size();
}
}
The ViewHolder for that Adapter -- ViewHolder_Recipe
public class ViewHolder_Recipe extends RecyclerView.ViewHolder {
private CircularImageView recipe_image;
private TextView recipe_name;
private TextView recipe_prep;
private TextView recipe_serves;
private RecyclerView recyclerView;
private RecipeIngredientAdapter ingredientAdapter;
public ViewHolder_Recipe(View itemView) {
super(itemView);
recipe_image = (CircularImageView) itemView.findViewById(R.id.recipe_image);
recipe_name = (TextView) itemView.findViewById(R.id.recipe_name);
recipe_prep = (TextView) itemView.findViewById(R.id.recipe_prep);
recipe_serves = (TextView) itemView.findViewById(R.id.recipe_serves);
recyclerView = (RecyclerView) itemView.findViewById(R.id.recyclerView);
ingredientAdapter = new RecipeIngredientAdapter(itemView.getContext());
recyclerView.setLayoutManager(new LinearLayoutManager(itemView.getContext()
, LinearLayoutManager.HORIZONTAL, false));
recyclerView.setAdapter(ingredientAdapter);
}
public RecipeIngredientAdapter getIngredientAdapter() {
return ingredientAdapter;
}
public CircularImageView getRecipe_image() {
return recipe_image;
}
public TextView getRecipe_name() {
return recipe_name;
}
public TextView getRecipe_prep() {
return recipe_prep;
}
public TextView getRecipe_serves() {
return recipe_serves;
}
public RecyclerView getRecyclerView() {
return recyclerView;
}
}
The child adapter -- RecipeIngredientAdapter
public class RecipeIngredientAdapter extends RecyclerView.Adapter<ViewHolderRecipeIngredient> {
private Context context;
private ArrayList<Ingredient> ingredients;
public RecipeIngredientAdapter(Context context) {
this.context = context;
}
public void setIngredients(ArrayList<Ingredient> ingredients) {
this.ingredients = ingredients;
}
#Override
public ViewHolderRecipeIngredient onCreateViewHolder(ViewGroup parent, int viewType) {
LayoutInflater inflater = LayoutInflater.from(parent.getContext());
View view = inflater.inflate(R.layout.item_recipe_ingredients, parent, false);
return new ViewHolderRecipeIngredient(view);
}
#Override
public void onBindViewHolder(ViewHolderRecipeIngredient holder, int position) {
final Ingredient ingredient = ingredients.get(position);
Glide.with(context)
.load(ingredient.getImage())
.into(holder.getIngredient_image());
}
#Override
public int getItemCount() {
return 0;
}
}
The viewholder for that is a simple viewholder which contains an image.
I have seen posts online which seem to do the exact same thing and get it working,what exactly am i missing here?
From the error, it sounds like the RecyclerView is null, not the LayoutManager. Make sure you are using the proper id from the layout. are you sure the proper layout id of the RecyclerView is R.id.recyclerView?

Categories