SlideShare a Scribd company logo
1 of 37
Download to read offline
A short overview of different
types of iMessage Sticker
Apps
November, 2016
www.byteout.com
Three levels of customization
1. Simple Sticker App
○ Set sticker size
2. Customized Sticker App
○ Set background color/image
○ Add elements (views, links, texts) behind or on top of stickers
3. Totally Custom Sticker App
○ Different size of each sticker
○ Custom layouts
○ Interaction
○ Mix up stickers with other elements (links, buttons, views, ...)
www.byteout.com
1. Simple Sticker App
1. Create sticker app
2. Import assets
3. Set sticker size
1.1. Create Sticker Pack Application
1.2. Drag assets to Sticker Pack folder
1.3. Set sticker size
Preview of the app - small, medium and large sticker size
www.byteout.com
Helpful links
https://developer.apple.com/videos/play/tutorials/building-sticker-packs/
(Apple Tutorial)
http://www.appcoda.com/message-sticker-app/ (Simple Sticker App Tutorial)
www.byteout.com
2. More customized Sticker App
1. Create iMessage app
2. Subclass MSStickerBrowserViewController and
a. Load stickers
b. Implement numberOfStickers(in:) and stickerBrowserView(_:stickerAt:)
3. Make simple customizations
a. Change background color (Storyboard/code)
b. Add button/text/link on top of or behind the sticker browser view
4. Load MSStickerBrowserViewController into
MessageViewController
2.1. Create iMessage App
2.2. Subclassing MSStickerBrowserViewController (add new file into MessagesExtension folder)
2.2. Loading stickers and implementing required methods
var stickers = [MSSticker]()
func loadStickers() {
let names = ["heart", "romb", "club", "star", "square", "circle"]
for name in names {
if let url = Bundle.main.url(forResource: name, withExtension: "png") {
do {
let sticker = try MSSticker(contentsOfFileURL: url, localizedDescription: "")
stickers.append(sticker)
} catch {
print(error)
}
}
}
}
override func numberOfStickers(in stickerBrowserView: MSStickerBrowserView) -> Int {
return stickers.count
}
override func stickerBrowserView(_ stickerBrowserView: MSStickerBrowserView, stickerAt index: Int)
-> MSSticker {
return stickers[index]
}
2.5. Loading StickerBrowserViewController into MessagesViewController: step 1 - add Container View into
MessagesViewCtontroller and set up the constraints, background colors, etc.
2.5. Loading StickerBrowserViewController into MessagesViewController: step 2 - set the class of newly created View Controller to
be StickerBrowserViewController (name of your custom class)
Preview of the app - background color of container view was changed
www.byteout.com
Helpful links
https://github.com/jelenakrmar/purpleBackgroundStickers (Download sample
code)
https://developer.apple.com/reference/messages/msstickerbrowserviewcontr
oller (Apple Docs)
http://blog.lookfar.com/how-to-build-a-simple-imessages-app-in-ios-10
(Customized Sticker App Tutorial)
www.byteout.com
3. Totally custom Sticker App
1. Create iMessage app
2. Subclass UIViewController and add subviews
a. Views, buttons, labels, … (optional)
b. UICollectionView (required) and implement its dataSource methods:
i. numberOfSections(in:)
ii. collectionView(_:numberOfItemsInSection:)
iii. collectionView(_:cellForItemAt:)
3. Subclass UICollectionViewCell and add MSStickerView to it
(possible through Storyboard)
a. Load sticker into MSStickerView in collectionView(_:cellForItemAt:)
method
4. Load UIViewController into MessageViewController
3.1. Create iMessage App
3.2. Create custom UIViewController (in MessagesExtension folder)
3.2. Add UIViewController to Storyboard, set custom class and add subviews - one of them must be UICollectionView
3.2.a. Hold control key and drag from UICollectionView to UIViewController to connect dataSource and delegate
3.2.b. Implement dataSource methods (in MyCustomStickerViewController.swift)
// Number of sections in collection view
func numberOfSections(in collectionView: UICollectionView) -> Int {
return 1
}
// Number of items in section
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) ->
Int {
return stickers.count
}
private let reuseIdentifier = "StickerCell"
// Cell for item at index path
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) ->
UICollectionViewCell {
// Load reusable cell using its identifier;
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: reuseIdentifier, for:
indexPath)
return cell
}
3.3. Add a UIView to the prototype cell and set its class to MSStickerView
3.3. Subclass UICollectionViewCell and connect outlet to MSStickerView
3.3. Change collectionView(_:cellForItemAt:) function so it can load sticker in the cell (in MyCustomStickerViewController.swift)
// Array of stickers
var stickers = [MSSticker]()
// Cell for item at index path
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) ->
UICollectionViewCell {
// Load reusable cell using its identifier;
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: reuseIdentifier, for:
indexPath) as! StickerCell
// Set up cell with its sticker
cell.stickerView.sticker = stickers[indexPath.row]
return cell
}
3.3. Helper methods for loading stickers (MyCustomStickerViewController.swift)
// Create sticker
func createSticker(asset: String, localizedDescription: String) {
// Get path for asset
guard let stickerPath = Bundle.main.path(forResource: asset, ofType:"png") else {
print("couldn't create the sticker for asset ", asset)
return
}
// Create url from the path
let stickerUrl = URL(fileURLWithPath: stickerPath)
// Load asset into sticker and append the array of stickers with the new element
let sticker: MSSticker
do {
try sticker = MSSticker(contentsOfFileURL: stickerUrl,
localizedDescription:localizedDescription)
stickers.append(sticker)
}
catch {
print(error)
return
}
}
3.3. Helper methods for loading stickers (MyCustomStickerViewController.swift)
// Load all assets and create stickers from them
// This can be done in any way - through a loop, dictionary of names and localized descriptions,
etc.
func loadStickers() {
createSticker(asset: "heart", localizedDescription: NSLocalizedString("heart", comment: ""))
createSticker(asset: "romb", localizedDescription: NSLocalizedString("romb", comment: ""))
createSticker(asset: "club", localizedDescription: NSLocalizedString("club", comment: ""))
createSticker(asset: "square", localizedDescription: NSLocalizedString("square", comment:
""))
createSticker(asset: "star", localizedDescription: NSLocalizedString("star", comment: ""))
createSticker(asset: "circle", localizedDescription: NSLocalizedString("circle", comment:
""))
}
3.4. Load MyCustomStickerViewController in MessagesViewController.swift
private let StickersViewController = "StickersViewController"
override func viewDidLoad() {
super.viewDidLoad()
let _ = loadViewController(StickersViewController)
}
// Load a view controller with given identifier
func loadViewController(_ viewControllerIdentifier: String) -> Bool {
// Remove any existing child controllers.
childViewControllers.forEach {
$0.willMove(toParentViewController: nil)
$0.view.removeFromSuperview()
$0.removeFromParentViewController()
}
// Instantiate view controller from storyboard, using its identifier...
guard let vc = storyboard?.instantiateViewController(withIdentifier: viewControllerIdentifier)
else {return false}
vc.addTo(appViewController: self)
return true
}
3.4. UIViewController extension - for adding a view controller to any container
// Extension for UIViewController class - adds additional functions to a class
extension UIViewController {
// Load any view controller into Messages App
func addTo(appViewController host:MSMessagesAppViewController) {
// Add child view controller
willMove(toParentViewController: host)
host.addChildViewController(self)
// Set up the frame of child view controller
view.frame = host.view.bounds
view.translatesAutoresizingMaskIntoConstraints= false
host.view.addSubview(view)
/*!
@discussion The NSLayoutAnchor class is a factory class for creating NSLayoutConstraint objects using
a fluent API. Use these constraints to programatically define your layout using Auto Layout.
*/
view.leftAnchor.constraint(equalTo: host.view.leftAnchor).isActive = true
view.rightAnchor.constraint(equalTo: host.view.rightAnchor).isActive = true
view.bottomAnchor.constraint(equalTo: host.view.bottomAnchor).isActive = true
// We do not want our view controller to be covered with the contact name, that is why this one is different
view.topAnchor.constraint(equalTo: host.topLayoutGuide.bottomAnchor).isActive = true
didMove(toParentViewController: host)
}
}
www.byteout.com
3.a. Customize Collection View Layout
If you do not like the grid layout, you can create your own.
1. Subclass UICollectionViewLayout and override methods:
a. prepare()
b. collectionViewContentSize (getter function)
c. layoutAttributesForElements(in:)
2. Set UICollectionView to use this custom layout class
3.a. Subclass UICollectionViewLayout and assign it to UICollectionView
3.a. Implement layout methods: Calculate positions of every sticker in prepare() method. Cache layout attributes for performance.
(in StickerLayout.swift)
override func prepare() {
if cache.isEmpty {
for i in 0 ..< collectionView!.numberOfItems(inSection: 0) {
let indexPath = IndexPath(item: i, section: 0)
// Create new attributes for cell with index path
let attributes = UICollectionViewLayoutAttributes.init(forCellWith: indexPath)
// First row has two columns, second three, third two again...
if ((row % 2) == 0) {
col = 2
}
else {
col = 3
}
// Calculate sticker width based on number of columns
width = Int((Double(contentWidth) - Double((col + 1) * cellPadding)) / Double(col))
attributes.frame = CGRect(x:(colCounter * width + (colCounter + 1) * cellPadding), y:(row * height + (row +
1) * cellPadding), width:width, height:height)
cache.append(attributes)
colCounter += 1
// If we have filled a row, we proceed to another row
if (colCounter == col) {
row += 1
colCounter = 0
}
}
}
}
3.a. Implement layout methods: defined properties and collectionViewContentSize for defining scroll view content size (in
StickerLayout.swift)
private let cellPadding = 6 // Space between sticker cells
private let height = 100 // Height of a sticker - equal for all of them
private var row = 0 // Total number of rows
private var col = 2 // Number of columns in a row
private var colCounter = 0 // Current column
private var width = 1 // Sticker width
private var cache = [UICollectionViewLayoutAttributes ]() // Cached attributes
private var contentWidth: CGFloat {
// Returns width of the collection view
return collectionView !.bounds.width
}
// CollectionView content size
override var collectionViewContentSize: CGSize {
if (colCounter != 0) {
return CGSize(width: contentWidth , height: CGFloat((row + 1) * height + (row + 2) *
cellPadding ))
}
else {
// If the last row is completely full, variable row is already increased by one
return CGSize(width: contentWidth , height: CGFloat(row * height + (row + 1) * cellPadding ))
}
}
3.a. Implement layout methods (in StickerLayout.swift): layoutAttributesForElements(in:)
// Layout attributes for elements in rect - to return layout attributes for for supplementary or
decoration views, or to perform layout in an as-needed-on-screen fashion.
override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]?
{
var layoutAttributes = [UICollectionViewLayoutAttributes]()
// Get attributes from cache...
for attributes in cache {
if attributes.frame.intersects(rect) {
layoutAttributes.append(attributes)
}
}
// ... and return them
return layoutAttributes
}
Preview of the custom layout
www.byteout.com
Helpful links
https://github.com/jelenakrmar/customStickerApp (Download sample code)
https://developer.apple.com/videos/play/wwdc2016/204/ (WWDC Video)
https://developer.apple.com/reference/messages/msstickerview (Apple Docs)
https://developer.apple.com/reference/uikit/uicollectionviewlayout (Apple
Docs)
https://www.safaribooksonline.com/library/view/ios-10-swift/9781491966426
/ch01.html (Examples from Swift cookbook)
www.byteout.com
Helpful links
https://code.tutsplus.com/tutorials/create-an-imessage-app-in-ios-10--cms-26
870 (Sticker Apps - Tutorials)
https://www.raywenderlich.com/107439/uicollectionview-custom-layout-tutori
al-pinterest (Custom layouts Tutorial)
https://medium.com/lost-bananas/building-an-interactive-imessage-applicatio
n-for-ios-10-in-swift-7da4a18bdeed#.5nxx0shd5 (Interactive App Tutorial)

