android - ListView 上的聊天气泡对齐

标签 android android-layout firebase firebase-realtime-database getview

我已将我的 android 应用程序连接到 Firebase,并且正在发送具有属性“名称”和“状态”的消息。发送或接收状态。 我在根据状态向左/右对齐聊天气泡时遇到问题。

这是代码 fragment

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 的代码 fragment

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

最佳答案

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

@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;
}

关于android - ListView 上的聊天气泡对齐,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33795484/

相关文章:

android - Surfaceview 上的 Admob

android - 选定的单卡 View 并更改颜色

java - 检测用户手指触摸的大小

Android:以编程方式在表格中创建两列

android - 我如何创建一个带有下面 TextView 的按钮网格

android - Firebase Cloud Messaging 将服务器 key 替换为用于发送通知/消息的 token

android - 无法在未调用 Looper.prepare 的线程内创建处理程序

javascript - Firebase NPM 包中缺少区域

java - 检索Firebase数据库数据并列出

java - 如何从Firebase数据库Android获取子节点