VNUHCM
Previous lesson Next lesson
  • Learning content
  • Help
    Do you have any questions while learning?
    Learning instructions Frequently asked questions Email for support
    • Tiếng Việt
    • English
    • Member's information
    • Registered courses
    • Log out
  • Cohota
  • HƯỚNG DẪN HỌC TẬP

  • View detail >>
    You have completed 0% of the course
  • HƯỚNG DẪN SINH VIÊN ĐĂNG NHẬP HỆ THỐNG
    • Hướng dẫn đăng nhập
    • Hướng dẫn vào khóa học
  • Introduction
    • Welcome
  • Unit 1: Values
    • Introduction - Unit 1: Values
    • Get Started With Values
    • Play with Values
    • Playground Basics
    • Naming and Identifiers
    • Simulation
    • Strings
    • Constants and Variables
    • Word Games
    • Build a PhotoFrame App
    • Design for People
  • Episode 1: The TV Club
    • Introduction - Episode 1: The TV Club
    • Searching for Content
    • Sharing Personal Information
    • Ordering Online
    • Reflection: Episode 1
  • Unit 2: Algorithms
    • Introduction - Unit 2: Algorithms
    • Get Started with Algorithms
    • Play with Programs
    • Functions
    • Types
    • Parameters and Results
    • Making Decisions
    • BoogieBot
    • Data Visualization
    • Build a QuestionBot App
    • Design an Experience
  • Episode 2: The Viewing Party
    • Introduction - Episode 2: The Viewing Party
    • Accessing the Show
    • Streaming on the Network
    • Reflection: Episode 2
  • Unit 3: Organizing Data
    • Introduction - Unit 3: Organizing Data
    • Get Started with Organizing Data
    • Play with Complex Data
    • Instances, Methods, and Properties
    • Arrays and Loops
    • Structures
    • Enums and Switch
    • Testing Code
    • Processing Data
    • Pixel Art
    • Password Security
    • Visualization Revisited
    • Build a BouncyBall App
    • Design a Prototype
  • Episode 3: Sharing Photos
    • Introduction - Episode 3: Sharing Photos
    • Capturing Images
    • Posting on Social Media
    • Reflection: Episode 3
  • Unit 4: Building Apps
    • Introduction - Unit 4: Building Apps
    • Get Started with App Development
    • Play with App Components
    • Color Picker
    • ChatBot
    • Rock, Paper, Scissors
    • MemeMaker
    • Build an ElementQuiz App
    • Design for Impact
  • Appendix
    • Episode Technical Concepts
    • Glossary
Course overview
Assessment

Progress
Criteria name Weighting (%) Score Progress (%)
Unit 4: Building Apps

MemeMaker

Unit 4: Building Apps|Play

Introduction

You’re going to build an app that lets you add fun captions to a photo. This is another opportunity to practice the Xcode and Swift skills you've learned throughout this course. The final app will look something like the image below.

Screenshot of complete meme maker project

Selecting any one of the emoji will change the text above and below its image, so you can mix and match statements to suit your mood.

Challenge Yourself

You’ll be using concepts and skills you’ve already learned to build this app. At the same time, you’ll get to know a new control—the segmented control. And you'll learn how to use a gesture recognizer to enable touch interactions.

You'll also be able to flex your creative muscles by making this project your own with custom text and images.

Part 1 - Planning

Before you dive into making the app, spend some time thinking about the content you’re going to use. The app will need the following:

  • An image to go in the center
  • Some text options to go above the image, and an emoji to represent each one
  • Some text options to go below the image, and an emoji to represent each one

Try to think of two, three, or four choices for the top and the bottom. It can be hard to think up working combinations of text. If you get stuck, here’s some inspiration:

Above the image

  • "You know what's cool?" could be represented by 🕶
  • "You know what makes me mad?" could be represented by 💥
  • "You know what I love?" could be represented by 💕

Below the image

  • "Cats wearing hats" could be represented by 🐱
  • "Llamas in pajamas" could be represented by 🦙
  • "Monkeys being funky" could be represented by 🐒

Once you have your ideas, you can get started building.

Part 2 - Building the UI

Create a new Xcode project using the App template. Name it “MemeMaker.”

Open the Main storyboard and select iPhone 14 Pro from the Devices icon at the bottom of the screen. Then add the following items, placing them from top to bottom:

  • A segmented control
  • A label
  • An image view
  • A label
  • A segmented control

Change the text of the top label to “TOP” and the bottom label to “BOTTOM.” You’ll be changing these in code later, but this step will help to make your storyboard clear.

Segmented Controls