More Related Content

What's hot

View groups containers
View groups containersView groups containers
View groups containers
Mani Selvaraj
 
Londroid Android Home Screen Widgets
Londroid Android Home Screen WidgetsLondroid Android Home Screen Widgets
Londroid Android Home Screen Widgets
Richard Hyndman
 
android layouts
android layoutsandroid layouts
android layouts
Deepa Rani
 
How to create ui using droid draw
How to create ui using droid drawHow to create ui using droid draw
How to create ui using droid draw
info_zybotech
 

What's hot (20)

A comprehensive guide on developing responsive and common react filter component
A comprehensive guide on developing responsive and common react filter componentA comprehensive guide on developing responsive and common react filter component
A comprehensive guide on developing responsive and common react filter component
 
Lessons Learned: Migrating Tests to Selenium v2
Lessons Learned: Migrating Tests to Selenium v2Lessons Learned: Migrating Tests to Selenium v2
Lessons Learned: Migrating Tests to Selenium v2
 
U.S. News | National News
U.S. News | National NewsU.S. News | National News
U.S. News | National News
 
Documentation For Tab Setup
Documentation For Tab SetupDocumentation For Tab Setup
Documentation For Tab Setup
 
Android
AndroidAndroid
Android
 
Geb qa fest2017
Geb qa fest2017Geb qa fest2017
Geb qa fest2017
 
