草庐IT

Android在ListView中实现聊天气泡

coder 2023-11-20 原文

我正在 Android 上编写聊天客户端,但在我的客户端中放置聊天气泡时遇到了一些问题。我的聊天屏幕由一个 ListView 组成,底部有一个文本框和一个发送按钮。对于传出消息,文本在 ListView 行中左对齐。对于传入消息,文本在 ListView 行中右对齐。但是,聊天气泡不会调整为传入消息文本的长度。对于左对齐的传出消息,不会发生此问题。

下面是屏幕截图。

聊天消息文本存储在数据库中,并通过光标适配器显示在 ListView 中。聊天文本的对齐方式在 MessageAdapter 中的 Java 源代码中即时确定。两个聊天气泡都是使用 Android 的 9-patch 图像完成的。

下面是我的聊天 Activity 布局,有问题的 ListViewmessageHistoryList:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 
  android:orientation="vertical"
  android:padding="10dip" 
  android:layout_width="fill_parent"
  android:layout_height="fill_parent">

    <ListView
      android:id="@+id/messageHistoryList"
      android:layout_width="wrap_content" 
      android:layout_height="0px" 
      android:layout_weight="1"/>

    <LinearLayout 
      android:layout_width="fill_parent" 
      android:layout_height="wrap_content" >

      <EditText
        android:id="@+id/message"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:gravity="top"
        android:layout_weight="1"/>

      <Button 
          android:id="@+id/sendMessageButton"
          android:layout_width="fill_parent"
          android:layout_height="wrap_content"
          android:layout_weight="4"
          android:text="Send"/>

    </LinearLayout>

</LinearLayout>

ListView 行布局:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
  xmlns:android="http://schemas.android.com/apk/res/android"
  android:orientation="vertical"
  android:layout_width="wrap_content"
  android:layout_height="wrap_content">

    <RelativeLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/userAndMessage">

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:id="@+id/textUser"
            android:textStyle="bold"
            android:textColor="@color/blue"/>

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:id="@+id/textMessage"
            android:textColor="@color/blue"
            android:textStyle="bold"/>

    </RelativeLayout>

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/textTime"
        android:textColor="@color/blue"/>

</RelativeLayout>

消息适配器:

public class MessageAdapter extends SimpleCursorAdapter {

    static final String[] FROM = { ChatHistoryManager.C_TIME };
    static final int[] TO = { R.id.textTime };

    static final int MESSAGE_INCOMING_DIR = 1;

    private String incomingMessageUserName;
    private String selfUserName;

    public MessageAdapter(Context context, Cursor cursor) {
        super(context, R.layout.message_list_item, cursor, FROM, TO);
    }

    @Override
    public void bindView(View row, Context context, Cursor cursor) {
        super.bindView(row, context, cursor);

        int messageDir = cursor.getInt(cursor.getColumnIndex(ChatHistoryManager.C_DIR));
        if(messageDir == MESSAGE_INCOMING_DIR) {

            RelativeLayout.LayoutParams userNameAndChatMessageParams = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.WRAP_CONTENT, RelativeLayout.LayoutParams.WRAP_CONTENT);
            userNameAndChatMessageParams.addRule(RelativeLayout.ALIGN_PARENT_RIGHT, RelativeLayout.TRUE);

            RelativeLayout.LayoutParams userNameParams = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.WRAP_CONTENT, RelativeLayout.LayoutParams.WRAP_CONTENT);
            userNameParams.addRule(RelativeLayout.LEFT_OF, R.id.textMessage);

