ListView上的聊天气泡对齐

时间:2015-11-19 04:49:12

标签: 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: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>

message_row.xml design

activity_main.xml中

<?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>

activity_main.xml design

以下是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);
}

我注意到getView()的调用次数比列表中的次数多(例如:如果我有2条消息,则getview()被调用4到5次)。 使用当前代码聊天气泡总是在左边,而不管聊天状态如何。

on device

Firebase数据

enter image description here

1 个答案:

答案 0 :(得分:1)

我建议使用两种布局 - 泡泡和对手。在适配器的getView()方法中使用它们。对于list_item_message_own.xml使用正确的allignment和list_item_message_opponent.xml使用left allignment,它取决于消息状态。

@Override
public View getView(Context context, Cursor cursor, ViewGroup parent) {
    View view;
    ViewHolder viewHolder = new ViewHolder();

    MessageCache messageCache = ChatManager.getMessageCacheFromCursor(cursor);
    boolean ownMessage = isOwnMessage(messageCache.getSenderId());

    if (messageCache.getMessagesNotificationType() == null) {

        if (ownMessage) {
            view = layoutInflater.inflate(R.layout.list_item_message_own, null, true);
        } else {
            view = layoutInflater.inflate(R.layout.list_item_message_opponent, null, true);
        }

        viewHolder.timeAttachMessageTextView = (TextView) view.findViewById(R.id.time_attach_message_textview);
        viewHolder.verticalProgressBar.setProgressDrawable(context.getResources().getDrawable(R.drawable.vertical_progressbar));
        viewHolder.centeredProgressBar = (ProgressBar) view.findViewById(R.id.centered_progressbar);
    } else {
        view = layoutInflater.inflate(R.layout.list_item_notification_message, null, true);

        viewHolder.messageTextView = (EmojiTextView) view.findViewById(R.id.message_textview);
        viewHolder.timeTextMessageTextView = (TextView) view.findViewById(
                R.id.time_text_message_textview);
    }

    view.setTag(viewHolder);

    return view;
}