View groups containers
View groups containersView groups containers
View groups containers
 
Android UI
Android UIAndroid UI
Android UI
 
Advanced Android gReporter
Advanced Android gReporterAdvanced Android gReporter
Advanced Android gReporter
 
UITableView Pain Points
UITableView Pain PointsUITableView Pain Points
UITableView Pain Points
 
Londroid Android Home Screen Widgets
Londroid Android Home Screen WidgetsLondroid Android Home Screen Widgets
Londroid Android Home Screen Widgets
 
What Would You Do? With John Quinones
What Would You Do? With John QuinonesWhat Would You Do? With John Quinones
What Would You Do? With John Quinones
 
android layouts
android layoutsandroid layouts
android layouts
 
How to create ui using droid draw
How to create ui using droid drawHow to create ui using droid draw
How to create ui using droid draw
 
Politics News and U.S. Elections Coverage
Politics News and U.S. Elections CoveragePolitics News and U.S. Elections Coverage
Politics News and U.S. Elections Coverage
 
Chapter 10
Chapter 10Chapter 10
Chapter 10
 
Politics News and U.S. Elections Coverage
Politics News and U.S. Elections CoveragePolitics News and U.S. Elections Coverage
Politics News and U.S. Elections Coverage
 
Why NextCMS: Layout Editor
Why NextCMS: Layout EditorWhy NextCMS: Layout Editor
Why NextCMS: Layout Editor
 
