I'm displaying daily events. The number of events/day is variable. Each item in the RecView is a Day which should contain as many views as the number of events.
Here is one item's layout:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/llDay">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/tvDay"
android:text="TODAY"
android:layout_gravity="center_horizontal"
android:layout_marginTop="15dp"
android:textSize="25sp"
android:textStyle="bold" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/tvNothing"
android:text="No events"
android:layout_gravity="center_horizontal"
android:layout_marginTop="10dp"
android:textSize="18sp"
android:textStyle="italic"
android:visibility="gone"/>
</LinearLayout>
I'd like to add views to the llDay dynamically.
Here is my Adapter:
public class DiaryAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>{
ArrayList<ArrayList<Displayable>> diaryEvents = new ArrayList<>();
Context context;
public DiaryAdapter(ArrayList<ArrayList<Displayable>> diaryEvents, Context context) {
this.diaryEvents = diaryEvents;
this.context = context;
}
#Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
ViewGroup viewGroup = (ViewGroup) LayoutInflater.from(parent.getContext()).inflate(R.layout.layout_day_diary, parent, false);
DiaryDayViewHolder viewHolder = new DiaryDayViewHolder(viewGroup);
return viewHolder;
}
#Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
DiaryDayViewHolder viewHolder = (DiaryDayViewHolder) holder;
ArrayList<Displayable> events = diaryEvents.get(position);
if (events.size() > 0){
addLayouts(events, viewHolder);
}
else{
viewHolder.tvNothing.setVisibility(View.VISIBLE);
}
}
#Override
public int getItemCount() {
return diaryEvents.size();
}
private void addLayouts(ArrayList<Displayable> events, DiaryDayViewHolder viewHolder) {
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT);
for (Displayable event : events) {
switch (event.getEventType()){
case Types.TYPE_TEACHING:
TeachingDiaryLayout teachingDiaryLayout = new TeachingDiaryLayout(context);
teachingDiaryLayout.setLayoutParams(params);
teachingDiaryLayout.setViews((Teaching) event);
viewHolder.llDay.addView(teachingDiaryLayout);
viewHolder.tvDay.setText("DAY"); // TODO: day + date
break;
case Types.TYPE_TASK: // TODO
break;
case Types.TYPE_EXAM: // TODO
break;
}
}
}
}
When the RecyclerView is displayed first, the events are displayed correctly, but after scrolling some events are displayed multiple times. I know that the problem is caussed by calling the addLayouts(...) in the onBindViewHolder(...) but I don't know how to create the correct amount of views for each day.
UPDATE: ViewHolder added:
public static class DiaryDayViewHolder extends RecyclerView.ViewHolder {
LinearLayout llDay;
TextView tvDay;
TextView tvNothing;
public DiaryDayViewHolder(View itemView) {
super(itemView);
llDay = (LinearLayout) itemView.findViewById(R.id.llDay);
tvDay = (TextView) itemView.findViewById(R.id.tvDay);
tvNothing = (TextView) itemView.findViewById(R.id.tvNothing);
}
}
Ok finally figured it out.
Firstly change your layout to:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/llDay">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/tvDay"
android:text="TODAY"
android:layout_gravity="center_horizontal"
android:layout_marginTop="15dp"
android:textSize="25sp"
android:textStyle="bold" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/tvNothing"
android:text="No events"
android:layout_gravity="center_horizontal"
android:layout_marginTop="10dp"
android:textSize="18sp"
android:textStyle="italic"
android:visibility="gone"/>
<LinearLayout
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="#+id/llDay1"/>
</LinearLayout>
now in your view holder add another LinearLayout parameter:
LinearLayout llDay,llday1;
and inside the addLayouts method change:
viewHolder.llDay.addView(teachingDiaryLayout);
to
viewHolder.llDay1.addView(teachingDiaryLayout);
Also before the for loop add
viewHolder.llDay1.removeAllViews();
for (Displayable event : events)
Related
I want that my horizontal recyclerview always shows the first item after setting the adapter instead of scrolling to the centre item. How can I achieve that?
This is my recommendation.xml file:
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="fill_parent"
android:layout_height="wrap_content">
<ImageView
android:id="#+id/img"
android:layout_marginLeft="10dp"
android:layout_width="50dp"
android:layout_height="50dp"
android:layout_marginTop="5dp"
android:layout_marginBottom="5dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="#+id/zone"
android:textColor="#color/colorPrimary"
android:textSize="18sp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintStart_toStartOf="#+id/xyz"
app:layout_constraintEnd_toEndOf="#+id/xyz"
android:layout_marginTop="3dp"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/xyz"
android:gravity="center"
android:textSize="16sp"
android:layout_marginLeft="15dp"
app:layout_constraintTop_toBottomOf="#id/zone"
android:layout_marginTop="5dp"
app:layout_constraintStart_toEndOf="#id/img"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/day"
android:gravity="center"
android:textSize="16sp"
app:layout_constraintTop_toBottomOf="#id/xyz"
app:layout_constraintStart_toStartOf="#id/xyz"
app:layout_constraintEnd_toEndOf="#id/xyz"
app:layout_constraintBottom_toBottomOf="parent"
android:layout_marginBottom="6dp"/>
</androidx.constraintlayout.widget.ConstraintLayout>
This is my adapter class:
class recom_adapter extends RecyclerView.Adapter<recom_adapter.ViewHolder> {
private List<saved_zone> zoneList;
private Context context;
public static PrefConfig prefConfig;
public recom_adapter(List<saved_zone> zoneList, Context context) {
this.zoneList = zoneList;
this.context = context;
}
#NonNull
#Override
public recom_adapter.ViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View view= LayoutInflater.from(parent.getContext()).inflate(R.layout.recommendation,parent,false);
return new recom_adapter.ViewHolder(view);
}
#Override
public void onBindViewHolder(#NonNull recom_adapter.ViewHolder holder, int position) {
saved_zone sz = zoneList.get(position);
Glide.with(context).load(sz.getImageUrl).into(holder.img);
holder.xyz.setText(sz.getXYZ());
holder.day.setText(sz.getDate());
}
#Override
public int getItemCount() {
return zoneList.size();
}
public class ViewHolder extends RecyclerView.ViewHolder{
private ImageView img;
TextView zone, xyz, day;
public ViewHolder(View itemView) {
super(itemView);
img = itemView.findViewById(R.id.img);
zone = itemView.findViewById(R.id.zone);
xyz = itemView.findViewById(R.id.xyz);
day = itemView.findViewById(R.id.day);
}
}
}
This is how I am setting the setting the recyclerView in my adapter in my mainActivity:
recomm_recycler.setLayoutManager(new LinearLayoutManager(getActivity(),LinearLayoutManager.HORIZONTAL, true));
recomData = response.body();
recom_adapter = new recom_adapter(recomData, getActivity());
recomm_recycler.setAdapter(recom_adapter);
recomm_recycler.setLayoutManager(new LinearLayoutManager(getActivity(),LinearLayoutManager.HORIZONTAL, true));
There is problem in your above line.
Change the true to false
New Code
recomm_recycler.setLayoutManager(new LinearLayoutManager(getActivity(),LinearLayoutManager.HORIZONTAL, false));
I had a similar issue with vertical recycler view. In my case adding
android:focusableInTouchMode="true"
to RecyclerView's parent helped me.
Try this in your main XML parent layout
XML:
android:descendantFocusability="blocksDescendants"
Java:
listItem.setDescendantFocusability(FOCUS_BLOCK_DESCENDANTS);
I am using AleSpero's library to create expandable cardviews for my layout. Works as expected, but now I want to add multiple cardviews in the same fragment layout, dynamically binding to some async list data that loads. How would that be possible?
Followed the demo on the library. Here is how I am adding the cards in the layout:
<LinearLayout
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/watchlist_holder"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="20dp"
android:orientation="vertical"
android:clipChildren="false"
android:background="#FAFAFA">
<com.alespero.expandablecardview.ExpandableCardView
android:id="#+id/main_profile_card"
android:layout_marginLeft="10dp"
android:layout_marginRight="10dp"
android:layout_marginTop="10dp"
android:layout_marginBottom="10dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:title="My Watchlist"
app:inner_view="#layout/watchlist_layout"
app:expandOnClick="true" />
</LinearLayout>
#layout/watchlist_layout is a layout I want to repeat, it contain some textView and a recyclerView to show list data. Any help or guidance would be great.
You will need to create different Adapter and Inner Row XML Layout files for each RecyclerView.
For Ex: You inflate a layout in a RecyclerView inside the MainActivity. You are using an Adapter class which is inflating the rows based on your List. Inside onBindViewHolder, you should get the object of the inner RecyclerView which is present in the row layout of the parent view. Once you have the object, create another list and initialize another adapter for the inner recyclerview. Use the new adapter to populate data inside it (similar to the first recyclerview).
Keep in mind, the process remains same, with each recyclerview
Steps:
Create recylcerview inside the layout which is going to display the list
Create a separate row_layout to be inflated in each row based on the number of list data
Crete an Adapter class, which receives data from the parent class and inflates the layout (row_ayout) in the recyclerview
Repeat these steps for N number of Nested RecyclerViews
For the demo, I am attaching sample codes with this answer to help you understand my concept.
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".MainActivity">
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/recylcerViewParent"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>
item_layout_row.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<com.alespero.expandablecardview.ExpandableCardView
android:id="#+id/main_profile_card"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="10dp"
android:layout_marginTop="10dp"
android:layout_marginRight="10dp"
android:layout_marginBottom="10dp"
app:expandOnClick="true"
app:inner_view="#layout/watchlist_inner"
app:title="My Watchlist" />
</RelativeLayout>
item_recycler_view_favorite.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/layout_with_favorites"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:id="#+id/favorites_count"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="#dimen/margin_small"
android:layout_marginLeft="#dimen/margin_small"
android:textSize="12sp" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="#dimen/margin_small"
android:layout_marginEnd="#dimen/margin_small"
android:orientation="horizontal"
android:weightSum="2">
<Button
android:id="#+id/btn_view_details"
android:layout_width="0dp"
android:layout_height="30dp"
android:layout_weight="1"
android:background="#android:color/transparent"
android:gravity="start|center_vertical"
android:padding="5dp"
android:text="Atish"
android:textColor="#color/colorPrimaryDark" />
<Button
android:id="#+id/btn_add_symbols"
android:layout_width="0dp"
android:layout_height="30dp"
android:layout_weight="1"
android:background="#android:color/transparent"
android:gravity="end|center_vertical"
android:padding="5dp"
android:text="Agrawal"
android:textColor="#color/colorPrimaryDark" />
</LinearLayout>
</LinearLayout>
watchlist_inner.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/layout_with_favorites"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:id="#+id/favorites_count"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="#dimen/margin_small"
android:layout_marginLeft="#dimen/margin_small"
android:textSize="12sp" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="#dimen/margin_small"
android:layout_marginEnd="#dimen/margin_small"
android:orientation="horizontal"
android:weightSum="2">
<Button
android:id="#+id/btn_view_details"
android:layout_width="0dp"
android:layout_height="30dp"
android:layout_weight="1"
android:background="#android:color/transparent"
android:gravity="start|center_vertical"
android:padding="5dp"
android:text="VIEW DETAILS"
android:textColor="#color/colorPrimaryDark" />
<Button
android:id="#+id/btn_add_symbols"
android:layout_width="0dp"
android:layout_height="30dp"
android:layout_weight="1"
android:background="#android:color/transparent"
android:gravity="end|center_vertical"
android:padding="5dp"
android:text="ADD SYMBOLS"
android:textColor="#color/colorPrimaryDark" />
</LinearLayout>
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/recycler_view_favorite"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginStart="#dimen/margin_small"
android:layout_marginEnd="#dimen/margin_small"
android:layout_marginBottom="#dimen/margin_small" />
</LinearLayout>
MainActivity.java
public class MainActivity extends AppCompatActivity {
List<String> stringsList = new ArrayList<>();
RecyclerView recyclerViewLayout;
InnerAdapter adapter;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
recyclerViewLayout = findViewById(R.id.recylcerViewParent);
//Dummy add 10 objects in the list
for (int i = 0; i < 10; i++) {
stringsList.add(String.valueOf(i));
}
populateRecyclerView();
}
/**
* Create N items in the recycler view
*/
private void populateRecyclerView() {
//Initialize Adapter
recyclerViewLayout.setLayoutManager(new LinearLayoutManager(this));
recyclerViewLayout.setHasFixedSize(false);
adapter = new InnerAdapter(recyclerViewLayout, this);
adapter.setData(this.stringsList);
recyclerViewLayout.setAdapter(adapter);
}
}
InnerAdapter.java
public class InnerAdapter extends RecyclerView.Adapter<InnerAdapter.ViewHolder> {
private List<String> data;
private RecyclerView recyclerView;
private int i = 0;
private Context mContext;
public InnerAdapter(RecyclerView recyclerView, Context context) {
this.recyclerView = recyclerView;
this.mContext = context;
}
#NonNull
#Override
public ViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
//Inflater creates rows from a given layout file
LayoutInflater inflater = LayoutInflater.from(parent.getContext());
View v = inflater.inflate(R.layout.item_layout_row, parent, false);
return new ViewHolder(v);
}
#Override
public void onBindViewHolder(#NonNull ViewHolder holder, int position) {
//Method to perform actions on individual row based on the position. We will get back to this later
//Change the title of the CardView
holder.main_profile_card.setTitle(String.valueOf(position));
//Creating a dummy adapter again to populate the inner recyclerview
List<String> innerData = new ArrayList<>();
for (int i = 0; i < 10; i++) {
innerData.add(String.valueOf(i));
}
//Initialize Inner Adapter
holder.recycler_view_favorite.setLayoutManager(new LinearLayoutManager(mContext));
holder.recycler_view_favorite.setHasFixedSize(false);
InnerFavAdapter adapter = new InnerFavAdapter(holder.recycler_view_favorite, mContext);
adapter.setData(innerData);
holder.recycler_view_favorite.setAdapter(adapter);
}
#Override
public int getItemCount() {
return data.size();
}
public void setData(List<String> data) {
this.data = data;
}
class ViewHolder extends RecyclerView.ViewHolder {
RecyclerView recycler_view_favorite;
ExpandableCardView main_profile_card;
ViewHolder(View itemView) {
super(itemView);
//Get the object of the views from the row layout
main_profile_card = itemView.findViewById(R.id.main_profile_card);
recycler_view_favorite = itemView.findViewById(R.id.recycler_view_favorite);
}
}
}
InnerFavAdapter.java
public class InnerFavAdapter extends RecyclerView.Adapter<InnerFavAdapter.ViewHolder> {
private List<String> data;
private RecyclerView recyclerView;
private int i = 0;
private Context mContext;
public InnerFavAdapter(RecyclerView recyclerView, Context context) {
this.recyclerView = recyclerView;
this.mContext = context;
}
#NonNull
#Override
public ViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
//Inflater creates rows from a given layout file
LayoutInflater inflater = LayoutInflater.from(parent.getContext());
View v = inflater.inflate(R.layout.inner_recycler_view_favorite, parent, false);
return new ViewHolder(v);
}
#Override
public void onBindViewHolder(#NonNull ViewHolder holder, int position) {
//Method to perform actions on individual row based on the position. We will get back to this later
}
#Override
public int getItemCount() {
return data.size();
}
public void setData(List<String> data) {
this.data = data;
}
class ViewHolder extends RecyclerView.ViewHolder {
ViewHolder(View itemView) {
super(itemView);
}
}
}
I'm working on a chatting application. All I did is i can get api response successfully and can show them serially like this
This is id of sender and reciver
This is the messages
For doing this I created an adapter which code is something like this.
public class Single_chat_adapter extends RecyclerView.Adapter<Single_chat_adapter.Single_chat_adapterViewHolder>{
private List<Datum2> data;
private int rowLayout;
private Context context;
public Single_chat_adapter(List<Datum2> data, int rowLayout, Context context) {
this.data = data;
this.rowLayout = rowLayout;
this.context = context;
}
#Override
public Single_chat_adapterViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.card2, parent, false);
return new Single_chat_adapterViewHolder(view); }
#Override
public void onBindViewHolder(Single_chat_adapterViewHolder holder, int position) {
holder.single_msg.setText(data.get(position).getMsg());
}
#Override
public int getItemCount() {
return data.size();
}
public class Single_chat_adapterViewHolder extends RecyclerView.ViewHolder {
TextView single_msg;
public Single_chat_adapterViewHolder(View itemView) {
super(itemView);
single_msg =itemView.findViewById(R.id.userNameTV);
}
}
}
Here I use a single view which is card2.xml. But all I need to do is set senders message in the left side and receiver message in other side.
What To do?
To achieve what you have explained, Create two views in card2.xml(one at the left and the other in the right). I have created one for you.
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:paddingStart="5dp"
android:paddingEnd="5dp"
android:layout_marginBottom="6dp"
android:layout_marginTop="4dp"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<ImageView
android:layout_width="40dp"
android:id="#+id/avatar"
android:background="#drawable/circle_stroke"
android:layout_marginStart="5dp"
android:layout_marginEnd="5dp"
android:src="#drawable/useric"
android:layout_height="40dp" />
<RelativeLayout
android:layout_toEndOf="#+id/avatar"
android:id="#+id/msg_back"
android:layout_marginBottom="5dp"
android:layout_gravity="center_vertical"
android:background="#drawable/message_bubble_accent"
android:layout_width="match_parent"
android:padding="10dp"
android:orientation="vertical"
android:layout_height="wrap_content">
<TextView
android:textSize="17sp"
android:id="#+id/user_text"
android:layout_width="wrap_content"
android:textColor="#color/white"
android:text="Hello world how are you?"
android:layout_height="wrap_content" />
<TextView
android:textSize="12sp"
android:layout_below="#+id/user_text"
android:id="#+id/chat_time"
android:textColor="#color/dark"
android:text="3:33pm"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</RelativeLayout>
<ImageView
android:layout_width="40dp"
android:id="#+id/avatar2"
android:layout_alignParentEnd="true"
android:layout_below="#+id/msg_back"
android:background="#drawable/circle_stroke"
android:layout_marginStart="5dp"
android:layout_marginEnd="5dp"
android:src="#drawable/useric"
android:layout_height="40dp" />
<RelativeLayout
android:layout_toStartOf="#+id/avatar2"
android:layout_below="#+id/msg_back"
android:id="#+id/msg_back2"
android:layout_gravity="center_vertical"
android:background="#drawable/message_bubble_white"
android:layout_width="match_parent"
android:padding="10dp"
android:orientation="vertical"
android:layout_height="wrap_content">
<TextView
android:textSize="17sp"
android:id="#+id/user_text2"
android:layout_width="wrap_content"
android:textColor="#color/white"
android:text="Hello world how are you?"
android:layout_height="wrap_content" />
<TextView
android:layout_below="#+id/user_text2"
android:id="#+id/chat_time2"
android:textColor="#color/dark"
android:text="3:33pm"
android:textSize="12sp"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<TextView
android:layout_alignParentEnd="true"
android:layout_below="#+id/user_text2"
android:text="#string/sent"
android:width="20dp"
android:textAppearance="?android:textAppearanceSmall"
android:layout_width="20dp"
android:layout_height="20dp"
android:textColor="#android:color/holo_green_light"/>
</RelativeLayout>
</RelativeLayout>
</LinearLayout>
Modify your onBindViewHolder and add the condition that will check if the message is coming from another user or not. Like this...
#Override
public void onBindViewHolder(Single_chat_adapterViewHolder holder, int position) {
Datum2 datum = data.get(position);
holder.single_msg.setText(datum.getMsg());
int msgId = datum.getMsgId();
if (msgId == datum.getUserMsgId) {
//Do everything pertaining to this user here
holder.rightBubble.setText(single_msg);
//holder.rightAvatar.setText(single_msg) //For setting image
} else {
holder.leftBubble.setText(single_msg);
}
}
Make sure you reference leftBubble and rightBubble from you ViewHolder, and set the current userMsgid from the activity that is using this adapter.
You have to create 2 viewtype and two xml for them additionally and load them in a single adapter. Follow the link may help you.
Android Chat Tutorial: Building a Messaging UI
1) Create 2 views in card2.xml
2) One for left and another for right
3) Put condition in your onBindViewHolder, if message is from senders make left view visible and hide right view and same thing for right view also.
You can put condition inside onCreateViewHolder, this will let you to swap the layout (xml file)
#Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
int layout = -1;
switch (viewType) {
case Message.TYPE_MESSAGE:
layout = R.layout.item_message;
break;
case Message.TYPE_LOG:
layout = R.layout.item_log;
break;
case Message.TYPE_ACTION:
layout = R.layout.item_action;
break;
}
View v = LayoutInflater
.from(parent.getContext())
.inflate(layout, parent, false);
return new ViewHolder(v);
}
You can change viewtype from this method
#Override
public int getItemViewType(int position) {
// Just as an example, return 0 or 2 depending on position
// Note that unlike in ListView adapters, types don't have to be contiguous
return position % 2 * 2;
}
I am implementing chat application in android using xmpp.My Chat is working fine but when i am setting layout for sender and receiver in chat then the inflater is changing layout for all existing list item.
Below is the screenshot when user sends "Hi"
But when receiver sends "hello" then this chat message is comming to left position but it is also taking other messages to left postion and same when sending messages..
Below is the screenshot when user receives "Hello"
And followed by this when sending "How are you"
I dont where i am wrong
My recycler view sender layout
chat_layout_self.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="10dp"
android:layout_gravity="right|bottom"
android:gravity="right|bottom"
>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#drawable/chatsymbolself">
<TextView
android:id="#+id/cltv"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="hi"
android:textSize="20sp"
android:textColor="#fff"
android:padding="10dp"
android:layout_gravity="left|bottom"/>
</LinearLayout>
</LinearLayout>
chat_layout_other.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="10dp"
android:layout_gravity="left|bottom"
android:gravity="left|bottom"
>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#drawable/chatsymbolother">
<TextView
android:id="#+id/cltv"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="hi"
android:textSize="20sp"
android:textColor="#fff"
android:padding="10dp"
android:layout_gravity="left"/>
</LinearLayout>
</LinearLayout>
MessageAdapter.java
public class MessageAdapter extends RecyclerView.Adapter<MessageAdapter.MyViewHolder> {
private String user="+918439198269#desktop-5ehan36/Android";
private LayoutInflater inflater;
List<Message> data= Collections.emptyList();
public MessageAdapter(Context context,List<Message> data){
inflater=LayoutInflater.from(context);
this.data=data;
}
#Override
public int getItemViewType(int position) {
Message message = data.get(position);
Log.e("MAdapter", "getItemViewType: from "+message.from);
if (message.from.equals(user)){
return 0;
}
else {
return 1;
}
}
#Override
public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view;
MyViewHolder holder;
if(viewType==0){
Log.e("MAdapter", "onCreateViewHolder: SEFL");
view=LayoutInflater.from(parent.getContext()).inflate(R.layout.chat_layout_self,parent,false);
}
else{
Log.e("MAdapter", "onCreateViewHolder: OTHER");
view=LayoutInflater.from(parent.getContext()).inflate(R.layout.chat_layout_other,parent,false);
}
return new MyViewHolder(view);
}
#Override
public void onBindViewHolder(MyViewHolder holder, int position) {
final int itemType = getItemViewType(position);
Message current=data.get(position);
holder.chat.setText(current.msg);
}
#Override
public int getItemCount() {
return data.size();
}
class MyViewHolder extends RecyclerView.ViewHolder{
TextView chat;
public MyViewHolder(View itemView) {
super(itemView);
chat=(TextView)itemView.findViewById(R.id.cltv);
}
}
}
I think, it because of your layout which have circular layout size. you should change the TextView width to wrap_content rather than match_parent.
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:id="#+id/cltv"
android:background="#drawable/chatsymbolother"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="hi"
android:textSize="20sp"
android:textColor="#fff"
android:padding="10dp"
android:layout_gravity="left"/>
</LinearLayout>
make your viewholder static
You don't need to create deep xml layout, if simple textview is enough.
I have a list that when you click on the row on the right side the layout with the icon is changed by other. This makes it well but when I scrolling in the list, I notice there are rows with the same icon without do click. Also, if I scroll quickly these same icons are lost and are built differently. I think it's on the reuse of cells but I can not find the solution. What I want is that the image stays active only in the row where clicka.
Thanks!!
Adapter class:
public class ListadoVotantesArrayAdapter extends ArrayAdapter<Votante> {
private Context context;
private LayoutInflater inflater;
private ArrayList<Votante> listaVotantes;
private int rowLayout;
private View mConverView;
public ListadoVotantesArrayAdapter(Context context, int resource, ArrayList<Votante> objects) {
super(context, resource,objects);
this.context = context;
this.inflater = LayoutInflater.from(context);
this.listaVotantes = objects;
this.rowLayout = resource;
}
public int getCount(){
return this.listaVotantes.size();
}
public Votante getVotante(int position){
return this.listaVotantes.get(position);
}
private static class ViewHolder {
public TextView lblName;
public TextView lblLastName;
public TextView lblDni;
public TextView lblVoterNumber;
public RelativeLayout lytVoted;
public RelativeLayout lytCanVote;
public RelativeLayout lytUndo;
}
public View getView(int position, View converView, ViewGroup parent) {
final ViewHolder viewHolder;
mConverView = converView;
if (mConverView == null){
viewHolder = new ViewHolder();
this.mConverView = inflater.inflate(this.rowLayout, parent, false);
if (mConverView != null){
viewHolder.lblName = (TextView) mConverView.findViewById(R.id.lblVoterName);
viewHolder.lblLastName = (TextView) mConverView.findViewById(R.id.lblVoterLastName);
viewHolder.lblDni = (TextView) mConverView.findViewById(R.id.lblDni);
viewHolder.lblVoterNumber = (TextView) mConverView.findViewById(R.id.lblNumber);
viewHolder.lytVoted = (RelativeLayout) mConverView.findViewById(R.id.lytVoted);
viewHolder.lytCanVote = (RelativeLayout) mConverView.findViewById(R.id.lytCanVote);
viewHolder.lytUndo = (RelativeLayout) mConverView.findViewById(R.id.lytUndo);
mConverView.setTag(viewHolder);
}
}else{
viewHolder = (ViewHolder) mConverView.getTag();
}
Votante votante = getVotante(position);
viewHolder.lblName.setText(votante.getNombre());
viewHolder.lblLastName.setText(votante.getApellidos());
viewHolder.lblDni.setText(votante.getDni());
viewHolder.lblVoterNumber.setText(""+votante.getNumVotante());
if (votante.getVotado()){
viewHolder.lytVoted.setVisibility(View.VISIBLE);
viewHolder.lytCanVote.setVisibility(View.GONE);
}else{
viewHolder.lytVoted.setVisibility(View.GONE);
viewHolder.lytCanVote.setVisibility(View.VISIBLE);
}
mConverView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
viewHolder.lytUndo.setVisibility(View.VISIBLE);
notifyDataSetChanged();
}
});
return mConverView;
}
}
Layout Row:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/lyt_voter"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="1dp">
<RelativeLayout
android:id="#+id/lytVoterNumber"
android:layout_width="70dp"
android:layout_height="70dp"
android:layout_alignParentLeft="true"
android:background="#color/lightBlueItemList">
<TextView
android:id="#+id/lblNumber"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true"
android:text="1999"
android:textAppearance="?android:attr/textAppearanceMedium" />
</RelativeLayout>
<LinearLayout
android:id="#+id/lytVoterData"
android:layout_width="wrap_content"
android:layout_height="70dp"
android:layout_alignParentTop="true"
android:layout_toLeftOf="#+id/lytCanVote"
android:layout_toRightOf="#+id/lytVoterNumber"
android:layout_toStartOf="#+id/lytCanVote"
android:background="#color/whiteItemList"
android:orientation="vertical"
android:padding="5dp">
<TextView
android:id="#+id/lblVoterLastName"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Suarez Garcia de la Serna"
android:textAppearance="?android:attr/textAppearanceMedium" />
<TextView
android:id="#+id/lblVoterName"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="José Carlos"
android:textAppearance="?android:attr/textAppearanceMedium" />
<TextView
android:id="#+id/lblDni"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="44950962S"
android:textAppearance="?android:attr/textAppearanceMedium" />
</LinearLayout>
<RelativeLayout
android:id="#+id/lytCanVote"
android:layout_width="70dp"
android:layout_height="70dp"
android:layout_alignParentRight="true"
android:background="#color/yellowItemList"
android:minHeight="30dp"
android:minWidth="30dp">
<ImageView
android:id="#+id/imgVote"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true"
android:src="#drawable/flecha" />
</RelativeLayout>
<RelativeLayout
android:id="#+id/lytVoted"
android:layout_width="70dp"
android:layout_height="70dp"
android:layout_alignParentRight="true"
android:background="#color/grrenAcceptList"
android:minHeight="30dp"
android:minWidth="30dp"
android:visibility="gone">
<ImageView
android:id="#+id/imgAccept"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true"
android:src="#drawable/aceptar"
/>
</RelativeLayout>
<RelativeLayout
android:layout_width="70dp"
android:layout_height="70dp"
android:minHeight="30dp"
android:minWidth="30dp"
android:background="#color/redD3"
android:id="#+id/lytUndo"
android:layout_alignParentRight="true"
android:visibility="gone">
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/imgUndo"
android:layout_centerVertical="true"
android:layout_centerHorizontal="true"
android:src="#drawable/undo"/>
</RelativeLayout>
</RelativeLayout>
You need to follow below Idea
1) this line of code mConverView = converView; doesn't makes sense. directly use converView(View from getView param). Remove mConvertView from the adapter.
2) Add some mechanism which can tell you which row is clicked and save that variable.
Example:- Have an boolean Array of size Rows.size . and set them in onClick.
Boolean[] array = new Boolean[getSize()];
in onClick that you already have in your getview set this.
public void onClick(View v) {
array[position] = !array[position];
viewHolder.lytUndo.setVisibility(View.VISIBLE);
//You do not need to call notifyDatasetChange.
3) in getView(), when you are setting data in to row items/or just before onClick. have a check like below.
if(array[position])// this will tell you if you need to show or hid lytUndo thing
viewHolder.lytUndo.setVisibility(View.VISIBLE); // Show it
else
viewHolder.lytUndo.setVisibility(View.GONE); // hide it or do whatever you want
You might need to set some params as final
I have written this as simple as possible, comment back with your result.