dxalxmur.com

Creating a Chat Interface with SwiftUI: A Comprehensive Guide

Written on

Chapter 1: Introduction to Messaging in Apps

Messaging is a vital component present in nearly every mobile application today. In this guide, I'll walk you through the process of creating a basic chat interface with SwiftUI.

To start, you'll need to create a new iOS app project in Xcode, ensuring that you select SwiftUI as your interface option. We'll begin by adding a file to establish a Message model, which will represent individual chat messages and hold relevant information for user display. Your Message file will look something like this:

You might have noticed the inclusion of the Role enum. This enum is crucial, as it allows us to differentiate how messages are displayed based on whether they are sent or received.

Section 1.1: Developing the View Model

Having defined our model, the next step is to create a straightforward view model that will control the user interface's appearance. Let’s introduce a new class named ChatViewModel. This class will contain properties such as the message currently being typed by the user (draftMessage) and an array of all messages in the chat (messages). Additionally, we will implement a method to send messages, which will update the message list accordingly. Your ChatViewModel class might resemble this:

It's important to note that our view model is annotated with @Observable, which enables the UI to react to changes in the view model and update dynamically. This feature was introduced in iOS 17 to replace the ObservableObject protocol. I also included some example messages (using our Message model), but feel free to customize these as you wish.

Subsection 1.1.1: Crafting the UI Components

Now that our view model is set up, let's move on to the exciting part: building the user interface!

We’ll start by creating a reusable cell to present each message in the chat. Add a new SwiftUI View file named MessageCell. Before we define the view, we'll establish a few extensions for the Role enum to streamline UI customization based on a message's role. These extensions will include four computed properties: bubbleColor, textColor, cornerRadii, and padding.

The MessageCell will consist of an HStack with a Spacer and a MessageBubble. Let's define the MessageBubble first, which will display text and feature rounded corners—except for one corner, which will be either the bottom left or bottom right, to indicate the message's role.

With the extensions we defined earlier, we can determine the bubble's corner radii and color.

Section 1.2: Message Interaction Components

Now, let's create the MessageCell. If the user sent the message, the bubble will be aligned to the right; otherwise, it will be aligned to the left, facilitated by the spacers.

Next, we will develop the text field for typing messages. Create a new SwiftUI view file and call it MessageTextField. This view will simply create a TextField that binds to a string representing the user's input.

Moving on, we’ll create a straightforward view for the button that sends messages. This view will accept an action and will use an SF Symbol to showcase a paper airplane icon.

To display all messages, we will employ a ForEach loop within a ScrollView. For each message in the view model's messages list, we will render a MessageCell. We will also configure the default scroll anchor to the bottom, ensuring that when the list of messages grows lengthy, the most recent message—located at the bottom—will be displayed first.

Chapter 2: Assembling the Chat View

Now that we've built various simple views, we will utilize them to create our primary view, ChatView. I have renamed the default ContentView file to ChatView. This view will be wrapped in a NavigationStack and will contain a VStack, positioning the chat list at the top and the text field and button at the bottom. Our ChatView will appear similar to this:

You can see that we pass a call to viewModel.sendMessage() as the button's action. Now, let’s run our app to see everything in action!

Improvements and Final Touches

Finally, we can implement a couple of enhancements to our chat interface. First, we will ensure that the send message button is disabled if the user hasn’t typed anything. This can be accomplished with a simple one-line modification using the disabled modifier within the SendMessageButton of our ChatView.

Second, we will ensure that the chat list scrolls to the bottom whenever a new message is added to the messages list. This requires assigning an id to each MessageCell and adjusting the scroll view's position to that id when a message is sent. This will involve adding a new scrollPosition property to our view model and updating it in sendMessage, then modifying our ChatMessageList by using the id modifier on each MessageCell and setting the scroll view's scrollPosition.

After making these adjustments, we can run our app once more to see the improvements in action.

That's a wrap for this tutorial! Thank you for reading. I hope you found it informative. You can access the final code for the Chat app on GitHub. If you're interested in furthering your knowledge in iOS app development, be sure to check out my YouTube channel for more insights and tutorials. Additionally, follow me on Medium for future tips and guides!

In this full course, learn how to create a SwiftUI chat application from scratch, covering all essential components and interactions.

This video demonstrates how to build a SwiftUI chat app using Firestore, guiding you through the entire process step-by-step.

Share the page:

Twitter Facebook Reddit LinkIn

-----------------------

Recent Post:

Intermittent Fasting: Understanding Its Effectiveness and Challenges

An exploration of intermittent fasting, its scientific backing, and the challenges of maintaining dietary changes over time.

Finding Balance: How Biking Helped Me Tackle My Addiction

Discover how learning to ride a bike mirrored my journey to manage addiction, emphasizing gradual change and mindful choices.

Exploring Our Fascination with Infinite Progress: A Deep Dive

This article examines our cultural obsession with the infinite, contrasting it with classical thought and discussing its implications.