Android 2
Android 2Android 2
Android 2
 
Abandoned carts
Abandoned cartsAbandoned carts
Abandoned carts
 

Similar to Different types of sticker apps

Android Development with Flash Builder Burrito
Android Development with Flash Builder BurritoAndroid Development with Flash Builder Burrito
Android Development with Flash Builder Burrito
Jeff Bollinger
 
Adding custom ui controls to your application (1)
Adding custom ui controls to your application (1)Adding custom ui controls to your application (1)
Adding custom ui controls to your application (1)
Oro Inc.
 

Similar to Different types of sticker apps (20)

Lecture 2 Styling and Layout in React Native.pptx
Lecture 2 Styling and Layout in React Native.pptxLecture 2 Styling and Layout in React Native.pptx
Lecture 2 Styling and Layout in React Native.pptx
 
Swift Tableview iOS App Development
Swift Tableview iOS App DevelopmentSwift Tableview iOS App Development
Swift Tableview iOS App Development
 
A Guide to Creating a Great Custom Tailwind Sidebar
A Guide to Creating a Great Custom Tailwind SidebarA Guide to Creating a Great Custom Tailwind Sidebar
A Guide to Creating a Great Custom Tailwind Sidebar
 
Building a dashboard using AngularJS
Building a dashboard using AngularJSBuilding a dashboard using AngularJS
Building a dashboard using AngularJS
 
Volley lab btc_bbit
Volley lab btc_bbitVolley lab btc_bbit
Volley lab btc_bbit
 
Ionic tabs template explained
Ionic tabs template explainedIonic tabs template explained
Ionic tabs template explained
 
UIAutomator
UIAutomatorUIAutomator
UIAutomator
 
Unlock the Power of Mui Breakpoints and Make Great Projects.pdf
Unlock the Power of Mui Breakpoints and Make Great Projects.pdfUnlock the Power of Mui Breakpoints and Make Great Projects.pdf
Unlock the Power of Mui Breakpoints and Make Great Projects.pdf
 
Android Development with Flash Builder Burrito
Android Development with Flash Builder BurritoAndroid Development with Flash Builder Burrito
Android Development with Flash Builder Burrito
 
Actionview
ActionviewActionview
Actionview
 
Knockoutjs databinding
Knockoutjs databindingKnockoutjs databinding
Knockoutjs databinding
 
Top Tips for Android UIs - Getting the Magic on Tablets
Top Tips for Android UIs - Getting the Magic on TabletsTop Tips for Android UIs - Getting the Magic on Tablets
Top Tips for Android UIs - Getting the Magic on Tablets
 
Beginning Native Android Apps
Beginning Native Android AppsBeginning Native Android Apps
Beginning Native Android Apps
 
iOS Development (Part 3) - Additional GUI Components
iOS Development (Part 3) - Additional GUI ComponentsiOS Development (Part 3) - Additional GUI Components
iOS Development (Part 3) - Additional GUI Components
 
Adding custom ui controls to your application (1)
Adding custom ui controls to your application (1)Adding custom ui controls to your application (1)
Adding custom ui controls to your application (1)
 
Backbone.js
Backbone.jsBackbone.js
Backbone.js
 
Custom PrimeFaces components
Custom PrimeFaces componentsCustom PrimeFaces components
Custom PrimeFaces components
 
Aspnet mvc tutorial_01_cs
Aspnet mvc tutorial_01_csAspnet mvc tutorial_01_cs
Aspnet mvc tutorial_01_cs
 
11 asp.net session16
11 asp.net session1611 asp.net session16
11 asp.net session16
 
Eclipse Tricks
Eclipse TricksEclipse Tricks
Eclipse Tricks
 

Recently uploaded

Love witchcraft +27768521739 Binding love spell in Sandy Springs, GA |psychic...
Love witchcraft +27768521739 Binding love spell in Sandy Springs, GA |psychic...Love witchcraft +27768521739 Binding love spell in Sandy Springs, GA |psychic...
Love witchcraft +27768521739 Binding love spell in Sandy Springs, GA |psychic...
chiefasafspells
 
