Problem Summary: Im implementing a chat application. Outgoing messages should be right aligned, incoming messages left. The chat messages are being displayed in a ListView. Each entry View has a Nine Patch Image as a BackgroundResource which encases the messages inside of a bubble. The problem is with the alignment when I put an ImageButton inside of the Nine Patch. I can not get it to right align. Im not sure if the cause of this is layout related or to the Nine Patch.
Screen shot
As you can see the text message is correctly aligned but the message containing the image is not. It should be aligned to the right
Layout Code
View for text entries (Alignment working)
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content" >
<LinearLayout
android:id="@+id/wrapper_listviewtextrow"
android:layout_width="fill_parent"
android:layout_height="wrap_content" >
<TextView
android:id="@+id/textview_chatmsg"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_margin="5dip"
android:paddingLeft="10dip"
android:textColor ="#000000"
android:text="LstVwRow-Default Text"
android:background="@drawable/bubble_yellow" />
</LinearLayout>
</LinearLayout>
View for img entries (Alignment not working)
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:id="@+id/wrapper">
<ImageButton
android:id="@+id/upload_img_thmbnail"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_alignParentTop="true"
android:layout_marginRight="6dip"
android:paddingLeft="8dp"
android:contentDescription="TODO"
android:onClick=""
android:background="@null"/>
<ProgressBar
android:id="@+id/progress"
style="?android:attr/progressBarStyleSmall"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:visibility="visible"/>
</RelativeLayout>
Adapter Code
public View getView(int position, View convertView, ViewGroup parent) {
//test - id like to see every time getView is invoked. print to log.
Log.i(TAG, "getview invoked.");
View row = convertView;
final ChatListEntry chatentry = getItem(position);
LayoutInflater inflater = (LayoutInflater) this.getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
if(chatentry.msgType.equals("IMG")) {
row = inflater.inflate(R.layout.list_view_row_img, parent, false);
//if message being added to listview is outbound the bitmap is saved in the chatentry obj.
//if it is being downloaded from a server (inbound) the bitmap need to be downloaded in this class.
if(chatentry.isOutbound == false) {
chatentry.imgthmbnail = createThumbnailImg(getBitmapFromURL(chatentry.content));
//test
Log.i(TAG, "bitmap width is" + chatentry.imgthmbnail.getWidth());
}
wrapper = (RelativeLayout) row.findViewById(R.id.wrapper);
ViewHolder viewHolder = new ViewHolder();
viewHolder.btn_showFSImageActivity = (ImageButton) row.findViewById(R.id.upload_img_thmbnail);
viewHolder.imgCaptureThbnail = (ImageView) row.findViewById(R.id.upload_img_thmbnail);
viewHolder.imgCaptureThbnail.setImageBitmap(chatentry.imgthmbnail);
viewHolder.pb = (ProgressBar) row.findViewById(R.id.progress);
row.setTag(viewHolder);
//testing
Log.i(TAG,"img received from srv. Here is associtated text content: " + chatentry.content);
viewHolder.btn_showFSImageActivity.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
Log.i(TAG,"yay button clicked, here is chatentry.content:" + chatentry.content);
MainActivity main_act = (MainActivity) v.getContext();
main_act.onShowImgInActivity(chatentry.content);
}
});
wrapper.setBackgroundResource(chatentry.isOutbound ? R.drawable.bubble_green : R.drawable.bubble_yellow);
wrapper.setGravity(chatentry.isOutbound ? Gravity.RIGHT : Gravity.LEFT);
if(!chatentry.getShow_Progress_Bar()) {
viewHolder.pb.setVisibility(View.INVISIBLE);
}
} else if(chatentry.msgType.equals("TXT")) {
row = inflater.inflate(R.layout.list_view_row, parent, false);
wrapper_text_entry = (LinearLayout) row.findViewById(R.id.wrapper_listviewtextrow);
message = (TextView) row.findViewById(R.id.textview_chatmsg);
message.setText(chatentry.content);
message.setBackgroundResource(chatentry.isOutbound ? R.drawable.bubble_green : R.drawable.bubble_yellow);
wrapper_text_entry.setGravity(chatentry.isOutbound ? Gravity.RIGHT : Gravity.LEFT);
} else
Log.e(TAG, "Something has gone terribly wrong in ChatArrayAdapter-getView.");
return row;
}
Ive tried different ways of encapsulating the widgets in the View and different ways of setting the gravity. No matter what the Views containing the Image wount align to the right.
Any ideas on what might be causing this to happen or any suggestions on how to fix the problem?
I've solved for the requirements although there may be better solutions. First place the ImageView and ProgressBar in a RelativeView. Set layout_alignParentRight to true. Next place the RelativeLayout inside of a LinearLayout. Now all you have to do is set the gravity of the outer container (The LinearLayout). This is done programmatically, depending on whether the message is incoming out outgoing.
ListView item View Layout:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/outer_wrapper_listviewimgrow"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:gravity="left">
<RelativeLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_marginTop="3dip"
android:id="@+id/inner_wrapper_listviewimgrow">
<ImageButton
android:id="@+id/upload_img_thmbnail"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginRight="6dip"
android:paddingLeft="8dp"
android:contentDescription="TODO"
android:onClick=""
android:background="@null"/>
<ProgressBar
android:id="@+id/progress"
style="?android:attr/progressBarStyleSmall"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:visibility="visible"/>
</RelativeLayout>
</LinearLayout>
excerpt from ArrayAdapter:
outer_wrapper_text_entry = (LinearLayout) row.findViewById(R.id.outer_wrapper_listviewtextrow);
outer_wrapper_text_entry.setGravity(chatentry.isOutbound ? Gravity.RIGHT : Gravity.LEFT);
My design for the Layout my not be optimal. Eclipse has generated some warnings:
"This RelativeLayout layout or its LinearLayout parent is possibly useless" - Please offer some suggestions on how to resolve this warning. Can this have any significant consequence on the apps functionality or performance? From my point of view the outer layout is not useless as it is the only way I was able to get the layout to work correctly. Is there a better way to do this?