【问题标题】:Chat Bubble Alignment on ListViewListView 上的聊天气泡对齐
【发布时间】:2015-11-19 04:49:11
【问题描述】:

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

这里是代码sn-p

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>

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>

以下是 MessageAdapter 的代码片段

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 次)。 使用当前代码,无论聊天状态如何,聊天气泡始终位于左侧。

Firebase 数据

【问题讨论】:

  • 带有描述的屏幕图片将帮助我们知道在哪里查看您的代码,而不是猜测。此外,如果必须查找或刷新某些内容,则 getView() 的调用次数可能会比列表的计数多得多。不用担心。

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


【解决方案1】:

我建议使用两种布局 - 用于您的气泡和您的对手。在适配器的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;
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2022-11-15
    • 1970-01-01
    • 2021-12-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多