Android ListView上的聊天气泡对齐
我已经将我的android应用程序连接到Firebase,我正在发送带有“name”和“status”属性的消息。正在发送或接收的状态。 根据状态将聊天气泡左/右对齐时,我遇到了问题 下面是代码片段 message_row.xmlAndroid ListView上的聊天气泡对齐,android,android-layout,firebase,firebase-realtime-database,getview,Android,Android Layout,Firebase,Firebase Realtime Database,Getview,我已经将我的android应用程序连接到Firebase,我正在发送带有“name”和“status”属性的消息。正在发送或接收的状态。 根据状态将聊天气泡左/右对齐时,我遇到了问题 下面是代码片段 message_row.xml <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layou
<?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="fill_parent"
android:orientation="horizontal">
<LinearLayout
android:id="@+id/singleMessageContainer"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/message_bubble_received">
<TextView
android:id="@+id/username_text_view"
android:layout_width="wrap_content"
android:paddingLeft="10dip"
android:layout_margin="5dip"
android:text="Hello bubbles!"
android:layout_height="wrap_content"/>
<TextView
android:id="@+id/message_text_view"
android:layout_width="wrap_content"
android:paddingLeft="1dip"
android:layout_margin="5dip"
android:text="Hello bubbles!"
android:layout_height="wrap_content" />
</LinearLayout>
</LinearLayout>
<?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="fill_parent"
android:background="#ECECEC">
<ListView
android:id="@+id/listView"
android:layout_width="fill_parent"
android:layout_height="match_parent"
android:divider="@null"
android:layout_marginTop="10dp"
android:listSelector="@android:color/transparent"
android:transcriptMode="alwaysScroll"
android:layout_marginBottom="80dp"/>
<RelativeLayout
android:id="@+id/form"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_alignParentLeft="true"
android:orientation="vertical" >
<LinearLayout
android:id="@+id/container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:orientation="horizontal">
<EditText
android:id="@+id/message_text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_gravity="left"
android:layout_marginLeft="5dp"
android:layout_marginRight="10dp"
android:layout_marginBottom="5dp"
android:layout_weight="3"
android:autoText="true"
android:background="@drawable/note_backgroud"
android:hint="Write your question here"
android:minLines="1"
android:paddingLeft="20dp"
android:paddingRight="8dp"
android:paddingBottom="16dp"
android:paddingTop="8dp"/>
<ImageButton
android:id="@+id/cameraButton"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:background="@null"
android:src="@drawable/camera"
android:gravity="top|right"
android:layout_marginRight="8dp"
android:layout_marginLeft="-52dp"
/>
<ImageButton
android:id="@+id/chatSendButton"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:src="@drawable/sent"
android:background="@null"
android:layout_gravity="center"
android:layout_marginRight="8dp"
android:layout_marginLeft="8dp"
android:text="Send"
android:onClick="onSendButtonClick"
android:textColor="#ffffff" />
</LinearLayout>
</RelativeLayout>
</RelativeLayout>
活动\u main.xml
<?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="fill_parent"
android:orientation="horizontal">
<LinearLayout
android:id="@+id/singleMessageContainer"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/message_bubble_received">
<TextView
android:id="@+id/username_text_view"
android:layout_width="wrap_content"
android:paddingLeft="10dip"
android:layout_margin="5dip"
android:text="Hello bubbles!"
android:layout_height="wrap_content"/>
<TextView
android:id="@+id/message_text_view"
android:layout_width="wrap_content"
android:paddingLeft="1dip"
android:layout_margin="5dip"
android:text="Hello bubbles!"
android:layout_height="wrap_content" />
</LinearLayout>
</LinearLayout>
<?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="fill_parent"
android:background="#ECECEC">
<ListView
android:id="@+id/listView"
android:layout_width="fill_parent"
android:layout_height="match_parent"
android:divider="@null"
android:layout_marginTop="10dp"
android:listSelector="@android:color/transparent"
android:transcriptMode="alwaysScroll"
android:layout_marginBottom="80dp"/>
<RelativeLayout
android:id="@+id/form"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_alignParentLeft="true"
android:orientation="vertical" >
<LinearLayout
android:id="@+id/container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:orientation="horizontal">
<EditText
android:id="@+id/message_text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_gravity="left"
android:layout_marginLeft="5dp"
android:layout_marginRight="10dp"
android:layout_marginBottom="5dp"
android:layout_weight="3"
android:autoText="true"
android:background="@drawable/note_backgroud"
android:hint="Write your question here"
android:minLines="1"
android:paddingLeft="20dp"
android:paddingRight="8dp"
android:paddingBottom="16dp"
android:paddingTop="8dp"/>
<ImageButton
android:id="@+id/cameraButton"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:background="@null"
android:src="@drawable/camera"
android:gravity="top|right"
android:layout_marginRight="8dp"
android:layout_marginLeft="-52dp"
/>
<ImageButton
android:id="@+id/chatSendButton"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:src="@drawable/sent"
android:background="@null"
android:layout_gravity="center"
android:layout_marginRight="8dp"
android:layout_marginLeft="8dp"
android:text="Send"
android:onClick="onSendButtonClick"
android:textColor="#ffffff" />
</LinearLayout>
</RelativeLayout>
</RelativeLayout>
下面是MessageAdapter的代码snipet
MessageAdapter.java
public abstract class MessageAdapter<T> extends BaseAdapter {
private Query mRef;
private Class<T> mModelClass;
private int mLayout;
private LayoutInflater mInflater;
private List<T> mModels;
private List<String> mKeys;
private ChildEventListener mListener;
private Context context;
private LinearLayout message_row;
private ProgressDialog mProgressDialog;
public MessageAdapter(Query mRef, Class<T> mModelClass, int mLayout, Activity activity) {
this.mRef = mRef;
this.mModelClass = mModelClass;
this.mLayout = mLayout;
this.context = activity.getApplicationContext();
mInflater = activity.getLayoutInflater();
mModels = new ArrayList<T>();
mKeys = new ArrayList<String>();
mProgressDialog = new ProgressDialog(activity);
mProgressDialog.show();
// Look for all child events. We will then map them to our own internal ArrayList, which backs ListView
mListener = this.mRef.addChildEventListener(new ChildEventListener() {
@Override
public void onChildAdded(DataSnapshot dataSnapshot, String previousChildName) {
T model = dataSnapshot.getValue(MessageAdapter.this.mModelClass);
String key = dataSnapshot.getKey();
// Insert into the correct location, based on previousChildName
if (previousChildName == null) {
mModels.add(0, model);
mKeys.add(0, key);
} else {
int previousIndex = mKeys.indexOf(previousChildName);
int nextIndex = previousIndex + 1;
if (nextIndex == mModels.size()) {
mModels.add(model);
mKeys.add(key);
} else {
mModels.add(nextIndex, model);
mKeys.add(nextIndex, key);
}
}
notifyDataSetChanged();
mProgressDialog.dismiss();
}
@Override
public void onChildChanged(DataSnapshot dataSnapshot, String s) {
// One of the mModels changed. Replace it in our list and name mapping
String key = dataSnapshot.getKey();
T newModel = dataSnapshot.getValue(MessageAdapter.this.mModelClass);
int index = mKeys.indexOf(key);
mModels.set(index, newModel);
notifyDataSetChanged();
}
@Override
public void onChildRemoved(DataSnapshot dataSnapshot) {
// A model was removed from the list. Remove it from our list and the name mapping
String key = dataSnapshot.getKey();
int index = mKeys.indexOf(key);
mKeys.remove(index);
mModels.remove(index);
notifyDataSetChanged();
}
@Override
public void onChildMoved(DataSnapshot dataSnapshot, String previousChildName) {
// A model changed position in the list. Update our list accordingly
String key = dataSnapshot.getKey();
T newModel = dataSnapshot.getValue(MessageAdapter.this.mModelClass);
int index = mKeys.indexOf(key);
mModels.remove(index);
mKeys.remove(index);
if (previousChildName == null) {
mModels.add(0, newModel);
mKeys.add(0, key);
} else {
int previousIndex = mKeys.indexOf(previousChildName);
int nextIndex = previousIndex + 1;
if (nextIndex == mModels.size()) {
mModels.add(newModel);
mKeys.add(key);
} else {
mModels.add(nextIndex, newModel);
mKeys.add(nextIndex, key);
}
}
notifyDataSetChanged();
}
@Override
public void onCancelled(FirebaseError firebaseError) {
Log.e("FirebaseListAdapter", "Listen was cancelled, no more updates will occur");
}
});
}
public void cleanup() {
// We're being destroyed, let go of our mListener and forget about all of the mModels
mRef.removeEventListener(mListener);
mModels.clear();
mKeys.clear();
}
@Override
public int getCount() {
return mModels.size();
}
@Override
public Object getItem(int i) {
return mModels.get(i);
}
@Override
public long getItemId(int i) {
return i;
}
@Override
public View getView(int i, View view, ViewGroup viewGroup) {
LayoutInflater vi = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
if (view == null) {
view = mInflater.inflate(mLayout, viewGroup, false);
message_row = (LinearLayout) view.findViewById(R.id.singleMessageContainer);
}
T model = mModels.get(i);
Message m = (Message) model;
Log.i("status", m.getStatus());
if (m.getStatus().equals("sent")){
message_row.setGravity(Gravity.LEFT);
message_row.setBackgroundResource(R.drawable.message_bubble_received);
}
else {
message_row.setGravity(Gravity.RIGHT);
message_row.setBackgroundResource(R.drawable.message_bubble_sent);
}
// Call out to subclass to marshall this model into the provided view
populateView(view, model);
return view;
}
protected abstract void populateView(View v, T model);
}
公共抽象类MessageAdapter扩展了BaseAdapter{
私有查询mRef;
私人类;
私人内部布局;
私人停车场;
私有列表MMODEL;
私人名单;
私家子弟;
私人语境;
专用线路布局信息_行;
private ProgressDialog mProgressDialog;
公共消息适配器(查询mRef、类mModelClass、int-mLayout、活动){
this.mRef=mRef;
this.mModelClass=mModelClass;
this.mLayout=mLayout;
this.context=activity.getApplicationContext();
mInflater=activity.getLayoutFlater();
mModels=新的ArrayList();
mKeys=newarraylist();
mProgressDialog=新建进度对话框(活动);
mProgressDialog.show();
//查找所有子事件,然后将它们映射到我们自己的内部ArrayList,它支持ListView
mListener=this.mRef.addChildEventListener(新的ChildEventListener()){
@凌驾
公共void onChildAdded(DataSnapshot DataSnapshot,字符串previousChildName){
T model=dataSnapshot.getValue(MessageAdapter.this.mModelClass);
String key=dataSnapshot.getKey();
//根据previousChildName插入到正确的位置
如果(previousChildName==null){
mModels.add(0,模型);
mKeys.add(0,键);
}否则{
int-previousIndex=mKeys.indexOf(previousChildName);
int nextIndex=以前的索引+1;
如果(nextIndex==mModels.size()){
mModels.add(模型);
添加(键);
}否则{
mModels.add(nextIndex,model);
mKeys.add(nextIndex,key);
}
}
notifyDataSetChanged();
mProgressDialog.disclose();
}
@凌驾
公共void onChildChanged(DataSnapshot DataSnapshot,字符串s){
//其中一个MMODEL已更改。请在列表和名称映射中替换它
String key=dataSnapshot.getKey();
T newModel=dataSnapshot.getValue(MessageAdapter.this.mModelClass);
int index=mKeys.indexOf(键);
mModels.set(索引,新模型);
notifyDataSetChanged();
}
@凌驾
ChildRemoved上的公共void(DataSnapshot DataSnapshot){
//已从列表中删除模型。请将其从列表和名称映射中删除
String key=dataSnapshot.getKey();
int index=mKeys.indexOf(键);
移除(索引);
mModels.remove(索引);
notifyDataSetChanged();
}
@凌驾
onChildMoved公共void(DataSnapshot DataSnapshot,字符串previousChildName){
//模型在列表中的位置已更改。请相应地更新我们的列表
String key=dataSnapshot.getKey();
T newModel=dataSnapshot.getValue(MessageAdapter.this.mModelClass);
int index=mKeys.indexOf(键);
mModels.remove(索引);
移除(索引);
如果(previousChildName==null){
mModels.add(0,新模型);
mKeys.add(0,键);
}否则{
int-previousIndex=mKeys.indexOf(previousChildName);
int nextIndex=以前的索引+1;
如果(nextIndex==mModels.size()){
mModels.add(newModel);
添加(键);
}否则{
mModels.add(nextIndex,newModel);
mKeys.add(nextIndex,key);
}
}
notifyDataSetChanged();
}
@凌驾
取消后的公共无效(FirebaseError FirebaseError){
Log.e(“FirebaseListAdapter”,“侦听已取消,将不再进行更新”);
}
});
}
公共空间清理(){
//我们被毁灭了,放开我们的mListener,忘掉所有的MModel
mRef.removeEventListener(mListener);
mModels.clear();
mKeys.clear();
}
@凌驾
public int getCount(){
返回mModels.size();
}
@凌驾
公共对象getItem(int i){
返回mModels.get(i);
}
@凌驾
公共长getItemId(int i){
返回i;
}
@凌驾
公共视图getView(int i、视图视图、视图组视图组){
LayoutInflater vi=(LayoutInflater)context.getSystemService(context.LAYOUT\u INFLATER\u SERVICE);
如果(视图==null){
视图=最小平坦度。充气(最小布局、视图组、假);
message_row=(LinearLayout)view.findViewById(R.id.singleMessageContainer);
}
T model=mModels.get(i);
消息m=(消息)模型;
Log.i(“status”,m.getStatus());
if(m.getStatus().equals(“sent”)){
信息_row.setGravity(Gravity.LEFT);
消息行。setBackgroundResource(R.drawable。消息气泡已接收);
}
否则{
信息_row.setGravity(Gravity.RIGHT);
消息行。setBackgroundResource(R.drawable.message\u bubble\u sent);
}
//调用子类将此模型打包到提供的视图中
populateView(视图、模型);
返回视图;
}
受保护的抽象void populateView(视图v,T模型);
}
我注意到调用getView()的次数超过了列表中的计数(例如:如果我有2条消息,则调用getView()的次数为4到5次)。
使用当前代码,聊天泡泡始终位于左侧