            RelativeLayout.LayoutParams chatMessageParams = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.WRAP_CONTENT, RelativeLayout.LayoutParams.WRAP_CONTENT);
            chatMessageParams.addRule(RelativeLayout.ALIGN_PARENT_RIGHT, R.id.textUser);

            RelativeLayout.LayoutParams timeParams = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.WRAP_CONTENT, RelativeLayout.LayoutParams.WRAP_CONTENT);
            timeParams.addRule(RelativeLayout.ALIGN_RIGHT, R.id.userAndMessage);
            timeParams.addRule(RelativeLayout.BELOW, R.id.userAndMessage);

            row.setBackgroundResource(R.color.grey);

            // Set the chat message
            String chatMessage = cursor.getString(cursor.getColumnIndex(ChatHistoryManager.C_TEXT));
            TextView textMessage = (TextView) row.findViewById(R.id.textMessage);
            textMessage.setText(chatMessage.trim());
            textMessage.setLayoutParams(chatMessageParams);

            // Format the time stamp of the message
            long timestamp = cursor.getLong(cursor.getColumnIndex(ChatHistoryManager.C_TIME));
            TextView textTime = (TextView) row.findViewById(R.id.textTime);
            String readableTimeStamp = (String) DateUtils.getRelativeTimeSpanString(timestamp);
            textTime.setText(readableTimeStamp.trim());
            textTime.setLayoutParams(timeParams);

            // Format the message owner and the message
            TextView textUser = (TextView) row.findViewById(R.id.textUser);
            textUser.setText(incomingMessageUserName + ": ");
            textUser.setLayoutParams(userNameParams);
            row.setBackgroundResource(R.drawable.incoming_chat_bubble);
        }
        else {
            RelativeLayout.LayoutParams userNameAndChatMessageParams = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.WRAP_CONTENT, RelativeLayout.LayoutParams.WRAP_CONTENT);
            userNameAndChatMessageParams.addRule(RelativeLayout.RIGHT_OF, R.id.userImage);

            RelativeLayout.LayoutParams userImageParams = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.WRAP_CONTENT, RelativeLayout.LayoutParams.WRAP_CONTENT);
            userImageParams.addRule(RelativeLayout.ALIGN_PARENT_LEFT, RelativeLayout.TRUE);

            RelativeLayout.LayoutParams userNameParams = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.WRAP_CONTENT, RelativeLayout.LayoutParams.WRAP_CONTENT);
            userNameParams.addRule(RelativeLayout.ALIGN_LEFT, R.id.userAndMessage);

            RelativeLayout.LayoutParams chatMessageParams = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.WRAP_CONTENT, RelativeLayout.LayoutParams.WRAP_CONTENT);
            chatMessageParams.addRule(RelativeLayout.RIGHT_OF, R.id.textUser);

            RelativeLayout.LayoutParams timeParams = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.WRAP_CONTENT, RelativeLayout.LayoutParams.WRAP_CONTENT);
            timeParams.addRule(RelativeLayout.ALIGN_LEFT, R.id.userAndMessage);
            timeParams.addRule(RelativeLayout.BELOW, R.id.userAndMessage);

            // Set the chat message
            String chatMessage = cursor.getString(cursor.getColumnIndex(ChatHistoryManager.C_TEXT));
            TextView textMessage = (TextView) row.findViewById(R.id.textMessage);
            textMessage.setText(chatMessage);
            textMessage.setLayoutParams(chatMessageParams);

            // Format the time stamp of the message
            long timestamp = cursor.getLong(cursor.getColumnIndex(ChatHistoryManager.C_TIME));
            TextView textTime = (TextView) row.findViewById(R.id.textTime);
            textTime.setText(DateUtils.getRelativeTimeSpanString(timestamp));
            textTime.setLayoutParams(timeParams);

            // Format the message owner and the message
            TextView textUser = (TextView) row.findViewById(R.id.textUser);
            textUser.setText(selfUserName + ": ");
            textUser.setLayoutParams(userNameParams);
            row.setBackgroundResource(R.drawable.outgoing_chat_bubble);
        }
    }

    public void setIncomingMessageUserName(String inputUserName) {
        this.incomingMessageUserName = inputUserName;
    }

    public void setSelfUserName(String inputUserName) {
        this.selfUserName = inputUserName;
    }
}

最佳答案

使用 LinearLayout 而不是 Relative 布局。它会解决你的问题。我有同样的问题。我使用 LinearLayout 解决了它

关于Android在ListView中实现聊天气泡,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8704436/

