Creating a custom sticker app

The standard sticker app that you created earlier using the sticker pack template is very plain. The generated iMessage app shows stickers on a white background and that's about it. Sticker apps shouldn't be more complex than this, but wouldn't it be great if you could at least change the background color for a sticker app? This isn't possible if you're using the simple sticker pack template. You can, however, create your own sticker pack app and customize the background. Doing this will allow you to familiarize yourself with the code that's involved in creating an iMessage app, so let's create a custom sticker pack.

In the source code repository for this book, you'll find a project named CustomStickers. This project already contains the stickers that will be used in the sample app. The images for these stickers are made available through openclipart.org by a user named bocian. Note that the images have not been added to the Assets.xcassets folder, but to the Stickers folder in MessagesExtension. The project was set up like this since the Assets.xcassets folder belongs to the containing app, which will be ignored.

In the MessagesExtension folder, you'll find a view controller file and a storyboard file. Open the storyboard and remove the default UILabel that was placed in the interface. You won't be adding any interface elements through Interface Builder because the interface elements to create a sticker app aren't directly available in Interface Builder.

You will find several boilerplate methods in the MessagesViewController class. We'll get into them soon; you can ignore them for now. The viewDidLoad method will be used to set up MSStickerBrowserViewController to display stickers in.

The MSStickerBrowserView instance that is contained inside MSStickerBrowserViewController behaves somewhat like UICollectionView because it requires a data source to determine how many, and which, stickers to display.

The first step in implementing your own sticker app is to add a property for an instance of MSStickerBrowserViewController to MessagesViewController:

var stickerBrowser = MSStickerBrowserViewController(stickerSize: .regular)

Next, add the following implementation for viewDidLoad:

override func viewDidLoad() {
  super.viewDidLoad()
  stickerBrowser.willMove(toParent: self)
  addChild(stickerBrowser)
  stickerBrowser.didMove(toParent: self)

  view.addSubview(stickerBrowser.view)
  stickerBrowser.stickerBrowserView.dataSource = self
  stickerBrowser.stickerBrowserView.reloadData()
  stickerBrowser.stickerBrowserView.backgroundColor = UIColor.red
}

The preceding snippet should not contain any surprises for you. First, stickerBrowser is added as a child view controller of the messages view controller. Then the stickerBrowser view is added as a subview of the messages view controller's view. Next, the dataSource is set on stickerBrowserView and it is told to reload its data. Lastly, the background color for stickerBrowserView is set.

If you build your app now, Xcode will complain about MessagesViewController not conforming to MSStickerBrowserViewDataSource. Add the following extension to MessagesViewController.swift to make MessagesViewController conform to MSStickerBrowserViewDataSource:

extension MessagesViewController: MSStickerBrowserViewDataSource {
  func stickerBrowserView(_ stickerBrowserView: MSStickerBrowserView, stickerAt index: Int) →; MSSticker {
    return OwlStickerFactory.sticker(forIndex: index)
  }

  func numberOfStickers(in stickerBrowserView: MSStickerBrowserView) → Int {
    return OwlStickerFactory.numberOfStickers
  }
}

The first method is expected to return a sticker for a certain index and the second returns the number of stickers in the app. The logic for this is abstracted into a sticker factory. This is done to keep the code in the view controller nice, compact, and to the point. Add a new Swift file to the project and name it OwlStickerFactory.

Add the following implementation to this file:

import Foundation
import Messages

struct OwlStickerFactory {
  static private let stickerNames = [
    "bike", "books", "bowler", "drunk", "ebook",
    "family", "grill", "normal", "notebook", "party",
    "punk", "rose", "santa", "spring"
  ]

  static var numberOfStickers: Int { return stickerNames.count }

  static func sticker(forIndex index: Int) → MSSticker {
    let stickerName = stickerNames[index]

    guard let stickerPath = Bundle.main.path(forResource: stickerName, ofType: "png")
      else { fatalError("Missing sicker with name: (stickerName)") }
    let stickerUrl = URL(fileURLWithPath: stickerPath)

    guard let sticker = try? MSSticker(contentsOfFileURL: stickerUrl, localizedDescription: "(stickerName) owl")
      else { fatalError("Failed to retrieve sticker: (stickerName)") }

    return sticker
  }
}

Most of the preceding code should speak for itself. There is an array of sticker names and a computed variable that returns the number of stickers for the app. The interesting part of this code is the sticker(forIndex:) method. This method retrieves a sticker name from our array of names. Then it retrieves the file path that can be used to retrieve the image file from the application bundle. Finally, it creates a URL with this path to create a sticker.

Note that the MSSticker initializer can throw errors so the initialization call is prefixed with try?. Also, note that the sticker initializer takes localizedDescription. This description is used by screen readers to read out a description of the sticker to users that have certain accessibility features enabled.

When you run your extension now, you should see an interface that looks very similar to the following screenshot:

You can drag stickers from the sticker browser to the messages view. Notice that the stickers are picked and placed with a nice peel animation. Whenever you add an MSSticker to the messages view, regardless of whether you use a sticker browser, the Messages framework takes care of the sticker peel, drag, and drop animations for you. This means that you can create a custom interface for your stickers if you'd like.

Keep in mind that most sticker apps will make use of the standard layout and your users might not be too pleased if your app presents them with an unexpected sticker sheet layout. However, apps that aren't about stickers do require a special layer of design and interaction. This is the next topic covered in this chapter.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset