You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

如何在Android Studio中设计WhatsApp风格聊天气泡?我需开发聊天应用

Hey there! I’ve built a couple of chat apps with WhatsApp-style bubbles before, so I can walk you through exactly how to implement this in Android Studio. Let’s break it down into simple, actionable steps.

Implement WhatsApp-Style Chat Bubbles in Android Studio

1. Define Bubble Shape Drawables

First, we need two custom shape drawables: one for messages you send, and one for messages you receive. These will replicate WhatsApp’s distinct rounded corners and color scheme.

Create res/drawable/chat_bubble_sent.xml (for your outgoing messages):

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="rectangle">
    <!-- WhatsApp's signature green for outgoing messages -->
    <solid android:color="#25D366" />
    <!-- Rounded corners: smaller on left, larger on right -->
    <corners
        android:topLeftRadius="16dp"
        android:topRightRadius="2dp"
        android:bottomLeftRadius="16dp"
        android:bottomRightRadius="16dp" />
    <!-- Padding between text and bubble edge -->
    <padding
        android:top="8dp"
        android:bottom="8dp"
        android:left="12dp"
        android:right="12dp" />
</shape>

Create res/drawable/chat_bubble_received.xml (for incoming messages):

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="rectangle">
    <!-- White background for incoming messages -->
    <solid android:color="#FFFFFF" />
    <!-- Rounded corners: smaller on right, larger on left -->
    <corners
        android:topLeftRadius="16dp"
        android:topRightRadius="16dp"
        android:bottomLeftRadius="2dp"
        android:bottomRightRadius="16dp" />
    <!-- Matching padding -->
    <padding
        android:top="8dp"
        android:bottom="8dp"
        android:left="12dp"
        android:right="12dp" />
    <!-- Light gray border to match WhatsApp's style -->
    <stroke
        android:width="1dp"
        android:color="#E5E5EA" />
</shape>

2. Build the Chat Item Layout

Next, create a layout for individual chat messages (we’ll use this with RecyclerView). Save it as res/layout/item_chat_message.xml:

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:padding="8dp">

    <!-- Outgoing message (right-aligned) -->
    <TextView
        android:id="@+id/tv_sent_message"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:maxWidth="280dp" <!-- Prevent overly wide bubbles -->
        android:textColor="#FFFFFF"
        android:textSize="14sp"
        android:background="@drawable/chat_bubble_sent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        android:visibility="gone" />

    <!-- Incoming message (left-aligned) -->
    <TextView
        android:id="@+id/tv_received_message"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:maxWidth="280dp"
        android:textColor="#000000"
        android:textSize="14sp"
        android:background="@drawable/chat_bubble_received"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        android:visibility="gone" />

    <!-- Timestamp for outgoing messages -->
    <TextView
        android:id="@+id/tv_sent_time"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textSize="12sp"
        android:textColor="#999999"
        android:layout_marginTop="4dp"
        app:layout_constraintTop_toBottomOf="@+id/tv_sent_message"
        app:layout_constraintEnd_toEndOf="@+id/tv_sent_message"
        android:visibility="gone" />

    <!-- Timestamp for incoming messages -->
    <TextView
        android:id="@+id/tv_received_time"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textSize="12sp"
        android:textColor="#999999"
        android:layout_marginTop="4dp"
        app:layout_constraintTop_toBottomOf="@+id/tv_received_message"
        app:layout_constraintStart_toStartOf="@+id/tv_received_message"
        android:visibility="gone" />

</androidx.constraintlayout.widget.ConstraintLayout>

3. Create the RecyclerView Adapter

We’ll use a RecyclerView to display the chat messages. First, define a data class to hold message details:

data class ChatMessage(
    val content: String,
    val isSentByMe: Boolean,
    val timestamp: String
)

Then build the adapter to toggle between outgoing and incoming message views:

class ChatAdapter(private val messages: List<ChatMessage>) :
    RecyclerView.Adapter<ChatAdapter.ChatViewHolder>() {

    inner class ChatViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
        val sentMessage: TextView = itemView.findViewById(R.id.tv_sent_message)
        val receivedMessage: TextView = itemView.findViewById(R.id.tv_received_message)
        val sentTime: TextView = itemView.findViewById(R.id.tv_sent_time)
        val receivedTime: TextView = itemView.findViewById(R.id.tv_received_time)
    }

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ChatViewHolder {
        val view = LayoutInflater.from(parent.context)
            .inflate(R.layout.item_chat_message, parent, false)
        return ChatViewHolder(view)
    }

    override fun onBindViewHolder(holder: ChatViewHolder, position: Int) {
        val message = messages[position]

        if (message.isSentByMe) {
            // Show outgoing message, hide incoming
            holder.sentMessage.visibility = View.VISIBLE
            holder.receivedMessage.visibility = View.GONE
            holder.sentTime.visibility = View.VISIBLE
            holder.receivedTime.visibility = View.GONE

            holder.sentMessage.text = message.content
            holder.sentTime.text = message.timestamp
        } else {
            // Show incoming message, hide outgoing
            holder.receivedMessage.visibility = View.VISIBLE
            holder.sentMessage.visibility = View.GONE
            holder.receivedTime.visibility = View.VISIBLE
            holder.sentTime.visibility = View.GONE

            holder.receivedMessage.text = message.content
            holder.receivedTime.text = message.timestamp
        }
    }

    override fun getItemCount() = messages.size
}

4. Set Up the Chat Activity

Finally, wire everything together in your chat activity:

class ChatActivity : AppCompatActivity() {
    private lateinit var recyclerView: RecyclerView
    private lateinit var adapter: ChatAdapter
    private val messageList = mutableListOf<ChatMessage>()

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_chat)

        recyclerView = findViewById(R.id.rv_chat)
        // Layout manager with stackFromEnd to show latest messages at bottom
        val layoutManager = LinearLayoutManager(this).apply {
            stackFromEnd = true
        }
        recyclerView.layoutManager = layoutManager

        // Add test messages
        messageList.apply {
            add(ChatMessage("Hey! How's it going?", false, "10:30 AM"))
            add(ChatMessage("Great! Just building WhatsApp-style bubbles 😊", true, "10:31 AM"))
            add(ChatMessage("Nice! Can you show me how?", false, "10:32 AM"))
            add(ChatMessage("Already did—check the code above!", true, "10:33 AM"))
        }

        adapter = ChatAdapter(messageList)
        recyclerView.adapter = adapter
    }
}

Quick Optimization Tips

  • Add long-click listeners to bubbles for copy/share functionality
  • Extend the item layout to support images or media messages
  • Adjust the maxWidth of the message TextViews to match your design preferences
  • Use DiffUtil in the adapter for smoother updates when new messages arrive

内容的提问来源于stack exchange,提问作者Sanjay

火山引擎 最新活动