Large-scale Logging Made Easy: Meetup at Deutsche Bank 2024
Large-scale Logging Made Easy: Meetup at Deutsche Bank 2024Large-scale Logging Made Easy: Meetup at Deutsche Bank 2024
Large-scale Logging Made Easy: Meetup at Deutsche Bank 2024
VictoriaMetrics
 
%+27788225528 love spells in Knoxville Psychic Readings, Attraction spells,Br...
%+27788225528 love spells in Knoxville Psychic Readings, Attraction spells,Br...%+27788225528 love spells in Knoxville Psychic Readings, Attraction spells,Br...
%+27788225528 love spells in Knoxville Psychic Readings, Attraction spells,Br...
masabamasaba
 
%+27788225528 love spells in Toronto Psychic Readings, Attraction spells,Brin...
%+27788225528 love spells in Toronto Psychic Readings, Attraction spells,Brin...%+27788225528 love spells in Toronto Psychic Readings, Attraction spells,Brin...
%+27788225528 love spells in Toronto Psychic Readings, Attraction spells,Brin...
masabamasaba
 
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
Health
 

Recently uploaded (20)

WSO2CON 2024 - Freedom First—Unleashing Developer Potential with Open Source
WSO2CON 2024 - Freedom First—Unleashing Developer Potential with Open SourceWSO2CON 2024 - Freedom First—Unleashing Developer Potential with Open Source
WSO2CON 2024 - Freedom First—Unleashing Developer Potential with Open Source
 
Crypto Cloud Review - How To Earn Up To $500 Per DAY Of Bitcoin 100% On AutoP...
Crypto Cloud Review - How To Earn Up To $500 Per DAY Of Bitcoin 100% On AutoP...Crypto Cloud Review - How To Earn Up To $500 Per DAY Of Bitcoin 100% On AutoP...
Crypto Cloud Review - How To Earn Up To $500 Per DAY Of Bitcoin 100% On AutoP...
 
What Goes Wrong with Language Definitions and How to Improve the Situation
What Goes Wrong with Language Definitions and How to Improve the SituationWhat Goes Wrong with Language Definitions and How to Improve the Situation
What Goes Wrong with Language Definitions and How to Improve the Situation
 
Love witchcraft +27768521739 Binding love spell in Sandy Springs, GA |psychic...
Love witchcraft +27768521739 Binding love spell in Sandy Springs, GA |psychic...Love witchcraft +27768521739 Binding love spell in Sandy Springs, GA |psychic...
Love witchcraft +27768521739 Binding love spell in Sandy Springs, GA |psychic...
 
Large-scale Logging Made Easy: Meetup at Deutsche Bank 2024
Large-scale Logging Made Easy: Meetup at Deutsche Bank 2024Large-scale Logging Made Easy: Meetup at Deutsche Bank 2024
Large-scale Logging Made Easy: Meetup at Deutsche Bank 2024
 
%+27788225528 love spells in Knoxville Psychic Readings, Attraction spells,Br...
%+27788225528 love spells in Knoxville Psychic Readings, Attraction spells,Br...%+27788225528 love spells in Knoxville Psychic Readings, Attraction spells,Br...
%+27788225528 love spells in Knoxville Psychic Readings, Attraction spells,Br...
 
WSO2Con2024 - From Code To Cloud: Fast Track Your Cloud Native Journey with C...
WSO2Con2024 - From Code To Cloud: Fast Track Your Cloud Native Journey with C...WSO2Con2024 - From Code To Cloud: Fast Track Your Cloud Native Journey with C...
WSO2Con2024 - From Code To Cloud: Fast Track Your Cloud Native Journey with C...
 
%+27788225528 love spells in Toronto Psychic Readings, Attraction spells,Brin...
%+27788225528 love spells in Toronto Psychic Readings, Attraction spells,Brin...%+27788225528 love spells in Toronto Psychic Readings, Attraction spells,Brin...
%+27788225528 love spells in Toronto Psychic Readings, Attraction spells,Brin...
 
Devoxx UK 2024 - Going serverless with Quarkus, GraalVM native images and AWS...
Devoxx UK 2024 - Going serverless with Quarkus, GraalVM native images and AWS...Devoxx UK 2024 - Going serverless with Quarkus, GraalVM native images and AWS...
Devoxx UK 2024 - Going serverless with Quarkus, GraalVM native images and AWS...
 
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
 
WSO2CON 2024 - Navigating API Complexity: REST, GraphQL, gRPC, Websocket, Web...
WSO2CON 2024 - Navigating API Complexity: REST, GraphQL, gRPC, Websocket, Web...WSO2CON 2024 - Navigating API Complexity: REST, GraphQL, gRPC, Websocket, Web...
WSO2CON 2024 - Navigating API Complexity: REST, GraphQL, gRPC, Websocket, Web...
 