有关Android在ListView中实现聊天气泡的更多相关文章

  1. ruby - 在 Ruby 中实现 `call_user_func_array` - 2

    我怎样才能完成http://php.net/manual/en/function.call-user-func-array.php在ruby中?所以我可以这样做:classAppdeffoo(a,b)putsa+benddefbarargs=[1,2]App.send(:foo,args)#doesn'tworkApp.send(:foo,args[0],args[1])#doeswork,butdoesnotscaleendend 最佳答案 尝试分解数组App.send(:foo,*args)

  2. ruby-on-rails - 如何在 Ruby on Rails 中实现无向图? - 2

    我需要在RubyonRails中实现无向图G=(V,E)并考虑构建一个Vertex和一个Edge模型,其中Vertex有_多条边。由于边恰好连接两个顶点,您将如何在Rails中执行此操作?您是否知道任何有助于实现此类图表的gem或库(对重新发明轮子不感兴趣;-))? 最佳答案 不知道有任何现有库在ActiveRecord之上提供图形逻辑。您可能必须实现自己的Vertex、EdgeActiveRecord支持的模型(请参阅Rails安装的rails/activerecord中的vertex.rb和edge.rb/test/fixtur

  3. ruby-on-rails - 如何在 Ruby on Rails 中实现由 JSF 2.0 (Primefaces) 驱动的 UI 魔法 - 2

    按照目前的情况,这个问题不适合我们的问答形式。我们希望答案得到事实、引用或专业知识的支持,但这个问题可能会引发辩论、争论、投票或扩展讨论。如果您觉得这个问题可以改进并可能重新打开,visitthehelpcenter指导。关闭10年前。问题1)我想知道ruby​​onrails是否有功能类似于primefaces的gem。我问的原因是如果您使用primefaces(http://www.primefaces.org/showcase-labs/ui/home.jsf),开发人员无需担心javascript或jquery的东西。据我所知,JSF是一个规范,基于规范的各种可用实现,prim

  4. 安卓apk修改(Android反编译apk) - 2

    最近因为项目需要,需要将Android手机系统自带的某个系统软件反编译并更改里面某个资源,并重新打包,签名生成新的自定义的apk,下面我来介绍一下我的实现过程。APK修改,分为以下几步:反编译解包,修改,重打包,修改签名等步骤。安卓apk修改准备工作1.系统配置好JavaJDK环境变量2.需要root权限的手机(针对系统自带apk,其他软件免root)3.Auto-Sign签名工具4.apktool工具安卓apk修改开始反编译本文拿Android系统里面的Settings.apk做demo,具体如何将apk获取出来在此就不过多介绍了,直接进入主题:按键win+R输入cmd,打开命令窗口,并将路

  5. ruby - 在 Ruby 中实现 to_int 和 to_str 的后果 - 2

    我haveaclass它公开了一个字符串值和一个int值(分别是命令输出和退出代码)。除了通过to_s和to_i公开它们之外,我还使用to_str和to_int,如下所示:classStatusdefto_s@outputendalias:to_str:to_sdefto_i@status.exitstatusendalias:to_int:to_iend我的想法是能够在尽可能多的情况下使用这个对象。将其强制转换为字符串或整数会增加可用性。例如,我可以将对象与字符串连接起来:a_string="Outputwas:"+results(我想用这个作为int强制转换的例子,但是Fixnum

  6. ruby - 在 Ruby 中实现二叉树 - 2

    我一直在尝试在Ruby中实现BinaryTree类,但我得到了stackleveltoodeep错误,尽管我似乎没有在该特定代码段中使用任何递归:1.classBinaryTree2.includeEnumerable3.4.attr_accessor:value5.6.definitialize(value=nil)7.@value=value8.@left=BinaryTree.new#stackleveltoodeephere9.@right=BinaryTree.new#andhere10.end11.12.defempty?13.(self.value==nil)?true:

  7. ruby - 如何在 Ruby 中实现私有(private)内部类 - 2

    来自Java,我正在尝试在Ruby中实现LinkedList。我在Java中实现它的通常方法是有一个名为LinkedList的类和一个名为Node的私有(private)内部类,其中LinkedList的每个对象都作为Node对象。classLinkedListprivateclassNodeattr_accessor:val,:nextendend我不想将Node类暴露给外部世界。然而,通过Ruby中的这个设置,我可以使用这个访问LinkedList类之外的私有(private)Node类对象-node=LinkedList::Node.new我知道,在Ruby1.9中,我们可以使用

  8. (附源码)vue3.0+.NET6实现聊天室(实时聊天SignalR) - 2

    参考文章搭建文章gitte源码在线体验可以注册两个号来测试演示图:一.整体介绍  介绍SignalR一种通讯模型Hub(中心模型,或者叫集线器模型),调用这个模型写好的方法,去发送消息。  内容有:    ①:Hub模型的方法介绍    ②:服务器端代码介绍    ③:前端vue3安装并调用后端方法    ④:聊天室样例整体流程:1、进入网站->调用连接SignalR的方法2、与好友发送消息->调用SignalR的自定义方法 前端通过,signalR内置方法.invoke()  去请求接口3、监听接受方法(渲染消息)通过new signalR.HubConnectionBuilder().on

  9. 智能客服 | 浅谈人工智能聊天机器人ChatGPT - 2

    2022年底,OpenAI的预训练模型ChatGPT给人工智能领域的爱好者和研究人员留下了深刻的印象和启发,他展现的惊人能力将人工智能的研究和应用热度推向高潮,网上也充斥着和ChatGPT的各种聊天,他可以作诗、写小说、写代码、讨论疫情问题等。下面就是一些他的神回复:人命关天的坑: 写歌,留给词作者的机会不多了。。。 回答人类怎么样面对人工智能: 什么是ChatGPT?借用网上的一段介绍,ChatGPT是由人工智能研究实验室OpenAI在2022年11月30日发布的全新聊天机器人模型,一款人工智能技术驱动的自然语言处理工具。它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动

  10. ruby - 在 Ruby 中实现 Luhn 算法 - 2

    我一直在尝试用Ruby实现Luhn算法。我一直在执行以下步骤:该公式根据其包含的校验位验证数字,该校验位通常附加到部分帐号以生成完整帐号。此帐号必须通过以下测试:从最右边的校验位开始向左移动,每第二个数字的值加倍。将乘积的数字(例如,10=1+0=1、14=1+4=5)与原始数字的未加倍数字相加。如果总模10等于0(如果总和以零结尾),则根据Luhn公式该数字有效;否则无效。http://en.wikipedia.org/wiki/Luhn_algorithm这是我想出的:defvalidCreditCard(cardNumber)sum=0nums=cardNumber.to_s.s

随机推荐