Segmented controls are used to offer a choice between a limited number of options. For example, a calendar app might have a segmented control to switch between day, week and month views. Only one option can be selected at a time. You can control the number of segments and the title of each segment.

When the user taps one of the segments, the Value Changed control event is sent. From your code you can access the index of the selected segment. In this app you’ll update the caption labels when a different option is chosen.

For now, just leave the segmented controls as they are. You’re going to set them up using code rather than in Interface Builder.

Adding the Image

Just like you did in the PhotoFrame lesson, you need to add in an image to your project so that it can be displayed as part of the app.

Open the assets catalog and choose an image to drag in.

Select the image view and choose the Aspect Fit content mode in the Attributes inspector. (This is the same setting you used in the PhotoFrame lesson.)

With the image view still selected, go to the Size inspector and set the width and height to 350, or another size that fits the screen.

Finally, use the Attributes inspector to choose the image that you’ve added to the project. The image you’ve added to the Asset Catalog will be available in the Image pop-up menu.

Finishing the Layout

Make sure that all your elements are centered on the canvas by using the blue guides that appear as you drag them. Then take a look at your labels.

One classic meme style (dating from the "I can haz" days) uses white all-caps block letters on top of an image. Move the two labels so that they're over the top and bottom of the image. (If one or both disappear under the image view, you'll have to move them in the Document Outline. Both labels should be below the image view in the outline.) Use the Attributes inspector to adjust the following settings for each label.

  1. Set Alignment to Center.
  2. Set Lines to 0—so that the label isn't limited to a particular number of lines.
  3. Using the Font control, set Font to Custom, Family to Avenir Next Condensed, Style to Heavy, and Size to 30.
  4. Set Autoshrink to Minimum Font Size with a value of 15. (The label will wrap its text automatically to fit its width. If there's too much to fit at 30 points, it will reduce the font to as small as 15 points.)
  5. Set Color to White Color (near the bottom of the popup menu).
  6. Find the Shadow control and set it to Black Color, and set the Shadow Offset Width to 3 and its Height to 2.

Now that the labels are configured, resize them both so that they're as wide as the image and tall enough to fit two lines of text. That size should be a good default setting for the text that you'd want to use in most memes.

The final layout should look like this. 1

Layout of meme maker UI elements in interface builder

Making Connections

Make outlets for the segmented controls in ViewController. Name them topSegmentedControl and bottomSegmentedControl. Then do the same for the labels, naming their outlets topCaptionLabel and bottomCaptionLabel.

Create an action from one of the segmented controls, then connect the same action to the other segmented control.

Part 3 - Modeling Your Data

This app has one basic component that powers its behavior: the choice the user makes about the captions. Each choice is represented by an emoji (for the segmented control) and some words (for the label).

Defining a Custom Type

You’re going to define a struct called CaptionOption to represent each possible choice.

Add a new Swift file to the app to hold the model. Name it "CaptionOption."

Define a new struct in your new file with two properties: the emoji used to represent the caption and the caption itself. Name the struct CaptionOption.

Creating the Choices

Create two arrays inside the ViewController class, one to represent the top choices, and one to represent the bottom choices. Each array should contain CaptionOption instances matching the ideas you came up with at the start of this project. Name the arrays topChoices and bottomChoices.

Part 4 - Configuring the UI

In this part of the lesson, you'll configure the segmented controls and update the labels based on the options the user has selected. All of this will happen in ViewController.

Configuring the Segmented Controls

It makes sense to configure the segmented controls in code rather than via Interface Builder, because the details of the configuration will come from the CaptionOption instances you’ve defined. These aren’t available to you in Interface Builder.

The segments of a segmented control have an index, like the elements of an array. Also like an array, the index starts at zero.

You’re going to loop through each choices array and configure the segmented control while you do so. This configuration will happen in viewDidLoad(), which is called once the components from the storyboard have been set up in the running app.

First, remove all of the segments from the top control:

topCaptionSegmentedControl.removeAllSegments()

This step removes the two default segments that were given when you dragged the segmented control onto the storyboard.

You add segments using the insertSegment(withTitle:at:animated:) method of UISegmentedControl. This has three parameters: The first one is the String that will be the title, the second is the index where the segment will be inserted, and the last is a Bool to say if the insertion should be animated or not.

The title will be the emoji property of each CaptionOption.

The index can be the count of the topChoices array. (If you supply a number that's greater than the highest segment index, it just gets added to the end.)

The animated option will be false. (This is all happening before the user gets to see anything, so there is no point in animating it.)

Loop through the topChoices array and add the new segments in:

for choice in topChoices {
    topCaptionSegmentedControl.insertSegment(withTitle: choice.emoji,
                                     at: topChoices.count,
                                     animated: false)
}

Because you removed all of the segments, the control no longer has a selected segment. You can set this with the selectedSegmentIndex property:

topCaptionSegmentedControl.selectedSegmentIndex = 0

The top segmented control now matches the top choices array exactly.

Follow the same pattern to configure the bottom segmented control.

At this point, build and run the project to check that everything you’ve done so far is working. You should see the segmented controls set up with the emoji labels matching your choices.

Configuring the Caption Labels

You need a method to set the correct captions based on the selection from each segmented control. The index of the selected segment is available via the selectedSegmentIndex property. This index can then be used to obtain the correct CaptionOption from the topChoices or bottomChoices array.

Add a new method to the view controller. In it, use the selected index from each segmented control to get the correct CaptionOption, then set the text of the appropriate label.

Call this method from viewDidLoad() to set up the labels when the app is launched, and also from the action method linked to both segmented controls.

Build and Run

Build and run your app on the iPhone 14 Pro simulator. Have fun putting your captions together!

Part 5 - Positioning the Captions

Memes of this form don't always have text in the same fixed locations. In this part, you'll add touch interaction to the labels, allowing the user to position them exactly where they want.

Gesture Recognizers

There's a system of callbacks for directly processing individual touch events in iOS, but using it requires quite a bit of nuanced code. For common interactions, you can use gesture recognizers instead. They're built on top of the same touch processing system, but they provide an abstraction layer to present you with simple information about gestures such as tapping, swiping, and pinching.

For the MemeMaker app, you'll use a UIPanGestureRecognizer, which tracks the state of a gesture as the user drags their finger around the screen.

Open your storyboard. By default, views that aren't usually intended for user interaction, such as labels, are completely invisible to touch. Enable user interaction for both your labels by using the Attributes inspector. In the View section, look for Interaction and check the User Interaction Enabled box.

Adding the Recognizers

Now you'll add the gesture recognizers. Find a pan gesture recognizer in the Object library, and drag it to the top label. Make sure the label itself is highlighted when you drop the recognizer. (A gesture recognizer is associated with one view in the scene. If it's connected to the image view or to the top-level view for the whole screen, your app won't work properly.)

Gesture recognizers use a familiar system—IBActions—to communicate events to your code. You'll use the familiar drag-and-drop technique to create an action for the gesture recognizer. Make sure the assistant editor is showing, then follow these steps:

  1. Locate the Pan Gesture Recognizer in the Document Outline. (You can't drag from the scene, because there's nothing there to represent the gesture recognizer.) While you're there, rename it to "Top Caption Pan Gesture Recognizer" by clicking its name and waiting for the title to turn into editable text.
  2. Drag from the gesture recognizer 1 to the assistant editor, and drop near the bottom of the view controller's code to create a new action. 2
  3. In the popup, use these values:
    • Connection: Action
    • Object: View Controller
    • Name: dragTopLabel
    • Type: UIPanGestureRecognizer

Dragging from the Pan Gesture Recognizer in the document outline to the assistant editor to make an action

Repeat the process to add another pan gesture recognizer and another action for the bottom label.

Moving the Labels

Go back to your view controller to fill in the new action methods. Here's the code for the top label:

@IBAction func dragTopLabel(_ sender: UIPanGestureRecognizer) {
    if sender.state == .changed {
        topCaptionLabel.center = sender.location(in: view)
    }
}

Here's what the code does:

  • The method is called in a similar way to other actions, with the originating object passed in as an argument—in this case, the gesture recognizer.
  • You check the state of the recognizer. For pan gesture recognizers, the state can be began, changed, or ended (or possibly cancelled if something interrupts the user's gesture, such as an incoming phone call).
  • The changed state indicates that the user's touch is moving on the screen. If the user's touch is moving, you want to update the position of the label.
  • The location(in:) method of UIGestureRecognizer returns the x and y coordinates (in a CGPoint) of the touch that the recognizer is tracking. Passing view as the argument tells the method that you want the location relative to the top-level view of the scene—the one that contains the label.
  • You set the center property of the label to update its position.

Fill in the code for the dragBottomLabel(_:) method the same way.

Checkpoint

Build and run your app. You should be able to position the captions wherever you want.

Reflection Questions

What are the differences and similarities between segmented controls and the other controls you've worked with previously?

How would you design an update to the MemeMaker app to let users enter their own custom text?

Summary

Congratulations! This is the third app you’ve built completely from scratch using what you’ve learned in the course. In the next and final project—the ElementQuiz app—you'll put all your experience to work to build the most complex app yet. You'll find out just how far you've come since your PhotoFrame days.

Report error