Reputation: 27
I am developing an app which has a text message interface (something like Facebook Messenger, Whatsapp, etc). I want to be able to change the background color of all the chat bubbles (a ListView
of TextView
s) sent by the user when they pick a new color (in a NavigationView
).
However, with the current code that I have, I only am able to change the color after the EditText
used to compose the message is clicked again. Or I am able to only edit the first bubble sent, but as soon as the color is changed.
Here's what I tried :
ItemColor1.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v){
Toast.makeText(activity, "Couleur mise à jour", Toast.LENGTH_SHORT).show();
currentTheme = position;
SharedPreferences.Editor editor = pref.edit();
editor.putInt("indexColorSelected",currentTheme);
editor.apply();
chatAdapter.notifyDataSetChanged();
//the following changes only the first message sent
for(int i=0; i<chatAdapter.getCount(); i++){
ChatData message = chatMessageList.get(position);
TextView msg = activity.findViewById(R.id.text);
msg.setText(message.body);
msg.setBackgroundResource(R.drawable.user_color1);
}
}
});
ChatData
is a custom Class that I created which looks like this :
public class ChatAdapter extends BaseAdapter {
private static LayoutInflater inflater = null;
private ArrayList<ChatData> chatMessageList;
private Context mContext;
ChatAdapter(Activity activity, ArrayList<ChatData> list) {
mContext = activity;
chatMessageList = list;
inflater = (LayoutInflater) activity.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}
...
}
Color drawable:
<corners
android:bottomRightRadius="5dp"
android:radius="40dp"/>
<gradient
android:angle="45"
android:endColor="#01f1fa"
android:startColor="#0189ff"
android:type="linear" />
</shape>
getView()
method of the Adapter:
public View getView(int position, View convertView, ViewGroup parent) {
ChatData message = chatMessageList.get(position);
View vi = convertView;
if (convertView == null)
vi = inflater.inflate(R.layout.msglist, parent, false);
TextView msg = vi.findViewById(R.id.text);
msg.setText(message.body);
LinearLayout layout = vi.findViewById(R.id.message_layout);
LinearLayout parent_layout = vi.findViewById(R.id.message_layout_parent);
inflater = (LayoutInflater) this.mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
// if message is mine then align to right
if (message.isMine) {
layout.setGravity(Gravity.RIGHT);
int couleurBubble = getCouleurSelectionnee();
switch(couleurBubble){
case R.color.c1: msg.setBackgroundResource(R.drawable.user_color1); break;
case R.color.c2: msg.setBackgroundResource(R.drawable.user_color2); break;
case R.color.c3: msg.setBackgroundResource(R.drawable.user_color3); break;
case R.color.c4: msg.setBackgroundResource(R.drawable.user_color4); break;
case R.color.c5: msg.setBackgroundResource(R.drawable.user_color5); break;
case R.color.c6: msg.setBackgroundResource(R.drawable.user_color6); break;
case R.color.c7: msg.setBackgroundResource(R.drawable.user_color7); break;
case R.color.c8: msg.setBackgroundResource(R.drawable.user_color8); break;
default: break;
}
parent_layout.setGravity(Gravity.RIGHT);
}
// If not mine then align to left
else {
layout.setGravity(Gravity.LEFT);
msg.setBackgroundResource(R.drawable.bot_chat);
parent_layout.setGravity(Gravity.LEFT);
}
return vi;
}
I don't really know where to go from here so any kind of help would be appreciated. If you want me to provide more code, let me know and I will.
Thank you.
Upvotes: 1
Views: 108
Reputation: 18687
I'm sharing how I would do it. Maybe, this can help you.
There's some strange issue because you are calling notifyDataSetChanged()
. This would be enough to re-draw all message bubbles.
My ideia is:
Add a int
variable to the adapter class (mColorResource
). This variable will point to the proper drawable that should be used (like R.drawable.user_color1
).
public class ChatAdapter extends BaseAdapter {
int mColorResource;
ChatAdapter(Activity activity, ArrayList<ChatData> list, int initialColorResource) {
mContext = activity;
chatMessageList = list;
inflater = (LayoutInflater) activity.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
// You must receive the color on the construtor
mColorResource = initialColor;
}
// Use this method to update the color (when user select a new color)
public void setColor(int newColorResource) {
mColorResource = newColorResource;
}
public View getView(int position, View convertView, ViewGroup parent) {
...
// Note how this if-else is cleaner now
if (message.isMine) {
layout.setGravity(Gravity.RIGHT);
msg.setBackgroundResource(mColorResource);
parent_layout.setGravity(Gravity.RIGHT);
} else {
layout.setGravity(Gravity.LEFT);
msg.setBackgroundResource(R.drawable.bot_chat);
parent_layout.setGravity(Gravity.LEFT);
}
...
}
}
Then, when a color is selected, find the proper drawable based on the view clicked and pass it to the adapter:
ItemColor1.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v){
Toast.makeText(activity, "Couleur mise à jour", Toast.LENGTH_SHORT).show();
currentTheme = position;
SharedPreferences.Editor editor = pref.edit();
editor.putInt("indexColorSelected", currentTheme);
editor.apply();
// Here, you send the proper drawable...
// I'm not sure how you convert color selected to the drawable
// So, add your logic to convert the button clicked to a drawable here
// like R.drawable.user_color1
chatAdapter.setColor(R.drawable.NAME_OF_THE_COLOR);
// Request to re-draw all items from the list (all bubbles)
chatAdapter.notifyDataSetChanged();
}
});
Also, on your activity, you create the adapter with the last used color. Something like:
@Override
protected void onCreate(@Nullable final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
....
// Set a default color (if user is open you app for the first time)
int chatColor = R.drawable.user_color1;
// Add your logic to read the shared preference and convert that last color used to a valid drawable.
// Like chatColor = pref.getInt(indexColorSelected, R.drawable.user_color1) etc....
// Set the color in the adapter.
chatAdapter = newAdapter(this, mChatDataList, chatColor);
}
Upvotes: 1