Architecture decision records - How not to get lost in the past
Architecture decision records - How not to get lost in the pastArchitecture decision records - How not to get lost in the past
Architecture decision records - How not to get lost in the past
 
%in tembisa+277-882-255-28 abortion pills for sale in tembisa
%in tembisa+277-882-255-28 abortion pills for sale in tembisa%in tembisa+277-882-255-28 abortion pills for sale in tembisa
%in tembisa+277-882-255-28 abortion pills for sale in tembisa
 
Artyushina_Guest lecture_YorkU CS May 2024.pptx
Artyushina_Guest lecture_YorkU CS May 2024.pptxArtyushina_Guest lecture_YorkU CS May 2024.pptx
Artyushina_Guest lecture_YorkU CS May 2024.pptx
 
Announcing Codolex 2.0 from GDK Software
Announcing Codolex 2.0 from GDK SoftwareAnnouncing Codolex 2.0 from GDK Software
Announcing Codolex 2.0 from GDK Software
 
OpenChain - The Ramifications of ISO/IEC 5230 and ISO/IEC 18974 for Legal Pro...
OpenChain - The Ramifications of ISO/IEC 5230 and ISO/IEC 18974 for Legal Pro...OpenChain - The Ramifications of ISO/IEC 5230 and ISO/IEC 18974 for Legal Pro...
OpenChain - The Ramifications of ISO/IEC 5230 and ISO/IEC 18974 for Legal Pro...
 
WSO2Con2024 - WSO2's IAM Vision: Identity-Led Digital Transformation
WSO2Con2024 - WSO2's IAM Vision: Identity-Led Digital TransformationWSO2Con2024 - WSO2's IAM Vision: Identity-Led Digital Transformation
WSO2Con2024 - WSO2's IAM Vision: Identity-Led Digital Transformation
 
tonesoftg
tonesoftgtonesoftg
tonesoftg
 
AI & Machine Learning Presentation Template
AI & Machine Learning Presentation TemplateAI & Machine Learning Presentation Template
AI & Machine Learning Presentation Template
 
WSO2CON 2024 - How to Run a Security Program
WSO2CON 2024 - How to Run a Security ProgramWSO2CON 2024 - How to Run a Security Program
WSO2CON 2024 - How to Run a Security Program
 

