unable to understand onClick event for multiple CardViews inside RecycleView - android

I looked up for the possible solutions but I could not figure out how to apply them in my case.
I am using a RecyclerView to display several CardViews inside it. Initially all cards have white background and I want to change the background color when a card is touched. Each CardView displays a name and an id as described in 'MyCards' class :
public class MyCards {
private String sName;
private int sId;
private boolean sPresent;
public String getName() {
return this.sName;
}
public MyCards(String sName, int sId, boolean sPresent) {
this.sName = sName;
this.sId = sId;
this.sPresent = sPresent;
}
public void setName(String t) {
this.sName = t;
}
public int getId() {
return sId;
}
public void setId(int id) {
this.sId = id;
}
public boolean isPresent() {
return sPresent;
}
public void setPresent(boolean present) {
this.sPresent = present;
}
}
I am making an ArrayList of these MyCards object in the 'Roster' class :
public class Roster extends ActionBarActivity{
private static final int READ_REQUEST_CODE = 42;
private static final String TAG = null;
private RecyclerView rObject;
private MyAdapter adapter;
String abc = null;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.roster_recycle);
rObject = (RecyclerView)findViewById(R.id.recycler_view);
LinearLayoutManager llm = new LinearLayoutManager(this);
llm.setOrientation(LinearLayoutManager.VERTICAL);
rObject.setLayoutManager(llm);
MyCards c1 = new MyCards("Abhinav", 123, true);
MyCards c2 = new MyCards("Abhishek", 13, false);
performFileSearch();
c1.setName("Abhinav");
c2.setName("Baba");
List<MyCards> cardList = new ArrayList<MyCards>();
cardList.add(c1);
cardList.add(c2);
adapter = new MyAdapter(Roster.this,cardList);
rObject.setAdapter(adapter);
}
The CardView is defined in the item_layout.xml file :
<android.support.v7.widget.CardView
android:id="#+id/card_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_margin="10dp"
android:clickable="true"
android:foreground="?android:attr/selectableItemBackground"
card_view:cardCornerRadius="4dp" >
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent" >
<TextView
android:id="#+id/sName"
android:layout_width="match_parent"
android:layout_height="20dp"
android:gravity="center_vertical"
android:text="contact det"
android:textSize="14dp" />
<TextView
android:id="#+id/sId"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="#id/sName"
android:layout_marginLeft="5dp"
android:layout_marginTop="10dp"
android:gravity="center_vertical"
android:text="Name"
android:textSize="10dp" />
<TextView
android:id="#+id/sPresent"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="#id/sId"
android:layout_marginLeft="5dp"
android:layout_marginTop="10dp"
android:gravity="center_vertical"
android:text="Present"
android:textSize="10dp" />
</RelativeLayout>
</android.support.v7.widget.CardView>
My question is : If I click on a card displaying data for 'c1' object then how can I identify that it was from 'c1' and not 'c2'. How do I use click handler in such cases where we display multiple cards?
I'm sorry if my question is too basic but I'm really stuck at it.

Thank you so much for your responses, they really helped. Finally I found a video on YouTube which explained the concept in a nice manner. I am posting the link so that others can also benefit if they get stuck. Here is the video -
see this :- https://www.youtube.com/watch?v=zE1E1HOK_E4

Take a look at this answer for using an onItemClickListener with a RecyclerView.

public class MyAdapter extends RecyclerView.Adapter {
Context mContext;
ArrayList<MyCard> mData;
public MyAdapter(Context context , ArrayList<MyCard> data ) {
mContext = context;
mData = data;
}
public class ViewHolder extends RecyclerView.ViewHolder{
private TextView sName, sId , sPresent;
public ViewHolder(View itemView) {
super(itemView);
sName = (TextView) itemView.findViewById(R.id.sName);
sId = (TextView) itemView.findViewById(R.id.sId);
sPresent = (TextView) itemView.findViewById(R.id.sPresent);
itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
// your logic
}
});
}
}
#Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_layout , parent , false);
ViewHolder vh = new ViewHolder(v);
return vh;
}
#Override
public int getItemCount() {
return mData.size();
}
#Override
public void onBindViewHolder(ViewHolder holder, final int position) {
final MyCard card = mData.get(position);
holder.sName.setText(card.getName().toString());
holder.sId.setText(card.getId().toString());
holder.sPresent.setText(card.getPresent().toString());
}
}

Related

Data missing in multiple View in RecyclerView using retrofit response

I am facing an issue in multiple view type recycler view i think the code in myadapter is lacking something which i am not able to figure out pls help. Here is the detailed description :
I have a response list from retrofit :
public class DateResponse {
#SerializedName("RecordEntryON")
#Expose
private String record_EntryOn;
#SerializedName("PatientID")
#Expose
private int Patient_ID;
#SerializedName("DiscountedAmount")
#Expose
private double discounted_Amount;
#SerializedName("ClientID")
#Expose
private int client_ID;
#SerializedName("TestType")
#Expose
private String test_Type;
#SerializedName("TestName")
#Expose
private String test_Name;
#SerializedName("FetchingTime")
#Expose
String fetching_Time;
#SerializedName("ClientTestCount")
#Expose
int clienttest_Count;
#SerializedName("CentreName")
#Expose
String center_Name;
getter and setter to follow (not writing here). I have another request model which i am passing into retrofit request here is the code for request model :
public class Date_Request {
#SerializedName("IsSuccess")
boolean is_success;
#SerializedName("Message")
String _message;
#SerializedName("ResponseData")
List<DateResponse> response_data;
code for retrofit in MyActivity :
authToken = "Basic " + Utils.getAuthToken(Dashboard.this);
restClient.getService().getByCentre(authToken, DEV_ID,defaultDate).enqueue(new
Callback<Date_Request>() {
#Override
public void onResponse(Call<Date_Request> call, Response<Date_Request> response) {
// List<DateResponse> listAll;
if (response.isSuccessful())
try {
boolean success = response.body().isIs_success();
String message = response.body().get_message();
if (success) {
listAll = response.body().getResponse_data();
List<DateResponse> centerList = new ArrayList<>();
int i;
for(i=0;i<5;i++){
String centerName = listAll.get(i).getCenter_Name();
int patientCount = listAll.get(i).getPatient_ID();
double amount = listAll.get(i).getDiscounted_Amount();
DateResponse topList = new DateResponse();
topList.setPatient_ID(patientCount);
topList.setDiscounted_Amount(amount);
centerList.add(topList);
dateViewAdapter = new DateViewAdapter(centerList, Dashboard.this);
recyclerView.setAdapter(dateViewAdapter);
dateViewAdapter.notifyDataSetChanged();
}
Procedure : I am selecting an option from Spinner there are three options: center,date,test. On select, a calendar opens user select the date and the corresponding list is shown. APIs for all three options are different with little different data. However, in model i am using only one response model and one request.
Now the issue is if I am running this code than no of item matches the for loop ie 5(or whatever i set here 10 15) and displayed in list if i remove the for loop and directly add the list wo setting getting anything here in activity than i still get list with 10 items as I fixed the list to show 10 items only using getItemCount method in adapter
whatever I use center name is not showing(blank) + TextView hardcoded text of xml layout is not showing + I am unable to concatenate anything before center name.
The data--amount and patientCount is showing but no hardcoded text or cant concatenate anything with these fields
In the test or date list in the same recycler view test name is showing but not test type(blank) instead it is showing patient count in test list and date list also
In centre list:
centre name not showing
Patient Count and Amount showing but hardcoded text in textview missing in addition cant concatenate string Patient Count
In test list:
test name and amount is showing
test type is not showing instead patient count is showing
In date list:
same as test list
Code for adapter :
public class DateViewAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private List<DateResponse> listAll;
private final int limit = 10;
private Context mContext;
private static final int CENTER_LIST = 0;
private static final int TEST_LIST = 1;
private static final int DATE_LIST = 2;
private static final int TYPE_DEFAULT = 3;
public DateViewAdapter(List<DateResponse> listAll, Context mContext) {
this.listAll = listAll;
this.mContext = mContext;
}
public void addAllItems(List<DateResponse> items) {
listAll.addAll(items);
notifyDataSetChanged();
}
//override getItemViewType method to assign the layout to each item depending on the viewtype passed
#NonNull
#Override
public RecyclerView.ViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View view;
// view = LayoutInflater.from(parent.getContext()).inflate(R.layout.center_list, parent, false);
// return new DetailsViewHolder(view);
switch (viewType) {
case CENTER_LIST:
view = LayoutInflater.from(parent.getContext()).inflate(R.layout.center_list, parent, false);
return new CenterViewHolder(view);
case TEST_LIST:
view = LayoutInflater.from(parent.getContext()).inflate(R.layout.test_list, parent, false);
return new TestViewHolder(view);
case DATE_LIST:
view = LayoutInflater.from(parent.getContext()).inflate(R.layout.date_list, parent, false);
return new DateListViewHolder(view);
default:
view = LayoutInflater.from(parent.getContext()).inflate(R.layout.default_view, parent, false);
return new DefaultViewHolder(view);
}
}
#Override
public void onBindViewHolder(#NonNull RecyclerView.ViewHolder holder, int position) {
if (listAll.get(position).toString().contains("CentreName")) {
CenterViewHolder centerViewHolder = (CenterViewHolder) holder;
centerViewHolder.setDetails(listAll.get(position));
} else if (listAll.get(position).toString().contains("TestName")) {
TestViewHolder testViewHolder = (TestViewHolder) holder;
testViewHolder.setTestDetails(listAll.get(position));
} else if (listAll.get(position).toString().contains("Date")) {
DateListViewHolder dateListViewHolder = (DateListViewHolder) holder;
dateListViewHolder.setDateListDetails(listAll.get(position));
} else if (listAll.get(position).toString().contains("PatientID")) {
DefaultViewHolder defaultViewHolder = (DefaultViewHolder) holder;
defaultViewHolder.setDefaultDetails(listAll.get(position));
// throw new RuntimeException("problem in logic");
} else {
throw new RuntimeException("problem in logic");
}
}
public int getItemViewType(int position) {
DateResponse dateResponse = new DateResponse();
dateResponse = listAll.get(position);
if(listAll.get(position).toString().contains("CentreName"))
{
return CENTER_LIST;
} else if (listAll.get(position).toString().contains("TestName")) {
return TEST_LIST;
} else if (listAll.get(position).toString().contains("Date")) {
return DATE_LIST;
} else if (listAll.get(position).toString().contains("PatientID")) return TYPE_DEFAULT;
return position;
}
#Override
public int getItemCount() {
if (listAll.size() > limit) {
return limit;
} else {
return listAll.size();
}
}
class CenterViewHolder extends RecyclerView.ViewHolder {
private TextView tvCenterName, tvPatientCount, tvAmount;
public CenterViewHolder(#NonNull View itemView) {
super(itemView);
tvCenterName = itemView.findViewById(R.id.cn_name);
tvPatientCount = itemView.findViewById(R.id.pt_count);
tvAmount = itemView.findViewById(R.id.amount);
}
void setDetails(DateResponse centerDetails) {
tvCenterName.setText("Centre Name : " + centerDetails.getCenter_Name());
tvPatientCount.setText("Patient Count : " + centerDetails.getPatient_ID());
tvAmount.setText("Amount : " + centerDetails.getDiscounted_Amount());
}
}
class TestViewHolder extends RecyclerView.ViewHolder {
private TextView tvTestName, tvTestType, tvTestAmount;
public TestViewHolder(#NonNull View itemView) {
super(itemView);
tvTestAmount = itemView.findViewById(R.id.test_amount);
tvTestName = itemView.findViewById(R.id.test_name);
tvTestType = itemView.findViewById(R.id.test_type);
}
void setTestDetails(DateResponse testDetails) {
tvTestType.setText("Test Name : " + testDetails.getTest_Type());
tvTestName.setText(testDetails.getTest_Name());
tvTestAmount.setText(String.valueOf(testDetails.getDiscounted_Amount()));
}
}
class DateListViewHolder extends RecyclerView.ViewHolder {
private TextView tvClientCount, tvPatCount, tvDateAmount;
public DateListViewHolder(#NonNull View itemView) {
super(itemView);
tvClientCount = itemView.findViewById(R.id.client_name);
tvPatCount = itemView.findViewById(R.id.patient_count);
tvDateAmount = itemView.findViewById(R.id.date_test_amount);
}
void setDateListDetails(DateResponse dateListDetails) {
tvDateAmount.setText(String.valueOf(dateListDetails.getDiscounted_Amount()));
tvPatCount.setText(String.valueOf(dateListDetails.getPatient_ID()));
tvClientCount.setText(dateListDetails.getTest_Name());
}
}
class DefaultViewHolder extends RecyclerView.ViewHolder {
private TextView tvdefaultCenter, tvdefaultCount, tvdefaultAmount;
public DefaultViewHolder(#NonNull View itemView) {
super(itemView);
tvdefaultCenter = itemView.findViewById(R.id.default_center);
tvdefaultCount = itemView.findViewById(R.id.default_pt_count);
tvdefaultAmount = itemView.findViewById(R.id.default_amount);
}
void setDefaultDetails(DateResponse defaultDetails) {
tvdefaultCenter.setText(defaultDetails.getCenter_Name());
tvdefaultCount.setText(String.valueOf(defaultDetails.getPatient_ID()));
tvdefaultAmount.setText(String.valueOf(defaultDetails.getDiscounted_Amount()));
}
}
}
layout for centre_list view:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
android:id="#+id/parent_linear"
xmlns:app="http://schemas.android.com/apk/res-auto">
<androidx.cardview.widget.CardView
android:id="#+id/parent_matrix"
app:cardCornerRadius="3dp"
app:cardElevation="2dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<RelativeLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<LinearLayout
android:id="#+id/cp_info"
android:layout_width="wrap_content"
android:orientation="vertical"
android:layout_height="wrap_content">
<TextView
android:id="#+id/cn_name"
android:padding="1dp"
android:layout_marginStart="5dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textStyle="bold"
android:text="Centre Name : "
android:textColor="#color/purple_200">
</TextView>
<TextView
android:padding="1dp"
android:text="Patient Count : "
android:id="#+id/pt_count"
android:textColor="#color/black"
android:layout_marginStart="5dp"
android:paddingBottom="1dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
</TextView>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:layout_alignParentEnd="true">
<TextView
android:id="#+id/amount"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="end"
android:layout_marginTop="#dimen/text_margin"
android:layout_marginEnd="25dp"
android:padding="2dp"
android:text="Amount"
android:textColor="#color/black"
android:textStyle="bold" />
</LinearLayout>
</RelativeLayout>
</androidx.cardview.widget.CardView>

not getting id of a clicked child item inside RecyclerView item layout

I have implemented a RecyclerView inside a ConstraintLayout. I am having one child image element inside the layout. But when I click the child image, it always returns the ConstraintLayout, not the clicked image.
Could you please tell me why this is happening, what is the solution for this ?
I separately did bind listener to image, it is working but not able to get the RecyclerItem object. I need RecyclerItem object for the position to proceed.
I implemented it by binding elements via onBindViewholder method in Adapter. Below are the codes
customAdapter = new GridViewAdapter(recyclerItems, 1, this.getContext().getPackageName(),
new GridViewAdapter.OnItemClickListener(){
#Override
public void onItemClick(RecyclerItem item) {
CommonUtil.addFragment("REP", Constants.CONTAINER_HOME,
new ModifyFragment(), getActivity(), null);
}
}, R.layout.rec_view_item_stock, Constants.V_SPAN_LIST_8);
RecyclerView recyclerView = view.findViewById(R.id.stockListRecView);
recyclerView.setItemAnimator(new DefaultItemAnimator());
recyclerView.setLayoutManager(new GridLayoutManager(this.getContext(), 1));
recyclerView.setAdapter(customAdapter);
//Adapter
public class GridViewAdapter extends RecyclerView.Adapter<GridViewAdapter.ViewHolder>{
private List<RecyclerItem> dataItems;
private int hSpan = 1;
private String packageName;
private final OnItemClickListener listener;
private int inflator;
private int vSpan;
public interface OnItemClickListener {
void onItemClick(RecyclerItem item);
}
public static class ViewHolder extends RecyclerView.ViewHolder {
private final ConstraintLayout constraintLayout;
private final TextView textView;
private final ImageView imageView;
private Object obj;
public ViewHolder(View view) {
super(view);
constraintLayout = (ConstraintLayout) view.findViewById(R.id.rec_content_layout);
textView = constraintLayout.findViewById(R.id.recTextView);
imageView = constraintLayout.findViewById(R.id.recImage);
}
public void bind(final RecyclerItem item, final OnItemClickListener listener) {
itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
listener.onItemClick(item);
}
});
}
public TextView getTextView() {
return textView;
}
public ImageView getImageView() {
return imageView;
}
public Object getObj() {
return obj;
}
public void setObj(Object obj) {
this.obj = obj;
}
}
public GridViewAdapter(List<RecyclerItem> items, int spanCount, String packageName, OnItemClickListener listener,
int inflator, int vSpan) {
dataItems = items;
this.hSpan = spanCount;
this.packageName = packageName;
this.listener = listener;
this.inflator = inflator;
this.vSpan = vSpan;
}
#Override
public ViewHolder onCreateViewHolder(ViewGroup viewGroup, int gridType) {
View view = LayoutInflater.from(viewGroup.getContext()).inflate(inflator, viewGroup, false);
ViewGroup.LayoutParams layoutParams = view.getLayoutParams();
layoutParams.width = (viewGroup.getResources().getDisplayMetrics().widthPixels / hSpan) - 24;
if(Constants.V_SPAN_GRID == vSpan) {
layoutParams.height = layoutParams.width;
} else {
layoutParams.height = (viewGroup.getResources().getDisplayMetrics().widthPixels / vSpan);
}
return new ViewHolder(view);
}
#Override
public void onBindViewHolder(ViewHolder viewHolder, final int position) {
viewHolder.getTextView().setText(dataItems.get(position).getText());
int imgId = viewHolder.getImageView().getResources().getIdentifier(
dataItems.get(position).getImageName(), "drawable", packageName);
viewHolder.getImageView().setImageResource(imgId);
viewHolder.setObj(dataItems.get(position));
viewHolder.bind(dataItems.get(position), listener);
}
#Override
public int getItemCount() {
return dataItems.size();
}
//item layout
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="#+id/rec_content_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:layout_marginTop="8dp"
android:layout_marginLeft="4dp"
android:padding="8dp"
android:background="#drawable/border_top_bottom" >
<androidx.constraintlayout.widget.Guideline
android:id="#+id/viewstock_gline_1_v"
android:layout_width="1dp"
android:layout_height="wrap_content"
android:orientation="vertical"
app:layout_constraintGuide_percent="0.6"/>
<ImageView
android:id="#+id/recImage"
android:background="#color/colorPrimaryDark"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="8dp" />
<TextView
android:id="#+id/recTextView"
app:layout_constraintLeft_toRightOf="#+id/recImage"
app:layout_constraintTop_toTopOf="parent"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="8dp" />
<ImageView
android:id="#+id/editstock_image"
android:src="#drawable/ic_edit_stock"
android:background="#color/colorPrimaryDark"
app:layout_constraintRight_toLeftOf="#+id/deletestock_image"
app:layout_constraintTop_toTopOf="parent"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="8dp" />
<ImageView
android:id="#+id/deletestock_image"
android:src="#drawable/ic_delete_stock"
android:background="#color/colorPrimaryDark"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="8dp" />
</androidx.constraintlayout.widget.ConstraintLayout>```
Try this!
public void bind(final RecyclerItem item, final OnItemClickListener listener, TextView itemTextView) {
itemTextView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
listener.onItemClick(item);
}
});
}
Pass every item text view instance from the view holder or fro onBindViewHolder itself implement onclick listener

I am building a chat application and not able to get the right and left styling

That is when the sender from one device sends message,it should appear on the right hand side and when the other device gets the message it should appear on the left hand side.
My java class: This is the function I am calling
private void chatRowStyling(boolean isItMe, ViewHolder holder){
if (isItMe){
holder.layoutParams.gravity = Gravity.END;
holder.chatBody.setTextColor(Color.BLUE);
holder.senderName.setBackgroundResource(R.drawable.speech_bubble_green);
}else{
holder.layoutParams.gravity = Gravity.START;
holder.chatBody.setTextColor(Color.GREEN);
holder.senderName.setBackgroundResource(R.drawable.speech_bubble_orange);
}
Log.i("TAG","error :" + mySnapShot);
holder.senderName.setLayoutParams(holder.layoutParams);
holder.chatBody.setLayoutParams(holder.layoutParams);
}
In the Screenshot, all the messages appear on the right side, whereas I want one to be on right and another to be on left from different users.
This is my XML code :
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/singleMessageContainer"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<TextView
android:id="#+id/author"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="start"
android:paddingLeft="12dp"
android:paddingRight="12dp"
android:text="#string/sender"
android:textColor="#2980b9"
android:textSize="16sp"
android:textStyle="bold" />
<TextView
android:id="#+id/message"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="start"
android:layout_margin="5dip"
android:padding="12dp"
android:text="#string/author"
android:textColor="#2c3e50" />
</LinearLayout>
The best way to do it would be to implement RecyclerView with separate view types, that way you could adjust layout however you want without some shady workaround. Here is example to do it.
Reference : How to create RecyclerView with multiple view type?
EDIT:
Convinced by comments I decided to add some more explanation.
You could create two separate layouts, one for your messages:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:id="#+id/tvAuthor"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"/>
<TextView
android:id="#+id/tvMessage"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="#id/tvAuthor"
android:layout_alignParentRight="true"/>
</RelativeLayout>
and the other one for messages from friend:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:id="#+id/tvAuthor"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<TextView
android:id="#+id/tvMessage"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="#id/tvAuthor" />
</RelativeLayout>
Then you can create a class for your messages:
public class Message {
private String message;
private String author;
public Message(String message, String author) {
this.message = message;
this.author = author;
}
public String getMessage() {
return message;
}
public String getAuthor() {
return author;
}
}
Next step would be to create adapter for your RecyclerView that will use two seperate ViewHolders, one for your messages and the other for messages from your friend. Inside OnCreateViewHolder you can choose which layout you want to display for each message. Then in OnBindViewHolder, you can fill TextViews with correct message data.
public class MessageAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private ArrayList<Message> messages;
private final static int TYPE_FROM_FRIEND = 1;
private final static int TYPE_TO_FRIEND = 2;
public MessageAdapter(ArrayList<Message> messages) {
this.messages = messages;
}
public int getItemViewType(int position) {
if (messages.get(position).getAuthor().equals("Me")) {
return TYPE_TO_FRIEND;
} else {
return TYPE_FROM_FRIEND;
}
}
#Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
int layout = 0;
RecyclerView.ViewHolder viewHolder;
switch (viewType){
case TYPE_TO_FRIEND:
layout = R.layout.view_message_to_friend;
View toFriendView = LayoutInflater
.from(parent.getContext())
.inflate(layout, parent, false);
viewHolder=new ToFriendViewHolder(toFriendView);
break;
case TYPE_FROM_FRIEND:
layout = R.layout.view_message_from_friend;
View fromFriendView = LayoutInflater
.from(parent.getContext())
.inflate(layout, parent, false);
viewHolder = new FromFriendViewHolder(fromFriendView);
break;
default:
viewHolder = null;
break;
}
return viewHolder;
}
#Override
public void onBindViewHolder(final RecyclerView.ViewHolder holder, final int position) {
int viewType=holder.getItemViewType();
switch (viewType){
case TYPE_TO_FRIEND:
((ToFriendViewHolder)holder).tvMessage.setText(messages.get(position).getMessage());
((ToFriendViewHolder)holder).tvAuthor.setText(messages.get(position).getAuthor());
break;
case TYPE_FROM_FRIEND:
((FromFriendViewHolder)holder).tvMessage.setText(messages.get(position).getMessage());
((FromFriendViewHolder)holder).tvAuthor.setText(messages.get(position).getAuthor());
break;
}
}
private class ToFriendViewHolder extends RecyclerView.ViewHolder {
private TextView tvAuthor;
private TextView tvMessage;
public ToFriendViewHolder(View view) {
super(view);
tvAuthor = (TextView) view.findViewById(R.id.tvAuthor);
tvMessage = (TextView) view.findViewById(R.id.tvMessage);
}
}
private class FromFriendViewHolder extends RecyclerView.ViewHolder {
private TextView tvAuthor;
private TextView tvMessage;
public FromFriendViewHolder(View view) {
super(view);
tvAuthor = (TextView) view.findViewById(R.id.tvAuthor);
tvMessage = (TextView) view.findViewById(R.id.tvMessage);
}
}
#Override
public int getItemCount() {
return messages.size();
}
}
Finally you can set RecyclerView's adapter in your activity:
public class MainActivity extends AppCompatActivity {
private RecyclerView rvMain;
private ArrayList<Message> messages = new ArrayList<>();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
rvMain = (RecyclerView) findViewById(R.id.rvMain);
rvMain.setLayoutManager(new LinearLayoutManager(this));
messages.add(new Message("Hello", "Me"));
messages.add(new Message("Hi", "Friend"));
messages.add(new Message("How are you?", "Me"));
messages.add(new Message("I'm fine and you?", "Friend"));
MessageAdapter adapter = new MessageAdapter(messages);
rvMain.setAdapter(adapter);
}
}
You can achieve it by setting the view gravity not the LayoutParams with something like this:
if(isIfMe) {
holder.linearLayout.setGravity(Gravity.END);
holder.tvAuthor.setGravity(Gravity.END);
} else {
holder.linearLayout.setGravity(Gravity.END);
holder.tvAuthor.setGravity(Gravity.END);
}

Can't get ImageView to show up on RecyclerView

I am just learning the RecyclerView and cannot figure out why the imageView with android:id="#+id/im_item_icon" will not show up on the screen. I even have another imageView that works but when I swap the IDs the original not working view works and the working one will not work. So basically the problem must be with the ID but I cannot figure out why. BTW I got the code from a blog "http://wiseassblog.com/tutorials/2016/03/04/how-to-build-a-recyclerview/"
DerpAdapter.java
public class DerpAdapter extends RecyclerView.Adapter<DerpAdapter.DerpHolder> {
private List<ListItem> listData;
private LayoutInflater inflater;
public DerpAdapter(List<ListItem> listData, Context c){
inflater = LayoutInflater.from(c);
this.listData = listData;
}
#Override
public DerpAdapter.DerpHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = inflater.inflate(R.layout.list_item, parent, false);
return new DerpHolder(view);
}
#Override
public void onBindViewHolder(DerpHolder holder, int position) {
ListItem item = listData.get(position);
holder.title.setText(item.getTitle());
holder.icon.setImageResource(item.getImageResId());
}
#Override
public int getItemCount() {
return listData.size();
}
class DerpHolder extends RecyclerView.ViewHolder {
private TextView title;
private ImageView icon;
private View container;
public DerpHolder(View itemView) {
super(itemView);
title = (TextView)itemView.findViewById(R.id.lbl_item_text);
icon = (ImageView)itemView.findViewById(R.id.im_item_icon);
//We'll need the container later on, when we add an View.OnClickListener
container = itemView.findViewById(R.id.cont_item_root);
}
}
DerpData.java
public class DerpData {
private static final String[] titles = {"Nothingness cannot be defined",
"Time is like a river made up of the events which happen, and a violent stream; " +
"for as soon as a thing has been seen, it is carried away, and another comes" +
" in its place, and this will be carried away too,",
"But when I know that the glass is already broken, every minute with it is precious.",
"For me, it is far better to grasp the Universe as it really is than to persist in" +
" delusion, however satisfying and reassuring.",
"The seeker after the truth is not one who studies the writings of the ancients and," +
" following his natural disposition, puts his trust in them, but rather the" +
" one who suspects his faith in them and questions what he gathers from them," +
" the one who submits to argument and demonstration, and not to the " +
"sayings of a human being whose nature is fraught with all kinds " +
"of imperfection and deficiency.",
"You must take personal responsibility. You cannot change the circumstances, the" +
" seasons, or the wind, but you can change yourself. That is something you" +
" have charge of."
};
private static final String[] subTitles = {"Bruce Lee",
"Marcus Aurelius",
"Meng Tzu",
"Ajahn Chah",
"Carl Sagan",
"Alhazen",
"Jim Rohn"
};
private static final int icon = R.drawable.ic_tonality_black_36dp;
public static List <ListItem> getListData() {
List <ListItem> data = new ArrayList <>();
//Repeat process 4 times, so that we have enough data to demonstrate a scrollable
//RecyclerView
for (int x = 0; x < 4; x++) {
//create ListItem with dummy data, then add them to our List
for (int i = 0; i < titles.length; i++) {
ListItem item = new ListItem();
item.setTitle(titles[i]);
item.setSubTitle(subTitles[i]);
data.add(item);
}
}
return data;
}
ListItem.java
public class ListItem {
private int imageResId;
private String subTitle;
private String title;
private boolean favourite = false;
public String getSubTitle() {
return subTitle;
}
public void setSubTitle(String subTitle) {
this.subTitle = subTitle;
}
public boolean isFavourite() {
return favourite;
}
public void setFavourite(boolean favourite) {
this.favourite = favourite;
}
public int getImageResId() {
return imageResId;
}
public void setImageResId(int imageResId) {
this.imageResId = imageResId;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
DetailActivity.java
public class DetailActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_detail);
}
ListActivity.java
public class ListActivity extends AppCompatActivity {
private RecyclerView recView;
private DerpAdapter adapter;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_list);
recView = (RecyclerView)findViewById(R.id.rec_list);
//Check out GridLayoutManager and StaggeredGridLayoutManager for more options
recView.setLayoutManager(new LinearLayoutManager(this));
adapter = new DerpAdapter(DerpData.getListData(), this);
recView.setAdapter(adapter);
}
activity_detail.xml
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="16dp"
android:paddingLeft="16dp"
android:paddingRight="16dp"
android:paddingTop="16dp"
tools:context="application.binarysoup.jsonpractice.ui.DetailActivity">
<TextView
android:id="#+id/lbl_quote_text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:fontFamily="sans-serif-medium" />
<TextView
android:id="#+id/lbl_quote_attribution"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="#id/lbl_quote_text"
android:fontFamily="sans-serif-light"
android:textStyle="italic" />
activity_list.xml
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="application.binarysoup.jsonpractice.ui.ListActivity"
tools:layout_editor_absoluteX="0dp"
tools:layout_editor_absoluteY="81dp">
<android.support.v7.widget.RecyclerView
android:id="#+id/rec_list"
android:layout_width="match_parent"
android:layout_height="match_parent" />
list_item.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/cont_item_root"
android:layout_width="match_parent"
android:layout_height="72dp"
android:background="#drawable/background_state_drawable"
android:clickable="true"
>
<ImageView
android:id="#+id/im_item_icon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:paddingLeft="16dp"
android:src="#drawable/ic_tonality_black_36dp" />
<TextView
android:id="#+id/lbl_item_text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignTop="#+id/im_item_icon"
android:layout_marginLeft="72dp"
android:layout_marginRight="48dp"
android:ellipsize="end"
android:fontFamily="sans-serif"
android:singleLine="true"
android:text="Sois comme l'eau mon ami"
android:textColor="#android:color/black"
android:textSize="16sp" />
<TextView
android:id="#+id/lbl_item_sub_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="#+id/lbl_item_text"
android:layout_marginLeft="72dp"
android:layout_marginRight="48dp"
android:ellipsize="end"
android:fontFamily="sans-serif"
android:singleLine="true"
android:text="Mononc' J"
android:textSize="14sp" />
<ImageView
android:id="#+id/im_item_icon_secondary"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"
android:clickable="true"
android:padding="16dp"
android:src="#drawable/ic_star_border_black_24dp"
android:background="#drawable/background_state_drawable"
/>
Can't get ImageView to show up on RecyclerView
You have to initialize imageResId in order to appear it in the recyclerView
for (int i = 0; i < titles.length; i++) {
ListItem item = new ListItem();
item.setTitle(titles[i]);
item.setSubTitle(subTitles[i]);
//put the code to initialise the imageResId here
data.add(item);
}

ReclyclerView and CardView, onclick method perform the action on several CardViews at same time

I've got a RecyclerView which populates from an ArrayList. The output is a CardView layout.
In the Cardview, there are 2 buttons amongst other Views.
They only have to read the current value of a TextView, which by default is 1, and increase or decrease it.
The Arraylist contains 8 items.
When I run the app the UI works fine. Trouble is when I try to modify the value of the TextView.
The value is correctly increased and decreased on the CardView I'm working on, but ALSO the value is modified on another CardView. And in that second CardView, modifying its TextView value, also modifies the first one.
So, what am I doing wrong?
This is my Fragment:
public class Fragment_rosas extends Fragment {
#Override
public View onCreateView(LayoutInflater inflater,ViewGroup container,Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.layout_rosas,container,false);
RecyclerView recyclerview_rosas;
RecyclerView.Adapter adaptador_rv_rosas;
RecyclerView.LayoutManager lm_rosas;
List rosas = new ArrayList();
rosas.add(new Tropa(1,R.drawable.minibarbaro, getResources().getString(R.string.barbaro),7,1));
recyclerview_rosas = (RecyclerView) view.findViewById(R.id.recyclerView_tropasRosas);
recyclerview_rosas.setHasFixedSize(true);
lm_rosas = new LinearLayoutManager(getContext());
recyclerview_rosas.setLayoutManager(lm_rosas);
adaptador_rv_rosas = new AdaptadorTropa(rosas);
recyclerview_rosas.setAdapter(adaptador_rv_rosas);
return view;
}
}
And here the part of code on my Adapter:
#Override
public void onBindViewHolder(final TropaViewHolder viewHolder, int i) {
viewHolder.imagen.setImageResource(items.get(i).getImagen());
viewHolder.nombre.setText(items.get(i).getNombre());
viewHolder.maxnivel.setText(String.valueOf(items.get(i).getNivelMax()));
viewHolder.espacioencamp.setText((String.valueOf(items.get(i).getEspacioEnCamp())));
final String nombre = items.get(i).getNombre();
final int maxnivel = items.get(i).getNivelMax();
viewHolder.nivelmas.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
String niveltemp = viewHolder.nivel.getText().toString();
String nivelmaxtemp = viewHolder.maxnivel.getText().toString();
int nivel = Integer.parseInt(niveltemp);
int maxxnivel = Integer.parseInt(nivelmaxtemp);
int nuevonivel = nivel+1 ;
if (nuevonivel<=maxxnivel) {
viewHolder.txtv_nivel.setText(String.valueOf(nuevonivel));
}
}
});
My OnCreateViewHolder (nothing really happens here):
#Override
public TropaViewHolder onCreateViewHolder(ViewGroup viewGroup, int i) {
View v = LayoutInflater.from(viewGroup.getContext())
.inflate(R.layout.cardview, viewGroup, false);
return new TropaViewHolder(v);
}
Here is the solution, as mentioned in the comment above, it addresses two problems:
1. positiontoValueMap - saves current value for each position
2. onclicklistener is passed to the ViewHolder in onCreateViewHolder
Adapter Class
public class MyAdapter extends RecyclerView.Adapter {
private Context context;
private List<String> dataList;
private Map<Integer, Integer> positionToValueMap = new HashMap<>();
public MyAdapter(Context context, List<String> dataList) {
this.context = context;
this.dataList = dataList;
}
#Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(context).inflate(R.layout.recycler_view_item, null, false);
return new MyViewHolder(view, new OnRecyclerItemClickListener());
}
#Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
((MyViewHolder) holder).onRecyclerItemClickListener.updatePosition(position);
((MyViewHolder) holder).position.setText("" + position);
((MyViewHolder) holder).title.setText(dataList.get(position));
int valueToDisplay = 1;
if(positionToValueMap.containsKey(position)) {
valueToDisplay = positionToValueMap.get(position);
} else {
positionToValueMap.put(position, valueToDisplay);
}
((MyViewHolder) holder).valueView.setText("value: " + valueToDisplay);
}
#Override
public int getItemCount() {
return dataList.size();
}
private class MyViewHolder extends RecyclerView.ViewHolder {
private OnRecyclerItemClickListener onRecyclerItemClickListener;
private TextView position;
private TextView title;
private TextView valueView;
public MyViewHolder(View itemView, OnRecyclerItemClickListener onRecyclerItemClickListener) {
super(itemView);
itemView.setOnClickListener(onRecyclerItemClickListener);
this.onRecyclerItemClickListener = onRecyclerItemClickListener;
this.position = (TextView) itemView.findViewById(R.id.position);
this.title = (TextView) itemView.findViewById(R.id.title);
this.valueView = (TextView) itemView.findViewById(R.id.value_view);
}
}
private class OnRecyclerItemClickListener implements View.OnClickListener {
private int position = -1;
public void updatePosition(int position) {
this.position = position;
}
#Override
public void onClick(View v) {
int oldValue = positionToValueMap.get(position); // get current value
oldValue++; // increment
positionToValueMap.put(position, oldValue); // save current value
notifyItemChanged(position); // update clicked view so that it picks up the new saved value from the positionToValueMap in onBindViewHolder
}
}
}
RecyclerView item layout
<TextView
android:id="#+id/position"
android:layout_width="30dp"
android:layout_height="50dp"
android:textColor="#android:color/white"
android:gravity="center"
android:background="#android:color/holo_green_light"
android:layout_alignParentLeft="true"/>
<TextView
android:id="#+id/title"
android:layout_width="50dp"
android:layout_height="50dp"
android:textColor="#android:color/white"
android:gravity="center"
android:background="#android:color/holo_green_dark"
android:layout_toRightOf="#id/position" />
<TextView
android:id="#+id/value_view"
android:layout_width="match_parent"
android:layout_height="50dp"
android:textColor="#android:color/white"
android:gravity="center"
android:background="#android:color/holo_green_light"
android:layout_toRightOf="#id/title"
android:layout_alignParentRight="true"/>
</RelativeLayout>
And Activity to test it out
public class MainActivity extends AppCompatActivity {
private RecyclerView recyclerView;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
recyclerView = (RecyclerView) findViewById(R.id.recycler_view);
recyclerView.setLayoutManager(new LinearLayoutManager(getApplicationContext()));
recyclerView.setAdapter(new MyAdapter(getApplicationContext(), getSampleData()));
}
private static List<String> getSampleData() {
List<String> dataList = new ArrayList<>();
dataList.add("zero");
dataList.add("one");
dataList.add("two");
dataList.add("three");
dataList.add("four");
dataList.add("five");
dataList.add("six");
dataList.add("seven");
dataList.add("eight");
dataList.add("nine");
dataList.add("ten");
dataList.add("eleven");
dataList.add("twelve");
dataList.add("thirteen");
dataList.add("fourteen");
dataList.add("fifteen");
dataList.add("sixteen");
dataList.add("seventeen");
dataList.add("eighteen");
dataList.add("nineteen");
dataList.add("twenty");
return dataList;
}
}
activity layout
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/root_view"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.v7.widget.RecyclerView
android:id="#+id/recycler_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#android:color/white"/>
</RelativeLayout>

Categories

Resources