Different types of sticker apps

  • 1. A short overview of different types of iMessage Sticker Apps November, 2016
  • 2. www.byteout.com Three levels of customization 1. Simple Sticker App ○ Set sticker size 2. Customized Sticker App ○ Set background color/image ○ Add elements (views, links, texts) behind or on top of stickers 3. Totally Custom Sticker App ○ Different size of each sticker ○ Custom layouts ○ Interaction ○ Mix up stickers with other elements (links, buttons, views, ...)
  • 3. www.byteout.com 1. Simple Sticker App 1. Create sticker app 2. Import assets 3. Set sticker size
  • 4. 1.1. Create Sticker Pack Application
  • 5. 1.2. Drag assets to Sticker Pack folder
  • 7. Preview of the app - small, medium and large sticker size
  • 9. www.byteout.com 2. More customized Sticker App 1. Create iMessage app 2. Subclass MSStickerBrowserViewController and a. Load stickers b. Implement numberOfStickers(in:) and stickerBrowserView(_:stickerAt:) 3. Make simple customizations a. Change background color (Storyboard/code) b. Add button/text/link on top of or behind the sticker browser view 4. Load MSStickerBrowserViewController into MessageViewController
  • 11. 2.2. Subclassing MSStickerBrowserViewController (add new file into MessagesExtension folder)
  • 12. 2.2. Loading stickers and implementing required methods var stickers = [MSSticker]() func loadStickers() { let names = ["heart", "romb", "club", "star", "square", "circle"] for name in names { if let url = Bundle.main.url(forResource: name, withExtension: "png") { do { let sticker = try MSSticker(contentsOfFileURL: url, localizedDescription: "") stickers.append(sticker) } catch { print(error) } } } } override func numberOfStickers(in stickerBrowserView: MSStickerBrowserView) -> Int { return stickers.count } override func stickerBrowserView(_ stickerBrowserView: MSStickerBrowserView, stickerAt index: Int) -> MSSticker { return stickers[index] }
  • 13. 2.5. Loading StickerBrowserViewController into MessagesViewController: step 1 - add Container View into MessagesViewCtontroller and set up the constraints, background colors, etc.
  • 14. 2.5. Loading StickerBrowserViewController into MessagesViewController: step 2 - set the class of newly created View Controller to be StickerBrowserViewController (name of your custom class)
  • 15. Preview of the app - background color of container view was changed
  • 16. www.byteout.com Helpful links https://github.com/jelenakrmar/purpleBackgroundStickers (Download sample code) https://developer.apple.com/reference/messages/msstickerbrowserviewcontr oller (Apple Docs) http://blog.lookfar.com/how-to-build-a-simple-imessages-app-in-ios-10 (Customized Sticker App Tutorial)
  • 17. www.byteout.com 3. Totally custom Sticker App 1. Create iMessage app 2. Subclass UIViewController and add subviews a. Views, buttons, labels, … (optional) b. UICollectionView (required) and implement its dataSource methods: i. numberOfSections(in:) ii. collectionView(_:numberOfItemsInSection:) iii. collectionView(_:cellForItemAt:) 3. Subclass UICollectionViewCell and add MSStickerView to it (possible through Storyboard) a. Load sticker into MSStickerView in collectionView(_:cellForItemAt:) method 4. Load UIViewController into MessageViewController
  • 19. 3.2. Create custom UIViewController (in MessagesExtension folder)
  • 20. 3.2. Add UIViewController to Storyboard, set custom class and add subviews - one of them must be UICollectionView
  • 21. 3.2.a. Hold control key and drag from UICollectionView to UIViewController to connect dataSource and delegate
  • 22. 3.2.b. Implement dataSource methods (in MyCustomStickerViewController.swift) // Number of sections in collection view func numberOfSections(in collectionView: UICollectionView) -> Int { return 1 } // Number of items in section func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { return stickers.count } private let reuseIdentifier = "StickerCell" // Cell for item at index path func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { // Load reusable cell using its identifier; let cell = collectionView.dequeueReusableCell(withReuseIdentifier: reuseIdentifier, for: indexPath) return cell }
  • 23. 3.3. Add a UIView to the prototype cell and set its class to MSStickerView
  • 24. 3.3. Subclass UICollectionViewCell and connect outlet to MSStickerView
  • 25. 3.3. Change collectionView(_:cellForItemAt:) function so it can load sticker in the cell (in MyCustomStickerViewController.swift) // Array of stickers var stickers = [MSSticker]() // Cell for item at index path func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { // Load reusable cell using its identifier; let cell = collectionView.dequeueReusableCell(withReuseIdentifier: reuseIdentifier, for: indexPath) as! StickerCell // Set up cell with its sticker cell.stickerView.sticker = stickers[indexPath.row] return cell }
  • 26. 3.3. Helper methods for loading stickers (MyCustomStickerViewController.swift) // Create sticker func createSticker(asset: String, localizedDescription: String) { // Get path for asset guard let stickerPath = Bundle.main.path(forResource: asset, ofType:"png") else { print("couldn't create the sticker for asset ", asset) return } // Create url from the path let stickerUrl = URL(fileURLWithPath: stickerPath) // Load asset into sticker and append the array of stickers with the new element let sticker: MSSticker do { try sticker = MSSticker(contentsOfFileURL: stickerUrl, localizedDescription:localizedDescription) stickers.append(sticker) } catch { print(error) return } }
  • 27. 3.3. Helper methods for loading stickers (MyCustomStickerViewController.swift) // Load all assets and create stickers from them // This can be done in any way - through a loop, dictionary of names and localized descriptions, etc. func loadStickers() { createSticker(asset: "heart", localizedDescription: NSLocalizedString("heart", comment: "")) createSticker(asset: "romb", localizedDescription: NSLocalizedString("romb", comment: "")) createSticker(asset: "club", localizedDescription: NSLocalizedString("club", comment: "")) createSticker(asset: "square", localizedDescription: NSLocalizedString("square", comment: "")) createSticker(asset: "star", localizedDescription: NSLocalizedString("star", comment: "")) createSticker(asset: "circle", localizedDescription: NSLocalizedString("circle", comment: "")) }
  • 28. 3.4. Load MyCustomStickerViewController in MessagesViewController.swift private let StickersViewController = "StickersViewController" override func viewDidLoad() { super.viewDidLoad() let _ = loadViewController(StickersViewController) } // Load a view controller with given identifier func loadViewController(_ viewControllerIdentifier: String) -> Bool { // Remove any existing child controllers. childViewControllers.forEach { $0.willMove(toParentViewController: nil) $0.view.removeFromSuperview() $0.removeFromParentViewController() } // Instantiate view controller from storyboard, using its identifier... guard let vc = storyboard?.instantiateViewController(withIdentifier: viewControllerIdentifier) else {return false} vc.addTo(appViewController: self) return true }
  • 29. 3.4. UIViewController extension - for adding a view controller to any container // Extension for UIViewController class - adds additional functions to a class extension UIViewController { // Load any view controller into Messages App func addTo(appViewController host:MSMessagesAppViewController) { // Add child view controller willMove(toParentViewController: host) host.addChildViewController(self) // Set up the frame of child view controller view.frame = host.view.bounds view.translatesAutoresizingMaskIntoConstraints= false host.view.addSubview(view) /*! @discussion The NSLayoutAnchor class is a factory class for creating NSLayoutConstraint objects using a fluent API. Use these constraints to programatically define your layout using Auto Layout. */ view.leftAnchor.constraint(equalTo: host.view.leftAnchor).isActive = true view.rightAnchor.constraint(equalTo: host.view.rightAnchor).isActive = true view.bottomAnchor.constraint(equalTo: host.view.bottomAnchor).isActive = true // We do not want our view controller to be covered with the contact name, that is why this one is different view.topAnchor.constraint(equalTo: host.topLayoutGuide.bottomAnchor).isActive = true didMove(toParentViewController: host) } }
  • 30. www.byteout.com 3.a. Customize Collection View Layout If you do not like the grid layout, you can create your own. 1. Subclass UICollectionViewLayout and override methods: a. prepare() b. collectionViewContentSize (getter function) c. layoutAttributesForElements(in:) 2. Set UICollectionView to use this custom layout class
  • 31. 3.a. Subclass UICollectionViewLayout and assign it to UICollectionView
  • 32. 3.a. Implement layout methods: Calculate positions of every sticker in prepare() method. Cache layout attributes for performance. (in StickerLayout.swift) override func prepare() { if cache.isEmpty { for i in 0 ..< collectionView!.numberOfItems(inSection: 0) { let indexPath = IndexPath(item: i, section: 0) // Create new attributes for cell with index path let attributes = UICollectionViewLayoutAttributes.init(forCellWith: indexPath) // First row has two columns, second three, third two again... if ((row % 2) == 0) { col = 2 } else { col = 3 } // Calculate sticker width based on number of columns width = Int((Double(contentWidth) - Double((col + 1) * cellPadding)) / Double(col)) attributes.frame = CGRect(x:(colCounter * width + (colCounter + 1) * cellPadding), y:(row * height + (row + 1) * cellPadding), width:width, height:height) cache.append(attributes) colCounter += 1 // If we have filled a row, we proceed to another row if (colCounter == col) { row += 1 colCounter = 0 } } } }
  • 33. 3.a. Implement layout methods: defined properties and collectionViewContentSize for defining scroll view content size (in StickerLayout.swift) private let cellPadding = 6 // Space between sticker cells private let height = 100 // Height of a sticker - equal for all of them private var row = 0 // Total number of rows private var col = 2 // Number of columns in a row private var colCounter = 0 // Current column private var width = 1 // Sticker width private var cache = [UICollectionViewLayoutAttributes ]() // Cached attributes private var contentWidth: CGFloat { // Returns width of the collection view return collectionView !.bounds.width } // CollectionView content size override var collectionViewContentSize: CGSize { if (colCounter != 0) { return CGSize(width: contentWidth , height: CGFloat((row + 1) * height + (row + 2) * cellPadding )) } else { // If the last row is completely full, variable row is already increased by one return CGSize(width: contentWidth , height: CGFloat(row * height + (row + 1) * cellPadding )) } }
  • 34. 3.a. Implement layout methods (in StickerLayout.swift): layoutAttributesForElements(in:) // Layout attributes for elements in rect - to return layout attributes for for supplementary or decoration views, or to perform layout in an as-needed-on-screen fashion. override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? { var layoutAttributes = [UICollectionViewLayoutAttributes]() // Get attributes from cache... for attributes in cache { if attributes.frame.intersects(rect) { layoutAttributes.append(attributes) } } // ... and return them return layoutAttributes }
  • 35. Preview of the custom layout
  • 36. www.byteout.com Helpful links https://github.com/jelenakrmar/customStickerApp (Download sample code) https://developer.apple.com/videos/play/wwdc2016/204/ (WWDC Video) https://developer.apple.com/reference/messages/msstickerview (Apple Docs) https://developer.apple.com/reference/uikit/uicollectionviewlayout (Apple Docs) https://www.safaribooksonline.com/library/view/ios-10-swift/9781491966426 /ch01.html (Examples from Swift cookbook)
  • 37. www.byteout.com Helpful links https://code.tutsplus.com/tutorials/create-an-imessage-app-in-ios-10--cms-26 870 (Sticker Apps - Tutorials) https://www.raywenderlich.com/107439/uicollectionview-custom-layout-tutori al-pinterest (Custom layouts Tutorial) https://medium.com/lost-bananas/building-an-interactive-imessage-applicatio n-for-ios-10-in-swift-7da4a18bdeed#.5nxx0shd5 (Interactive App Tutorial)