<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Nguyen Truong Ky</title>
    <description>The latest articles on DEV Community by Nguyen Truong Ky (@nguyentruongky).</description>
    <link>https://dev.to/nguyentruongky</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F373064%2Fb65ab047-f825-4fca-b98a-277f764ecefd.jpeg</url>
      <title>DEV Community: Nguyen Truong Ky</title>
      <link>https://dev.to/nguyentruongky</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/nguyentruongky"/>
    <language>en</language>
    <item>
      <title>How to organize the project folders and files?</title>
      <dc:creator>Nguyen Truong Ky</dc:creator>
      <pubDate>Sat, 02 May 2020 00:54:34 +0000</pubDate>
      <link>https://dev.to/nguyentruongky/how-to-organize-the-project-folders-and-files-1772</link>
      <guid>https://dev.to/nguyentruongky/how-to-organize-the-project-folders-and-files-1772</guid>
      <description>&lt;p&gt;Project structure (folder structure) is a very basic thing and usually ignored, especially junior developers. &lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--aRHMLkOy--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://firebasestorage.googleapis.com/v0/b/blogs-1de93.appspot.com/o/assets%252Fproject_structure%252Funorder.png%3Falt%3Dmedia%26token%3D99fb4814-eaa2-45e5-8b43-9d94af62a9fa" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--aRHMLkOy--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://firebasestorage.googleapis.com/v0/b/blogs-1de93.appspot.com/o/assets%252Fproject_structure%252Funorder.png%3Falt%3Dmedia%26token%3D99fb4814-eaa2-45e5-8b43-9d94af62a9fa" width="40%"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Good structure can help you increase your efficiency. &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;What are the most common ways to oganize the project structure?&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;There is not correct answer here, depend on developers. &lt;/p&gt;
&lt;h1&gt;
  
  
  I. Structure
&lt;/h1&gt;

&lt;p&gt;Today, I will show you 2 common ways to arrange files in project which can help you access to files easier. &lt;/p&gt;
&lt;h2&gt;
  
  
  1. Group files by features
&lt;/h2&gt;

&lt;p&gt;Any projects have at least 2 features. Large projects have many features. This way has 2 advantages: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You can access to other related files in the same folder. Press &lt;code&gt;Ctrl + 5&lt;/code&gt; to quick access files in the same folder. &lt;/li&gt;
&lt;li&gt;You can copy folders to new projects and reuse it easily. This is the reason I love this way.
&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--qQFoBq88--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://firebasestorage.googleapis.com/v0/b/blogs-1de93.appspot.com/o/assets%252Fproject_structure%252Fgroup_by_features.png%3Falt%3Dmedia%26token%3Dc0372cb6-665c-4af4-9ae9-0b3e0a580b12" width="40%"&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;

&lt;p&gt;Where should I put the models, which are used in many features? &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;Common&lt;/code&gt; folder is an option. &lt;br&gt;
But I usually put it in the most related folder. For example: &lt;code&gt;Product&lt;/code&gt; model is in folder &lt;code&gt;Products&lt;/code&gt;, &lt;code&gt;User&lt;/code&gt; model is in folder &lt;code&gt;Membership&lt;/code&gt; or &lt;code&gt;Login&lt;/code&gt;. &lt;/p&gt;
&lt;/blockquote&gt;


&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  2. Group files by type
&lt;/h2&gt;

&lt;p&gt;You can make many folders of same purpose files like, &lt;code&gt;Models&lt;/code&gt;, &lt;code&gt;Controllers&lt;/code&gt;, &lt;code&gt;Views&lt;/code&gt;&lt;br&gt;
You have right folders for right types, don't have to confuse where to put files. &lt;br&gt;
This way is very easy for newcomers (junior developers), they can easily find the files they want. &lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--2mLsYgY2--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://firebasestorage.googleapis.com/v0/b/blogs-1de93.appspot.com/o/assets%252Fproject_structure%252Fgroup_by_types.png%3Falt%3Dmedia%26token%3Dc3435d46-26c2-410a-9993-a32939e0076d" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--2mLsYgY2--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://firebasestorage.googleapis.com/v0/b/blogs-1de93.appspot.com/o/assets%252Fproject_structure%252Fgroup_by_types.png%3Falt%3Dmedia%26token%3Dc3435d46-26c2-410a-9993-a32939e0076d" width="40%"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I don't use this way so I don't know more benefits of it. Anyone who is using it, please share me in comments. &lt;/p&gt;

&lt;h1&gt;
  
  
  II. Naming
&lt;/h1&gt;

&lt;p&gt;Naming is very important. Descriptive names help you easy to find and understand the mission of files. &lt;br&gt;
Some things you should know in naming. &lt;/p&gt;

&lt;h2&gt;
  
  
  1. Class name is file name
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;RegisterController&lt;/code&gt; should be written in &lt;code&gt;RegisterController.swift&lt;/code&gt;. You don't have to remember 2 names, just one for Register feature. Keep your mind free to remember other things. &lt;/p&gt;

&lt;h2&gt;
  
  
  2. Feature name is folder name and prefix of file names
&lt;/h2&gt;

&lt;p&gt;This is for &lt;code&gt;group by features&lt;/code&gt; way. &lt;code&gt;Register&lt;/code&gt; feature should have structure like below. &lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--WaqyEtAu--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://firebasestorage.googleapis.com/v0/b/blogs-1de93.appspot.com/o/assets%252Fproject_structure%252Ffolder_name.png%3Falt%3Dmedia%26token%3D029bb578-006d-4de6-b114-54674dea859d" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--WaqyEtAu--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://firebasestorage.googleapis.com/v0/b/blogs-1de93.appspot.com/o/assets%252Fproject_structure%252Ffolder_name.png%3Falt%3Dmedia%26token%3D029bb578-006d-4de6-b114-54674dea859d" width="40%"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The folder name can be &lt;code&gt;Register&lt;/code&gt; or &lt;code&gt;RegisterController&lt;/code&gt;, no problem. You can understand its functionality at first glance, right. &lt;/p&gt;

&lt;p&gt;If you're using &lt;code&gt;group by types&lt;/code&gt; way, you can name your files with prefix is feature name as above example. Benefits are below. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--7cshfwkz--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://firebasestorage.googleapis.com/v0/b/blogs-1de93.appspot.com/o/assets%252Fproject_structure%252Fquick_access.png%3Falt%3Dmedia%26token%3Dcf38f01c-6eb6-4db0-958b-9a9fa7dd7a97" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--7cshfwkz--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://firebasestorage.googleapis.com/v0/b/blogs-1de93.appspot.com/o/assets%252Fproject_structure%252Fquick_access.png%3Falt%3Dmedia%26token%3Dcf38f01c-6eb6-4db0-958b-9a9fa7dd7a97" width="40%"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--SWsNGVdL--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://firebasestorage.googleapis.com/v0/b/blogs-1de93.appspot.com/o/assets%252Fproject_structure%252Fsearch.png%3Falt%3Dmedia%26token%3D01b147f6-c362-482a-ada5-877485c3e138" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--SWsNGVdL--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://firebasestorage.googleapis.com/v0/b/blogs-1de93.appspot.com/o/assets%252Fproject_structure%252Fsearch.png%3Falt%3Dmedia%26token%3D01b147f6-c362-482a-ada5-877485c3e138" width="40%"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Conclusion
&lt;/h1&gt;

&lt;p&gt;Hope these tips can help you increase your coding performance. Please share me how you organize your project structure. I am sure your ways are awesome ways. &lt;/p&gt;

&lt;p&gt;Introduce a very cool tool: &lt;a href="https://github.com/venmo/synx"&gt;https://github.com/venmo/synx&lt;/a&gt;. You should try it. &lt;/p&gt;

</description>
      <category>ios</category>
      <category>xcode</category>
      <category>projectorganization</category>
    </item>
    <item>
      <title>Starting Auto Layout Programmatically</title>
      <dc:creator>Nguyen Truong Ky</dc:creator>
      <pubDate>Thu, 30 Apr 2020 18:39:07 +0000</pubDate>
      <link>https://dev.to/nguyentruongky/starting-auto-layout-programmatically-2cm7</link>
      <guid>https://dev.to/nguyentruongky/starting-auto-layout-programmatically-2cm7</guid>
      <description>&lt;p&gt;I published a &lt;a href="https://dev.to/nguyentruongky/auto-layout-with-storyboard-and-programmatically-5kn"&gt;post&lt;/a&gt; to compare Auto Layout Programmatically and Storyboard. This subject has no correct answer at all. It depends on you and your experience. &lt;/p&gt;

&lt;p&gt;I wasn't able to live without Storyboard until I found the pain in Storyboard. Today I tell you how I started using Auto Layout Programmatically (ALP) and how I use it in my company projects everyday. &lt;/p&gt;

&lt;h1&gt;
  
  
  How I started
&lt;/h1&gt;

&lt;p&gt;I followed some cources from &lt;a href="https://www.youtube.com/channel/UCuP2vJ6kRutQBfRmdcI92mA"&gt;Let's Build That App&lt;/a&gt; and learned how to use ALP by default code from Apple. Really good source to start ALP. &lt;/p&gt;

&lt;p&gt;Today, I demonstrate how to use ALP with 3 different ways. I implement this screen by 3 ways and you can pick the best one for you. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--YLuGCE3w--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://firebasestorage.googleapis.com/v0/b/blogs-1de93.appspot.com/o/assets%252Fstart_autolayout_programmatically%252F1.png%3Falt%3Dmedia%26token%3D3b458df8-91f3-49ce-82b8-10f9b466f2ce" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--YLuGCE3w--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://firebasestorage.googleapis.com/v0/b/blogs-1de93.appspot.com/o/assets%252Fstart_autolayout_programmatically%252F1.png%3Falt%3Dmedia%26token%3D3b458df8-91f3-49ce-82b8-10f9b466f2ce" width="50%"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Let's do it.&lt;/p&gt;

&lt;h1&gt;
  
  
  Define controls
&lt;/h1&gt;

&lt;p&gt;Define and format background image view, some buttons. These controls are same for all ways in this post. We just focus on how to setup Auto Layout by code.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;let imgView = UIImageView(image: UIImage(named: "air_balloon"))
imgView.translatesAutoresizingMaskIntoConstraints = false
imgView.contentMode = .scaleAspectFill

let termLabel = UILabel()
termLabel.translatesAutoresizingMaskIntoConstraints = false
termLabel.textAlignment = .center
termLabel.numberOfLines = 0
termLabel.text = "By signing up, you agree to our Terms &amp;amp; Privacy Policy"
termLabel.textColor = .white

let fbLoginButton = UIButton()
fbLoginButton.translatesAutoresizingMaskIntoConstraints = false
fbLoginButton.setTitle("Login with Facebook", for: .normal)
fbLoginButton.setTitleColor(.white, for: .normal)
fbLoginButton.backgroundColor = UIColor(red: 123/255, green: 107/255, blue: 173/255, alpha: 1)

let registerEmailButton = UIButton()
registerEmailButton.translatesAutoresizingMaskIntoConstraints = false
registerEmailButton.setTitle("Sign up with email", for: .normal)
registerEmailButton.setTitleColor(.white, for: .normal)
registerEmailButton.backgroundColor = UIColor(red: 163/255, green: 128/255, blue: 190/255, alpha: 1)

let loginButton = UIButton()
loginButton.translatesAutoresizingMaskIntoConstraints = false
loginButton.setTitle("I already have an account", for: .normal)
loginButton.setTitleColor(.white, for: .normal)
loginButton.backgroundColor = UIColor(red: 171/255, green: 163/255, blue: 177/255, alpha: 1)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h1&gt;
  
  
  Default way
&lt;/h1&gt;

&lt;p&gt;Default syntax from Apple. Quite standard and important. You have to understand these syntax completely. Never depend 100% on any libraries.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;view.addSubview(imgView)
imgView.leftAnchor.constraint(equalTo: view.leftAnchor).isActive = true
imgView.rightAnchor.constraint(equalTo: view.rightAnchor).isActive = true
imgView.topAnchor.constraint(equalTo: view.topAnchor).isActive = true
imgView.bottomAnchor.constraint(equalTo: view.bottomAnchor).isActive = true


view.addSubview(termLabel)
termLabel.leftAnchor.constraint(equalTo: view.leftAnchor, constant: 16).isActive = true
termLabel.rightAnchor.constraint(equalTo: view.rightAnchor, constant: -16).isActive = true


view.addSubview(fbLoginButton)
fbLoginButton.leftAnchor.constraint(equalTo: view.leftAnchor).isActive = true
fbLoginButton.rightAnchor.constraint(equalTo: view.rightAnchor).isActive = true
fbLoginButton.heightAnchor.constraint(equalToConstant: 64).isActive = true


view.addSubview(registerEmailButton)
registerEmailButton.leftAnchor.constraint(equalTo: view.leftAnchor).isActive = true
registerEmailButton.rightAnchor.constraint(equalTo: view.rightAnchor).isActive = true
registerEmailButton.heightAnchor.constraint(equalToConstant: 64).isActive = true


view.addSubview(loginButton)
loginButton.leftAnchor.constraint(equalTo: view.leftAnchor).isActive = true
loginButton.rightAnchor.constraint(equalTo: view.rightAnchor).isActive = true
loginButton.heightAnchor.constraint(equalToConstant: 48).isActive = true
loginButton.bottomAnchor.constraint(equalTo: view.bottomAnchor).isActive = true

registerEmailButton.bottomAnchor.constraint(equalTo: loginButton.topAnchor).isActive = true
fbLoginButton.bottomAnchor.constraint(equalTo: registerEmailButton.topAnchor).isActive = true
termLabel.bottomAnchor.constraint(equalTo: fbLoginButton.topAnchor, constant: -16).isActive = true
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h3&gt;
  
  
  Pros
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Default ways, not depends on any libraries&lt;/li&gt;
&lt;li&gt;You remember the syntax. 
### Cons&lt;/li&gt;
&lt;li&gt;Boring: Type or copy/paste same things many times.&lt;/li&gt;
&lt;li&gt;Many lines of code.
### Notes&lt;/li&gt;
&lt;li&gt;You can add functions to shorten your code. I leave it for you. &lt;/li&gt;
&lt;li&gt;Important: &lt;strong&gt;You have to understand how default syntax work before moving to any libraries&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  Better way: &lt;a href="https://github.com/SnapKit/SnapKit"&gt;Snapkit&lt;/a&gt;
&lt;/h1&gt;

&lt;p&gt;Snapkit is very popular and has 14,245 stars on Github. You can try some alternative libs&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/PureLayout/PureLayout"&gt;PureLayout&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/robb/Cartography"&gt;Cartography&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;view.addSubview(imgView)
imgView.snp.makeConstraints({ (make) in
    make.left.equalToSuperview()
    make.right.equalToSuperview()
    make.top.equalToSuperview()
    make.bottom.equalToSuperview()
})


view.addSubview(termLabel)
termLabel.snp.makeConstraints { (make) in
    make.left.equalToSuperview().offset(16)
    make.right.equalToSuperview().offset(-16)
}


view.addSubview(fbLoginButton)
fbLoginButton.snp.makeConstraints { (make) in
    make.left.equalToSuperview()
    make.right.equalToSuperview()
    make.height.equalTo(64)
}


view.addSubview(registerEmailButton)
registerEmailButton.snp.makeConstraints { (make) in
    make.left.equalToSuperview()
    make.right.equalToSuperview()
    make.height.equalTo(64)
}


view.addSubview(loginButton)
loginButton.snp.makeConstraints { (make) in
    make.left.equalToSuperview()
    make.right.equalToSuperview()
    make.bottom.equalToSuperview()
    make.height.equalTo(32)
}

registerEmailButton.snp.makeConstraints { (make) in
    make.bottom.equalTo(loginButton.snp.top)
}

fbLoginButton.snp.makeConstraints { (make) in
    make.bottom.equalTo(registerEmailButton.snp.top)
}

termLabel.snp.makeConstraints { (make) in
    make.bottom.equalTo(fbLoginButton.snp.top).inset(-16)
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h3&gt;
  
  
  Pros
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Quite better, shorter syntax&lt;/li&gt;
&lt;li&gt;Easier to read &lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Cons
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Have a middle man &lt;code&gt;snp&lt;/code&gt;. Not cool with me&lt;/li&gt;
&lt;li&gt;Have a closure to setup layout&lt;/li&gt;
&lt;li&gt;Single constraints are not in good syntax.&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  My way: &lt;a href="https://github.com/nguyentruongky/KNConstraints"&gt;KNConstraint&lt;/a&gt;
&lt;/h1&gt;

&lt;p&gt;Honestly, I was affected by Robert-Hein Hooijmans to write this extension. Love how he write his lib, &lt;a href="https://github.com/roberthein/TinyConstraints"&gt;TinyConstraint&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;I do something different in my extension, and shorten the syntax.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;view.addSubviews(views: imgView, termLabel, fbLoginButton, registerEmailButton, loginButton)
imgView.fill(toView: view)

termLabel.horizontal(toView: view, space: 16)
termLabel.verticalSpacingDown(toView: fbLoginButton, space: -16)

fbLoginButton.horizontal(toView: view)
fbLoginButton.height(64)
fbLoginButton.verticalSpacingDown(toView: registerEmailButton)

registerEmailButton.horizontal(toView: view)
registerEmailButton.height(64)
registerEmailButton.verticalSpacingDown(toView: loginButton)

loginButton.horizontal(toView: view)
loginButton.bottom(toView: view)
loginButton.height(32)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h3&gt;
  
  
  Pros
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Very short syntax &lt;/li&gt;
&lt;li&gt;Easy to read, like a short paragraph. &lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Cons
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Some new term like &lt;code&gt;horizontal&lt;/code&gt;, &lt;code&gt;vertical&lt;/code&gt;, &lt;code&gt;verticalSpacing&lt;/code&gt;, &lt;code&gt;verticalSpacingDown&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  Conclusion
&lt;/h1&gt;

&lt;p&gt;I show you 3 different ways to setup Auto Layout by code. There are pros and cons in every way. &lt;br&gt;
Select a good way for you to start Auto Layout Programmatically. &lt;br&gt;
You can download the demo at &lt;a href="https://github.com/nguyentruongky/start_auto_layout_programmatically"&gt;my Github&lt;/a&gt;. &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Enjoy coding&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>ios</category>
      <category>swift</category>
      <category>autolayoutprogrammatically</category>
      <category>storyboard</category>
    </item>
    <item>
      <title>Auto Layout with Storyboard and Programmatically</title>
      <dc:creator>Nguyen Truong Ky</dc:creator>
      <pubDate>Wed, 29 Apr 2020 23:00:24 +0000</pubDate>
      <link>https://dev.to/nguyentruongky/auto-layout-with-storyboard-and-programmatically-5kn</link>
      <guid>https://dev.to/nguyentruongky/auto-layout-with-storyboard-and-programmatically-5kn</guid>
      <description>&lt;p&gt;I started iOS development as a .NET developer. My first impression, Storyboard is really really interesting. 80% UI of my apps is built in Storyboard. I can’t imagine how I can develop iOS without Storyboard.&lt;/p&gt;

&lt;p&gt;There are many discussions about Auto Layout with Storyboard or Programmatically is better. But no one wins. Everyone has own reason and belief.&lt;/p&gt;

&lt;p&gt;This post is my personal opinion. It’s written by a developer &lt;strong&gt;can’t live without Storyboard, and now he abandons it.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;3 reasons why he changed to Auto Layout by programmatically.&lt;/p&gt;

&lt;h1&gt;
  
  
  Why do I abandon Storyboard?
&lt;/h1&gt;

&lt;h2&gt;
  
  
  1. Too many steps to changes
&lt;/h2&gt;

&lt;p&gt;I designed a very good UI, and connected outlet, started logic coding, finished that feature. One day, I had to refactor code and found some improvement. Some &lt;code&gt;UILabel&lt;/code&gt; had gestures, should be changed to &lt;code&gt;UIButton&lt;/code&gt;. No problem, made changes. What did I do?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Found the &lt;code&gt;UILabel&lt;/code&gt; need change&lt;/li&gt;
&lt;li&gt;Delete one by one.&lt;/li&gt;
&lt;li&gt;Add new &lt;code&gt;UIButton&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Connect new outlets&lt;/li&gt;
&lt;li&gt;Setup Auto Layout constraints. (This is most painful step, dozens of constraints need setup)&lt;/li&gt;
&lt;li&gt;Find and change other things in code&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And when I changed to Auto Layout programmatically:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Found the &lt;code&gt;UILabel&lt;/code&gt; need change&lt;/li&gt;
&lt;li&gt;Change &lt;code&gt;UILabel&lt;/code&gt; to &lt;code&gt;UIButton&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Find and change other things in code&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Easier a lot, right? Especially, no change in setting up constraints.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Open Storyboard is a pain in the ass
&lt;/h2&gt;

&lt;p&gt;My first project had a huge Storyboard, all-in-one. More than &lt;strong&gt;30 Controllers&lt;/strong&gt; were in &lt;strong&gt;1 Storyboard file&lt;/strong&gt;. It’s a nightmare. Few times I got conflicts with other members' commits. Fix conflicts in XML is another nightmare.&lt;/p&gt;

&lt;p&gt;Thanks God, some experienced developers tell about split it up. A Storyboard should contain 3 to 5 Controllers, not more. It should be splitted up as features, for instance, &lt;code&gt;Membership&lt;/code&gt; Storyboard contains &lt;code&gt;Landing&lt;/code&gt;, &lt;code&gt;Register&lt;/code&gt;, &lt;code&gt;Login&lt;/code&gt; Controllers, or &lt;code&gt;Password&lt;/code&gt; Controller contains &lt;code&gt;ForgotPassword&lt;/code&gt;, &lt;code&gt;Confirmation&lt;/code&gt;, &lt;code&gt;NewPassword&lt;/code&gt; Controllers. It’s a big improvement and save a lot of iOS developer’s lives.&lt;/p&gt;

&lt;p&gt;It’s better but not the best choice. Conflicts usually occur with Storyboard, and can’t avoid. Besides that, constraints list is a mess, really mess and easy to make you mad.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--acWxZNxr--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://raw.githubusercontent.com/nguyentruongky/Photos_storage/master/Auto_Layout_Programmatically/Constraint_list.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--acWxZNxr--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://raw.githubusercontent.com/nguyentruongky/Photos_storage/master/Auto_Layout_Programmatically/Constraint_list.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can debate about select a control, and select the constraint you want instead of find in the list. Believe me, many times you can’t do that, and you soon get mad with it.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Dynamically customize control with Auto Layout programmatically
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--_UgXO4-s--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://raw.githubusercontent.com/nguyentruongky/Photos_storage/master/Auto_Layout_Programmatically/Custom_Control.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--_UgXO4-s--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://raw.githubusercontent.com/nguyentruongky/Photos_storage/master/Auto_Layout_Programmatically/Custom_Control.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;What would you do with this control in Storyboard? You can make a custom view with 1 &lt;code&gt;UILabel&lt;/code&gt; for title, 1 &lt;code&gt;UITextField&lt;/code&gt; for text input, and 1 &lt;code&gt;UIView&lt;/code&gt; for underline, 1 &lt;code&gt;UIButton&lt;/code&gt; for right button.&lt;/p&gt;

&lt;p&gt;How to use it? Drag a &lt;code&gt;UIView&lt;/code&gt; to Storyboard, choose subclass. Remember, it’s a UIView. You have to access to the view instance, textField and change the properties.&lt;/p&gt;

&lt;p&gt;But with Auto Layout programmatically, it’s a &lt;code&gt;UITextField&lt;/code&gt;. You can change textColor, font, backgroundColor easily. Again, It’s a &lt;code&gt;UITextField&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;You can see how I implement this custom &lt;code&gt;UITextField&lt;/code&gt; at &lt;a href="https://github.com/nguyentruongky/knCollection/blob/develop/knCollection/Control/knGistTextField.swift"&gt;knGistTextField&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Reasons prevent you from using Auto Layout programmatically
&lt;/h1&gt;

&lt;h2&gt;
  
  
  Too many code in a file
&lt;/h2&gt;

&lt;p&gt;Yes, I have to admit that. There are 600 - 700 lines of code in my file. But it’s easy to solve this problem with &lt;strong&gt;Extension&lt;/strong&gt;. Why don’t we define and setup constraints in a file, (&lt;code&gt;LoginControllerUI.swift&lt;/code&gt;, for instance), and move all handler, logic into new file, &lt;code&gt;LoginControllerHandler.swift&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Write the same codes many times
&lt;/h2&gt;

&lt;p&gt;Define a &lt;code&gt;UIButton&lt;/code&gt; with Auto Layout programmatically&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt; let button: UIButton = {
    let title = "Sample"
    let image = "Sample"
    let color = UIColor.black

    let button = UIButton()
    button.translatesAutoresizingMaskIntoConstraints = false
    button.setTitle(title, for: .normal)
    button.setTitleColor(color, for: .normal)
    button.setImage(UIImage(named: image), for: .normal)
    return button
}()
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Every time I need a &lt;code&gt;UIButton&lt;/code&gt;, do I have to find and copy this code? No, code snippet can help you.&lt;/p&gt;

&lt;p&gt;Find out how it helps &lt;a href="https://nshipster.com/xcode-snippets/"&gt;here&lt;/a&gt;. I define above button with &lt;code&gt;knButton&lt;/code&gt; key in my XCode. It’s easier that find and drag a &lt;code&gt;UIButton&lt;/code&gt; and then format it in Storyboard, right?&lt;/p&gt;

&lt;h3&gt;
  
  
  Better way
&lt;/h3&gt;

&lt;p&gt;You create a static funciton and use it with ease.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;static func makeButton(title: String? = nil,
                       titleColor: UIColor = .black,
                       font: UIFont? = nil,
                       background: UIColor = .clear,
                       cornerRadius: CGFloat = 0,
                       borderWidth: CGFloat = 0,
                       borderColor: UIColor = .clear) -&amp;gt; UIButton {
    let button = UIButton()
    button.translatesAutoresizingMaskIntoConstraints = false
    button.setTitle(title, for: .normal)
    button.setTitleColor(titleColor, for: .normal)
    button.titleLabel?.font = font
    button.setCorner(radius: cornerRadius)
    button.setBorder(borderWidth, color: borderColor)
    return button
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2&gt;
  
  
  Code is too long and unreadable
&lt;/h2&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// (1)
let underline = UIView()
underline.backgroundColor = UIColor.lightGray
underline.translatesAutoresizingMaskIntoConstraints = false
addSubview(underline)

// (2)
underline.bottomAnchor.constraint(equalTo: bottomAnchor, constant: -8).isActive = true
underline.rightAnchor.constraint(equalTo: rightAnchor).isActive = true
underline.leftAnchor.constraint(equalTo: leftAnchor).isActive = true
underline.heightAnchor.constraint(equalToConstant: 1).isActive = true

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h3&gt;
  
  
  (1)
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Same to all controls in Auto Layout programmatically, you have to keep this format for all controls. You can make it better with code below
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;extension UIView {
    func addToView(view: UIView) {
        translatesAutoresizingMaskIntoConstraints = false
        view.addSubview(self)
    }
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;(1) can be changed to&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;let underline = UIView() 
underline.addToView(view)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h3&gt;
  
  
  (2)
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;They’re default code from Apple, why don’t we make it more readable and beautiful?
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;underline.bottom(toView: view, space: -8)
underline.horizontal(toView: view)
underline.height(1)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Is it beautiful enough? It comes from my own Auto Layout library. You can find it at &lt;a href="https://github.com/nguyentruongky/knConstraints"&gt;knConstraints&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  How to start with Auto Layout programmatically?
&lt;/h1&gt;

&lt;p&gt;If you wan to try a life without Storyboard, why don’t you try these following instructions?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Setup your own code snippets&lt;/li&gt;
&lt;li&gt;Try my Auto Layout library &lt;a href="https://github.com/nguyentruongky/knConstraints"&gt;&lt;strong&gt;knConstraints&lt;/strong&gt;&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Develop some simple custom views, with Auto Layout programmatically.&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  How can I help?
&lt;/h1&gt;

&lt;p&gt;Please feel free to touch to me by leaving comments or schedule a session with me. &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Enjoy coding&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>autolayoutprogrammatically</category>
      <category>autolayoutbycode</category>
      <category>autolayout</category>
      <category>storyboard</category>
    </item>
    <item>
      <title>Tips to boost your iOS work</title>
      <dc:creator>Nguyen Truong Ky</dc:creator>
      <pubDate>Tue, 28 Apr 2020 21:19:34 +0000</pubDate>
      <link>https://dev.to/nguyentruongky/tips-to-boost-your-ios-work-4mdd</link>
      <guid>https://dev.to/nguyentruongky/tips-to-boost-your-ios-work-4mdd</guid>
      <description>&lt;p&gt;Some tips below help me work faster and more efficiently. Let's check it out. &lt;/p&gt;

&lt;h1&gt;
  
  
  1. Don't depend on server API.
&lt;/h1&gt;

&lt;p&gt;APIs are immensely important and we can't do anything without APIs. So can we watch Youtube or Facebook while backend teams are burying their noses in code? &lt;br&gt;
You will get a red alert from your manager soon. &lt;br&gt;
Or APIs are slow and hard for us to test while developing it. What should we do? &lt;/p&gt;

&lt;p&gt;&lt;code&gt;Don't depend on server API. Just depend on the schemas.&lt;/code&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Ask backend for API schemas, which they send to us when we call. Save it into a json file. &lt;/li&gt;
&lt;li&gt;Use tip #2 or #3 to create your data model.&lt;/li&gt;
&lt;li&gt;Setup your code as you're calling API. I usually seperate API calls to workers. You can do your way.
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class GetUserDetailWorker {
// (1)
    func run(completion: @escaping(User?, Error?) -&amp;gt; Void) {
        Alamofire.request() {
            handleResponse(response: AnyObject, completion: completion)
        }
    }

// (2)
    private func handleResponse(response: AnyObject?, completion: @escaping(User?, Error?) -&amp;gt; Void) {
        // parse json to your data model
        // check logic
        // ...
        // call completion
    }
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;(1): Your controllers don't know what is inside the &lt;code&gt;GetUserDetailWorker&lt;/code&gt;. They respond to success or failure from the worker. So, you are free to fake any data here and see how your controllers respond to. &lt;/p&gt;

&lt;p&gt;(2): This is where you parse raw json to your data model, handle the logic and response.&lt;/p&gt;

&lt;p&gt;Now do a trick. &lt;/p&gt;

&lt;p&gt;Add function after your &lt;code&gt;handleResponse&lt;/code&gt; function.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;func loadLocally(completion: @escaping(User?, Error?) -&amp;gt; Void) {
    if let filepath = Bundle.main.path(forResource: "User", ofType: "json") {
        do {
            let contents = try String(contentsOfFile: filepath)
            let data = contents.data(using: .utf8)!
            if let json = try JSONSerialization.jsonObject(with: data, options : .allowFragments) as AnyObject? {
                handleResponse(response: json, completion: completion)
                } else {
                    print("bad json")
                }
        } catch {
            completion(nil, error)
        }
    }
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Add this at the begining of &lt;code&gt;run&lt;/code&gt; function.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;loadLocally(completion: completion)
return
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;We load the &lt;code&gt;user.json&lt;/code&gt; and send it to controllers. It's on your computer, we can change any data as we want. When APIs are ready, just remove these 2 lines and work like a charm. &lt;/p&gt;

&lt;h2&gt;
  
  
  Some advantages
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Fast. You call it from your computer, no delay or depend on internet. &lt;/li&gt;
&lt;li&gt;Convenient. You can change any data you want, good cases, bad cases and change your UI approriately. &lt;/li&gt;
&lt;li&gt;Independent. You don't depend on server progress anymore. &lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  2. Create init function
&lt;/h1&gt;

&lt;p&gt;When you define &lt;code&gt;struct&lt;/code&gt;, Swift can give you an &lt;code&gt;init&lt;/code&gt; function, you don't have to write it yourself. But if you use &lt;code&gt;class&lt;/code&gt;, no free &lt;code&gt;init&lt;/code&gt;. What if you have a long class and long &lt;code&gt;init&lt;/code&gt;, like below.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class User {
    var id: String
    var tasks: [String]
    var email: String?
    var membershipExpirationDate: Date?
    var startDate: Date?
    var cancelAtPeriodEnd: Bool?
    var balance: Int
    let phoneNumber: String?
    let currency: String
    init(id: String, tasks: [String], email: String?, membershipExpirationDate: Date?, startDate: Date?, cancelAtPeriodEnd: Bool?, balance: Int, phoneNumber: String?, currency: String) {
        self.id = id
        self.tasks = tasks
        self.email = email
        self.membershipExpirationDate = membershipExpirationDate
        self.startDate = startDate
        self.cancelAtPeriodEnd = cancelAtPeriodEnd
        self.balance = balance
        self.phoneNumber = phoneNumber
        self.currency = currency
    }
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Do you want to type it yourself? Try this way. &lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--TAPChkEY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://firebasestorage.googleapis.com/v0/b/blogs-1de93.appspot.com/o/assets%252Fsublime%252Finit_function.gif%3Falt%3Dmedia%26token%3D6b2fbd14-3dbf-4564-ab6f-a58ee5b8a746" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--TAPChkEY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://firebasestorage.googleapis.com/v0/b/blogs-1de93.appspot.com/o/assets%252Fsublime%252Finit_function.gif%3Falt%3Dmedia%26token%3D6b2fbd14-3dbf-4564-ab6f-a58ee5b8a746" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Notes&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Press &lt;code&gt;option&lt;/code&gt; and drag to select multiline.&lt;/li&gt;
&lt;li&gt;Delete unused words.&lt;/li&gt;
&lt;li&gt;Copy properties' name.&lt;/li&gt;
&lt;li&gt;Press &lt;code&gt;esc&lt;/code&gt; to quit multi cursors. &lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;
  
  
  3. Parse JSON result
&lt;/h1&gt;

&lt;p&gt;I am not a fan of &lt;code&gt;Codable&lt;/code&gt;. It's really useful in simple responses, but complicated ones, no thanks. And it's hard to debug also. &lt;/p&gt;

&lt;p&gt;Most of work, I parse JSON manually, don't use &lt;code&gt;SwiftyJSON&lt;/code&gt; or similar ones. One time, I joined a team with complicated responses. Example is below.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  "Id": "b206bb24-03ab-4a25-a9c4-b26e2fd2e9f8",
  "Name": "Hexagon 21",
  "ScreenName": null,
  "Picture": "https://scontent.xx.fbcdn.net/v/t1.0-9/20245457_303012200102286_1324449236613079430_n.jpg?_nc_cat=104&amp;amp;_nc_oc=AQmRtf3n0fmK36Z8Vnzz5QFECni4m52YHbm0GbzdSEI6slVpgf59oGBHZCeOBv3yzGc&amp;amp;_nc_ht=scontent.xx&amp;amp;oh=24ebc12ea4244757e584f7f438e06e44&amp;amp;oe=5E613D7C",
  "ExternalId": "575475522634796",
  "FacebookUserId": null,
  "Account": null,
  "Type": 1,
  "Subtype": "FacebookGroup",
  "IsDefault": false,
  "Credential": null,
  "AssociatedSource": null,
  "PublishMessageProfiles": null,
  "ProfileSubscribeNotifications": null,
  "Selected": false,
  "HasAppInstalled": null,
  "IsWebHookSubscribed": false,
  "IsTwitterWebHookSubscribed": null
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Now, making a class from these is a boring work. &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Use this: &lt;a href="https://app.quicktype.io/"&gt;https://app.quicktype.io/&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Explore options on the right pane to see it changes. 
And here the result:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class User {
    var id: String?
    var name: String?
    var screenName: NSNull?
    var picture: String?
    var externalID: String?
    var facebookUserID: NSNull?
    var account: NSNull?
    var type: Int?
    var subtype: String?
    var isDefault: Bool?
    var credential: NSNull?
    var associatedSource: NSNull?
    var publishMessageProfiles: NSNull?
    var profileSubscribeNotifications: NSNull?
    var selected: Bool?
    var hasAppInstalled: NSNull?
    var isWebHookSubscribed: Bool?
    var isTwitterWebHookSubscribed: NSNull?

    init(id: String?, name: String?, screenName: NSNull?, picture: String?, externalID: String?, facebookUserID: NSNull?, account: NSNull?, type: Int?, subtype: String?, isDefault: Bool?, credential: NSNull?, associatedSource: NSNull?, publishMessageProfiles: NSNull?, profileSubscribeNotifications: NSNull?, selected: Bool?, hasAppInstalled: NSNull?, isWebHookSubscribed: Bool?, isTwitterWebHookSubscribed: NSNull?) {
        self.id = id
        self.name = name
        self.screenName = screenName
        self.picture = picture
        self.externalID = externalID
        self.facebookUserID = facebookUserID
        self.account = account
        self.type = type
        self.subtype = subtype
        self.isDefault = isDefault
        self.credential = credential
        self.associatedSource = associatedSource
        self.publishMessageProfiles = publishMessageProfiles
        self.profileSubscribeNotifications = profileSubscribeNotifications
        self.selected = selected
        self.hasAppInstalled = hasAppInstalled
        self.isWebHookSubscribed = isWebHookSubscribed
        self.isTwitterWebHookSubscribed = isTwitterWebHookSubscribed
    }
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Pretty cool, right? &lt;/p&gt;

&lt;h1&gt;
  
  
  Conclusion
&lt;/h1&gt;

&lt;p&gt;Some tips from my experience. Hope them help you work faster and more interesting your work. &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Enjoy coding&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>ios</category>
      <category>iostips</category>
    </item>
    <item>
      <title>iOS developer starts learning Android development</title>
      <dc:creator>Nguyen Truong Ky</dc:creator>
      <pubDate>Tue, 28 Apr 2020 21:17:07 +0000</pubDate>
      <link>https://dev.to/nguyentruongky/ios-developer-starts-learning-android-development-2mab</link>
      <guid>https://dev.to/nguyentruongky/ios-developer-starts-learning-android-development-2mab</guid>
      <description>&lt;h1&gt;
  
  
  iOS development choice
&lt;/h1&gt;

&lt;p&gt;I started iOS development 7 years ago when I was a .NET developer. That's a hard time for me. I had to choose learn Objective-C or Swift. At that time, Swift was too young and super easy to start. But the company project was written in Objective-C. Finally, I picked Swift learn deeply and abandon Objective-C.  &lt;/p&gt;

&lt;p&gt;I tried a lot of books, just few chapters in every book and easily found they make no sense and not really good for a fresher. I watched hundreds of videos on YouTube, and some are good, others are not.  &lt;/p&gt;

&lt;p&gt;Finally, I found a really good book from Ray Wenderlich.  &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--wnmdIJiR--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://files.kerching.raywenderlich.com/heros/5617284d-b374-4179-9ba8-cd64a5541c3c.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--wnmdIJiR--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://files.kerching.raywenderlich.com/heros/5617284d-b374-4179-9ba8-cd64a5541c3c.png" alt=""&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;I tried this book and learnt very fast. 2 weeks later, I started working on another company project, which was written in Swift.  &lt;/p&gt;

&lt;p&gt;I always suggest this to any mentees want to learn iOS. It helps them to build their fundamental knowledge.  &lt;/p&gt;

&lt;p&gt;2 years later, I figured out &lt;a href="https://www.youtube.com/channel/UCuP2vJ6kRutQBfRmdcI92mA"&gt;Lets build that app&lt;/a&gt; from Brian Voong. This brought my iOS development to a higher level. From that day, &lt;a href="https://www.codementor.io/@nguyentruongky/auto-layout-with-storyboard-and-programmatically-r1zuvtzbk"&gt;I've abandoned Storyboard&lt;/a&gt; and keep working with auto layout programmatically.  &lt;/p&gt;

&lt;p&gt;I've worked and learned 10-14 hours a day &lt;a href="https://www.codementor.io/@nguyentruongky/make-the-most-of-your-24-hours-qwyda1d2l"&gt;with few tips here&lt;/a&gt;. It makes me grow faster and stronger.  &lt;/p&gt;

&lt;p&gt;And now, here I am. I'm here to help you learn iOS and develop your career.  &lt;/p&gt;

&lt;h1&gt;
  
  
  Android development choice
&lt;/h1&gt;

&lt;p&gt;Today, I have the same problem, with Java and Kotlin. No doubt, select Kotlin as the first option.  &lt;/p&gt;

&lt;p&gt;I started learning Android 2 weeks ago, and lost in definitions, concepts, syntax. I tried book from Ray Wenderlich, some tutorials, anything I found and thought it's good, I tried. But not better. Ray's books are good but this time, doesn't work for me.  &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--U_Pz9Isn--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://files.kerching.raywenderlich.com/heros/9fabf748-6567-42f3-bd3e-1a66b5fb59b6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--U_Pz9Isn--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://files.kerching.raywenderlich.com/heros/9fabf748-6567-42f3-bd3e-1a66b5fb59b6.png" alt=""&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;Finally, I found &lt;a href="https://www.youtube.com/watch?v=ihJGxFu2u9Q&amp;amp;list=PL0dzCUj1L5JE-jiBHjxlmXEkQkum_M3R-"&gt;a course from Brian Voong&lt;/a&gt;. It's really awesome. And I am still learning in this list, Episode 9, at this time.  &lt;/p&gt;

&lt;h1&gt;
  
  
  How to learn new language/technologies
&lt;/h1&gt;

&lt;p&gt;Below are some notes I apply when I learn new thing, some are from my failures. They're used in my learning history and bring good result. Let's check it they work for you.  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Ask: I didn't ask so I had to try anything I found. Many suggestions on Google, but not all of them are good for you. Ray's books are good for others but not good for me. So, ask your friends, your mentors, they can give you good answers.  &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Ask strangers: Sometimes, strangers have same backgrounds, levels with you can give you exactly suggestions. Just ask. Developers are open to share, not all, but most. &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Try: don't trust anyone. Ask them to get suggestions, but you have to try yourself. Learn few chapters, try for 2 or 3 days and evaluate yourself. You find the best one for you.  &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Note what you learn. Anything is new for you, add to your notes. You forget it tomorrow, next week, next month. Just note, it helps you and other developers like you in future. I have a note about my first Android project &lt;a href="https://github.com/nguyentruongky/KotlinMessenger"&gt;here&lt;/a&gt;. &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Create your workspace. Create a codebase project, where you can put any new code snippets you did. Try to make it separately. Next project, you don't want to write that code again, copy it from your workspace.  &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Never stop learning: I've worked 10-14 hours a day, and done a lot of projects to improve my code, practiced hundreds of samples, follow thousands of tutorials. If you need any subjects/projects to practice in your development, don't hesitate to text me.  &lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  Conclusion
&lt;/h1&gt;

&lt;p&gt;Learning new things is never easy, but really fun. Never stop learning, never stop code. When you stop, you're dying.  &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Enjoy coding.  &lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>ios</category>
      <category>android</category>
      <category>learning</category>
    </item>
    <item>
      <title>Make the Most of Your 24 Hours</title>
      <dc:creator>Nguyen Truong Ky</dc:creator>
      <pubDate>Mon, 27 Apr 2020 22:20:33 +0000</pubDate>
      <link>https://dev.to/nguyentruongky/make-the-most-of-your-24-hours-j77</link>
      <guid>https://dev.to/nguyentruongky/make-the-most-of-your-24-hours-j77</guid>
      <description>&lt;p&gt;I started iOS as a 2-year-experience .NET developer. The salary range for a junior iOS dev is a little bit lower than the amount for a 2-year-experience develop get. I wanted to make myself stronger, earn more experience. I had a misconception of working and learning. I thought, freelance projects will help me strengthen my knowledge and experience. So I tried to get as more as possible freelance projects. And my nightmare started from here.&lt;/p&gt;

&lt;p&gt;I had no time to spend with my family, no time to work on personal improvement, no time to go out with friends, no time at all. All of my time was used up on my freelance work from coding new features, fixing bugs and much more. I was killing myself working odd hours and missing out on quality time with my family and friends.&lt;/p&gt;

&lt;p&gt;I made a mess, uncountable technical debts, bugs, with the project. I was angry with everyone and myself. And the company project was affected. I brought more bugs there, dozens of stupid bugs, critical bugs.&lt;/p&gt;

&lt;p&gt;Finally, after lots of stress situations, I found a way to get myself out of these nightmares.&lt;/p&gt;

&lt;h1&gt;
  
  
  Why necessary for you?
&lt;/h1&gt;

&lt;p&gt;You’re developer, and you understand clearly about the pressure in development. I’m sure you want to get some freelance projects to earn more money. So, you should try my solution to manage your time effectively.&lt;/p&gt;

&lt;p&gt;You’re developer, and you have to work OT. Too many tasks you have and you have no enough time for work. No time for family, no time for your life, no time at all. My solution can help you get out of your situation.&lt;/p&gt;

&lt;h1&gt;
  
  
  Solution
&lt;/h1&gt;

&lt;p&gt;This solution is about how to change the way I work, how to manage time effectively. It’s absolutely right for me, and helps me out of the shit situations, boost my career, make my life better. Is it good to try yourself?&lt;/p&gt;

&lt;p&gt;This solution has 2 parts:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Life skills: something you can change in your life, how you work, how you enjoy your life…&lt;/li&gt;
&lt;li&gt;Tech skills: 3 tips for iOS developers to work faster, better, and save time.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Life Skills - Switch Up Working Hours
&lt;/h2&gt;

&lt;p&gt;You have to spend at least 8 hours a day for working at your office. The manager says, “We have no time, we have to work OT”. Yes, it’s a extremely bad solution. Your brain, your body is drained. And now, you force it work more hard. Do you really think you can work effectively after 8 hours working? No, you don’t. You know, your colleagues know, but the manager doesn’t know.&lt;/p&gt;

&lt;p&gt;It’s too hard to decline working OT, but you should do. You have to do unless you make more bugs and everything is worse.&lt;/p&gt;

&lt;p&gt;One time, I had to work until 8.30 pm, without dinner, just some instance noodle. Went home, went to bed and 11.30pm, got a call.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“What the hell are you doing? Something is wrong with the promotion”.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;OK, turned my Macbook on and worked like a dead guy.&lt;/p&gt;

&lt;p&gt;Many times like that, and the project had shit quality. I can’t believe I can do that, but I did, no choice.&lt;/p&gt;

&lt;h3&gt;
  
  
  What is the better solution?
&lt;/h3&gt;

&lt;p&gt;The firs thing in my solution, is to switch up working hours. I decline all OT and try to work better, work more in my ideal time to finish more tasks or fix more bugs.&lt;/p&gt;

&lt;p&gt;The ideal time for working, for me, is 2am after 3 to 4 hours of sleeping, maybe different from you. This time is ideal because everything is quiet and there are absolutely no distractions. No phone calls, no email, no one bothers you. For me, this is the best time to get my creative juices flowing.&lt;/p&gt;

&lt;p&gt;It’s exactly same to freelance projects. You can achieve better results than work after office time.&lt;/p&gt;

&lt;p&gt;It’s hard to start at all, but try it yourself and experience amazing results.&lt;/p&gt;

&lt;h2&gt;
  
  
  Life Skills - Keep Up Health
&lt;/h2&gt;

&lt;p&gt;Most importantly, a healthy body is the key to reach success. I have to work 8 hours everyday in an office and an additional 4-6 hours on freelance projects. If you do the math, my body has to work 1.5 times more than usual. Crazy, right? For most people, their body and mind will become exhausted very quickly with a schedule like this. In order for me to prevent myself from becoming ill, I make a conscious effort to include additional nutrition in my meals with more fruits, protein, etc.&lt;/p&gt;

&lt;p&gt;In additional to a healthy diet, it’s important to stay active.I try to incorporate a little bit of exercise into my daily activities. For example, I use the stairs instead of the elevator, I try to walk faster, clean the floor manually, and more. Now, I know these types of activities won’t help me become an athlete, but every little bit helps to keep my health up.&lt;/p&gt;

&lt;p&gt;You can make more evil bugs when you’re not healthy. And you waste double time to fix what you did when you’re not healthy. So, keep up your health and make good things for your code.&lt;/p&gt;

&lt;h2&gt;
  
  
  Life Skills - Change Your Mindset
&lt;/h2&gt;

&lt;p&gt;Freelance projects are very good for expanding your experience. You have many projects to fill into your CV. You can earn more money. It’s great. But they’re not good to your knowledge. Freelance projects are useful when you have strong experience and want to strengthen them. But it’s a bad choice for learning because of pressure.&lt;/p&gt;

&lt;p&gt;When you’re in a freelance projects, you have many pressure about time limit, money, client attitude… And you just want to make it done, not want to understand how it work and how to make it better. It’s harmful for you. You think you have experience with it, CoreData for instance, and you apply for new projects with CoreData require. You run into a big bugs and take lots of time to understand to fix that.&lt;/p&gt;

&lt;p&gt;Side projects are better choice. You can research new technologies, try new hot things in new iOS, SiriKit, HealthKit for instance. Don’t forget to publish some side projects. They can help you to show off for your clients or your interviewer.&lt;/p&gt;

&lt;p&gt;You also practice or strengthen your weakness in iOS with side projects. With these projects, you learn a lot and be confident to apply new projects.&lt;/p&gt;

&lt;p&gt;Don’t think about money first, think about yourself, Make yourself better and money comes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Tech skills - Code Snippets
&lt;/h2&gt;

&lt;p&gt;Code Snippets is your template codes. You don’t want to type all the code or copy it from somewhere. Just type some first characters and select it from suggestion list. For instance, I usually type “button”, and XCode will give me this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--xIhiw_WJ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://raw.githubusercontent.com/nguyentruongky/Photos_storage/master/save_coding_time_ios/Button_Snippet.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--xIhiw_WJ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://raw.githubusercontent.com/nguyentruongky/Photos_storage/master/save_coding_time_ios/Button_Snippet.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Easy, right? You don’t want to type boring code anymore.&lt;/p&gt;

&lt;p&gt;Don’t forget use &amp;lt;# and #&amp;gt; with the placeholder text in the middle. Go ahead, type that into Xcode, and watch as the text between the octothorp tags magically transforms right in front of your eyes.&lt;/p&gt;

&lt;p&gt;You can try my snippets at by copy and paste to &lt;code&gt;~/Library/Developer/Xcode/UserData/CodeSnippets/&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Small things but very useful.&lt;/p&gt;

&lt;h2&gt;
  
  
  Tech skills - Knowledge base
&lt;/h2&gt;

&lt;p&gt;It works like an external library, nearly same to Pods but in free way.&lt;/p&gt;

&lt;p&gt;Situation like this. You finished a cool animation in company project. It’s really cool and you want to use it in your current freelance project. You copy this code to the freelance project, change something and let it work like a charm. But, you find something can be better in this code. You make changes, and want this change be applied in the company project. You copy this code again. Imagine you have more 2 projects, use this animation. It’s a nightmare.&lt;/p&gt;

&lt;p&gt;Knowledge base is good choice for you. Create your own knowledge base in Github, clone to your projects. Add new features, change some if needed. Push to Github and pull it from other projects. All your projects can get the latest update easily. Cool, right?&lt;/p&gt;

&lt;h2&gt;
  
  
  Tech skills - Auto Layout programmatically
&lt;/h2&gt;

&lt;p&gt;This is a popular war for many iOS developers. Storyboard fans think this is stupid thing. Programmatically guys fight for their belief.&lt;/p&gt;

&lt;p&gt;This is opinion from a developer can’t live without Storyboard, and now he abandons it. It’s me :)&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Auto Layout programmatically saves your time and your life.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h4&gt;
  
  
  How can it help to save time?
&lt;/h4&gt;

&lt;p&gt;My situation is a good example. I designed a very good UI, and connected outlet, started logic coding, finished that feature. One day, I had to refactor code and found some improvement. Some &lt;code&gt;UILabel&lt;/code&gt; had gestures, should be changed to &lt;code&gt;UIButton&lt;/code&gt;. No problem, made changes. What did I do?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Find the &lt;code&gt;UILabel&lt;/code&gt; need change&lt;/li&gt;
&lt;li&gt;Delete one by one.&lt;/li&gt;
&lt;li&gt;Add new &lt;code&gt;UIButton&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Connect new outlets&lt;/li&gt;
&lt;li&gt;Setup Auto Layout constraints. (This is most painful step, dozens of constraints need setup)&lt;/li&gt;
&lt;li&gt;Find and change many things in code&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And when I changed to Auto Layout programmatically:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Find the &lt;code&gt;UILabel&lt;/code&gt; need change&lt;/li&gt;
&lt;li&gt;Change &lt;code&gt;UILabel&lt;/code&gt; to &lt;code&gt;UIButton&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Find and change many things in code&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Easier a lot, right? Especially, no change in setting up constraints.&lt;/p&gt;

&lt;p&gt;Another advantage is to customize controls with Auto Layout programmatically. You can make any custom controls with programmatically, but you can’t do that with Storyboard.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--_UgXO4-s--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://raw.githubusercontent.com/nguyentruongky/Photos_storage/master/Auto_Layout_Programmatically/Custom_Control.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--_UgXO4-s--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://raw.githubusercontent.com/nguyentruongky/Photos_storage/master/Auto_Layout_Programmatically/Custom_Control.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you use Storyboard (I mean Xib file), you can make a view, and copy 2 files, &lt;code&gt;NewTextField.xib&lt;/code&gt; and &lt;code&gt;NewTextField.swift&lt;/code&gt;to your knowledge base. And you want to change it name to &lt;code&gt;MyAwesomeTextField&lt;/code&gt;, you have to change 4 times, the 2 files’ name, class’ name, and the subclass’ name in xib. Never happen in Programmatically.&lt;/p&gt;

&lt;h3&gt;
  
  
  Some libraries you can try
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/SnapKit/SnapKit"&gt;SnapKit&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/freshOS/Stevia"&gt;Stevia&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/roberthein/TinyConstraints"&gt;TinyConstraints&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And my favorite library is &lt;a href="https://github.com/nguyentruongky/knConstraints"&gt;knConstraints&lt;/a&gt;, a project learned style from TinyConstraints, developed with a new syntax and more advantages.&lt;/p&gt;

&lt;h1&gt;
  
  
  Conclusion
&lt;/h1&gt;

&lt;p&gt;This solution saves much time for me. I hope it can help you. Save time, work better and enjoy your life.&lt;/p&gt;

</description>
      <category>developerlife</category>
      <category>iosdeveloper</category>
      <category>lifebalance</category>
      <category>codeefficiently</category>
    </item>
    <item>
      <title>Hyperlink Label</title>
      <dc:creator>Nguyen Truong Ky</dc:creator>
      <pubDate>Mon, 27 Apr 2020 22:17:03 +0000</pubDate>
      <link>https://dev.to/nguyentruongky/hyperlink-label-56jn</link>
      <guid>https://dev.to/nguyentruongky/hyperlink-label-56jn</guid>
      <description>&lt;p&gt;Clickable Label is very popular in iOS, especially in Login, Register screen. You can easily see some text like this:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;By register, I agree to &lt;strong&gt;Terms of Service&lt;/strong&gt; and &lt;strong&gt;Private Policy&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This is how I make this label.&lt;/p&gt;

&lt;h1&gt;
  
  
  Define your texts
&lt;/h1&gt;

&lt;p&gt;Make sure the text you need to make clickable is exacly same to the full text.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;let termText = "By register, I agree to ... Terms of Service and Private Policy"
let term = "Terms of Service"
let policy = "Private Policy"
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h1&gt;
  
  
  Format the Label
&lt;/h1&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;let termLabel = UILabel()
let formattedText = String.format(strings: [term, policy],
                                    boldFont: UIFont.boldSystemFont(ofSize: 15),
                                    boldColor: UIColor.blue,
                                    inString: termText,
                                    font: UIFont.systemFont(ofSize: 15),
                                    color: UIColor.black)
termLabel.attributedText = formattedText
termLabel.numberOfLines = 0
let tap = UITapGestureRecognizer(target: self, action: #selector(handleTermTapped))
termLabel.addGestureRecognizer(tap)
termLabel.isUserInteractionEnabled = true
termLabel.textAlignment = .center
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;&lt;code&gt;String.format&lt;/code&gt; is an extension from my code collection. This is the full function.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;extension String {
    static func format(strings: [String],
                    boldFont: UIFont = UIFont.boldSystemFont(ofSize: 14),
                    boldColor: UIColor = UIColor.blue,
                    inString string: String,
                    font: UIFont = UIFont.systemFont(ofSize: 14),
                    color: UIColor = UIColor.black) -&amp;gt; NSAttributedString {
        let attributedString =
            NSMutableAttributedString(string: string,
                                    attributes: [
                                        NSAttributedStringKey.font: font,
                                        NSAttributedStringKey.foregroundColor: color])
        let boldFontAttribute = [NSAttributedStringKey.font: boldFont, NSAttributedStringKey.foregroundColor: boldColor]
        for bold in strings {
            attributedString.addAttributes(boldFontAttribute, range: (string as NSString).range(of: bold))
        }
        return attributedString
    }
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h1&gt;
  
  
  Handle Label Tap Gesture
&lt;/h1&gt;

&lt;p&gt;I get the tap location in the Label and check if this location belongs to term or policy text range.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@objc func handleTermTapped(gesture: UITapGestureRecognizer) {
    let termString = termText as NSString
    let termRange = termString.range(of: term)
    let policyRange = termString.range(of: policy)

    let tapLocation = gesture.location(in: termLabel)
    let index = termLabel.indexOfAttributedTextCharacterAtPoint(point: tapLocation)

    if checkRange(termRange, contain: index) == true {
        handleViewTermOfUse()
        return
    }

    if checkRange(policyRange, contain: index) {
        handleViewPrivacy()
        return
    }
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h1&gt;
  
  
  Supported code
&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;Check if a range contain an index
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;func checkRange(_ range: NSRange, contain index: Int) -&amp;gt; Bool {
    return index &amp;gt; range.location &amp;amp;&amp;amp; index &amp;lt; range.location + range.length
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Get index from a point in UILabel
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;extension UILabel {
    func indexOfAttributedTextCharacterAtPoint(point: CGPoint) -&amp;gt; Int {
        assert(self.attributedText != nil, "This method is developed for attributed string")
        let textStorage = NSTextStorage(attributedString: self.attributedText!)
        let layoutManager = NSLayoutManager()
        textStorage.addLayoutManager(layoutManager)
        let textContainer = NSTextContainer(size: self.frame.size)
        textContainer.lineFragmentPadding = 0
        textContainer.maximumNumberOfLines = self.numberOfLines
        textContainer.lineBreakMode = self.lineBreakMode
        layoutManager.addTextContainer(textContainer)

        let index = layoutManager.characterIndex(for: point, in: textContainer, fractionOfDistanceBetweenInsertionPoints: nil)
        return index
    }
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h1&gt;
  
  
  Demo
&lt;/h1&gt;

&lt;p&gt;And result is:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--PUAJy5gZ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://firebasestorage.googleapis.com/v0/b/blogs-1de93.appspot.com/o/assets%252Fhyperlink-label%252Fterm_demo.gif%3Falt%3Dmedia%26token%3D9cd27012-8f3f-4d42-adfd-c6fd45df6857" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--PUAJy5gZ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://firebasestorage.googleapis.com/v0/b/blogs-1de93.appspot.com/o/assets%252Fhyperlink-label%252Fterm_demo.gif%3Falt%3Dmedia%26token%3D9cd27012-8f3f-4d42-adfd-c6fd45df6857" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can download the source code &lt;a href="https://github.com/nguyentruongky/HyperlinkLabel"&gt;here&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Conclusion
&lt;/h1&gt;

&lt;p&gt;You can make a custom UILabel to be easier to reuse. I leave that for you. If you have any issues with this, let me know. &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Enjoy coding.&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>ios</category>
      <category>swift</category>
      <category>hyperlinklabel</category>
      <category>taplabel</category>
    </item>
    <item>
      <title>Customize your UITabBarController</title>
      <dc:creator>Nguyen Truong Ky</dc:creator>
      <pubDate>Sat, 25 Apr 2020 17:40:36 +0000</pubDate>
      <link>https://dev.to/nguyentruongky/customize-your-uitabbarcontroller-586n</link>
      <guid>https://dev.to/nguyentruongky/customize-your-uitabbarcontroller-586n</guid>
      <description>&lt;p&gt;From 2017, design trending has changed to tab bar, instead of slide menu. &lt;code&gt;UITabBarController&lt;/code&gt; has become one of the most popular controller. It’s very simple to use. But sometime, it’s too simple to customize and make attractive. Designers are artists, and they usually want tab bar like this&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--zjOtA-vj--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://firebasestorage.googleapis.com/v0/b/blogs-1de93.appspot.com/o/assets%252FtabController%252Fogenii.png%3Falt%3Dmedia%26token%3D033df77c-7adb-40a7-aca9-ad921efb4629" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--zjOtA-vj--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://firebasestorage.googleapis.com/v0/b/blogs-1de93.appspot.com/o/assets%252FtabController%252Fogenii.png%3Falt%3Dmedia%26token%3D033df77c-7adb-40a7-aca9-ad921efb4629" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;or like this&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--0UMOLV6G--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://firebasestorage.googleapis.com/v0/b/blogs-1de93.appspot.com/o/assets%252FtabController%252Fdoctor.png%3Falt%3Dmedia%26token%3De5a38fff-eddf-4863-b2bb-b4e15fdef4d2" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--0UMOLV6G--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://firebasestorage.googleapis.com/v0/b/blogs-1de93.appspot.com/o/assets%252FtabController%252Fdoctor.png%3Falt%3Dmedia%26token%3De5a38fff-eddf-4863-b2bb-b4e15fdef4d2" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I had to implement a tab bar like above in 2015. My implementation at that time was bad. I used a &lt;code&gt;UIViewController&lt;/code&gt; as a main controller, and added a custom view like a tab bar. And everytime a tab selected, embed the other &lt;code&gt;UIViewController&lt;/code&gt; into the main controller. That’s not good option.&lt;/p&gt;

&lt;p&gt;Today I make a &lt;code&gt;UITabBarController&lt;/code&gt; with a custom view like a tab bar. With this solution, we can use the max strength of &lt;code&gt;UITabBarController&lt;/code&gt; with the same behavior and code. Much easier and better than my implementation before. Hope anyone can easily customize to their design if they want after this note.&lt;/p&gt;

&lt;h2&gt;
  
  
  knTabBarItem
&lt;/h2&gt;

&lt;p&gt;First thing need to be customized is the &lt;code&gt;UITabBarItem&lt;/code&gt;. &lt;code&gt;UITabBarItem&lt;/code&gt; is not flexible enough to be customized to anything I want. I need to use &lt;code&gt;UIButton&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class knTabBarItem: UIButton {
    // (1)
    var itemHeight: CGFloat = 0
    // (2)
    var lock = false
    // (3)
    var color: UIColor = UIColor.lightGray {
        didSet {
            guard lock == false else { return }
            iconImageView.change(color: color)
            textLabel.textColor = color
        }}

    // (4)
    private let iconImageView = knUIMaker.makeImageView(contentMode: .scaleAspectFit)
    private let textLabel = knUIMaker.makeLabel(font: UIFont.systemFont(ofSize: 11),
                                        color: .black, alignment: .center)

    convenience init(icon: UIImage, title: String,
                    font: UIFont = UIFont.systemFont(ofSize: 11)) {
        self.init()
        translatesAutoresizingMaskIntoConstraints = false
        iconImageView.image = icon
        textLabel.text = title
        textLabel.font = UIFont(name: font.fontName, size: 11)
        setupView()
    }

    // (5)
    private func setupView() {
        addSubviews(views: iconImageView, textLabel)
        iconImageView.top(toView: self, space: 4)
        iconImageView.centerX(toView: self)
        iconImageView.square()

        let iconBottomConstant: CGFloat = textLabel.text == "" ? -2 : -20
        iconImageView.bottom(toView: self, space: iconBottomConstant)

        textLabel.bottom(toView: self, space: -2)
        textLabel.centerX(toView: self)
    }
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h3&gt;
  
  
  (1) (2) (3)
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Some tab items can be bigger than others. I can easily set the height for them to make difference with others.&lt;/li&gt;
&lt;li&gt;Some tab items are very unacceptional with different color and don’t change color when selected.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  (4)
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;knUIMaker is my collection to make controls. Just easier to make UIButton, UIImageView, UILabel by code.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  (5)
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;addSubviews&lt;/code&gt;, &lt;code&gt;top&lt;/code&gt;, &lt;code&gt;centerX&lt;/code&gt;, &lt;code&gt;bottom&lt;/code&gt; are from my &lt;a href="https://github.com/nguyentruongky/knConstraints"&gt;knConstraints&lt;/a&gt; to make auto layout. I’m a fan of auto layout programmatically, so make controls and set layouts by code is what to do hundreds times everyday.&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  knTabBar
&lt;/h1&gt;

&lt;p&gt;Next thing I have to focus on is &lt;code&gt;UITabBar&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class knTabBar: UITabBar {
    // (1)
    var kn_items = [knTabBarItem]()
    convenience init(items: [knTabBarItem]) {
        self.init()
        kn_items = items
        translatesAutoresizingMaskIntoConstraints = false
        setupView()
    }

    override var tintColor: UIColor! {
        didSet {
            for item in kn_items {
                item.color = tintColor
            }}}

    func setupView() {
        backgroundColor = .white
        if kn_items.count == 0 { return }

        // (2)
        let line = knUIMaker.makeLine(color: .gray, height: 0.5)
        addSubviews(views: line)
        line.horizontal(toView: self)
        line.top(toView: self)

        // (3)
        var horizontalConstraints = "H:|"
        let itemWidth: CGFloat = screenWidth / CGFloat(kn_items.count)
        for i in 0 ..&amp;lt; kn_items.count {
            let item = kn_items[i]
            addSubviews(views: item)
            if item.itemHeight == 0 {
                item.vertical(toView: self)
            }
            else {
                item.bottom(toView: self)
                item.height(item.itemHeight)
            }
            item.width(itemWidth)
            horizontalConstraints += String(format: "[v%d]", i)
            if item.lock == false {
                item.color = tintColor
            }
        }

        horizontalConstraints += "|"
        addConstraints(withFormat: horizontalConstraints, arrayOf: kn_items)
    }
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h3&gt;
  
  
  (1)
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;I can’t override &lt;code&gt;items&lt;/code&gt; in &lt;code&gt;UITabBar&lt;/code&gt;, so I name it a little bit similar to easier to remember&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  (2)
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Add a line to separate the tab bar to the controller. Some designs need indicator at the selected item, I will add indicator here.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  (3)
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Flexible to add items by programmatically. Thanks Apple for Auto Layout Programmatically.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  knTabController
&lt;/h2&gt;

&lt;p&gt;The easiest thing is here. Just inherit from &lt;code&gt;UITabBarController&lt;/code&gt;, add some code, and it works.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class knTabController: UITabBarController {
    var kn_tabBar: knTabBar!
    var selectedColor = UIColor.darkGray
    var normalColor = UIColor.lightGray {
        didSet {
            kn_tabBar.tintColor = normalColor
        }}

    private var kn_tabBarHeight: CGFloat = 49
    override func viewDidLoad() {
        super.viewDidLoad()
        tabBar.isHidden = true
        setupView()
    }

    func setupView() {}

    private func setTabBar(items: [knTabBarItem], height: CGFloat = 49) {
        guard items.count &amp;gt; 0 else { return }

        kn_tabBar = knTabBar(items: items)
        guard let bar = kn_tabBar else { return }
        kn_tabBar.tintColor = normalColor
        bar.kn_items.first?.color = selectedColor

        view.addSubviews(views: bar)
        bar.horizontal(toView: view)
        bar.bottom(toView: view)
        kn_tabBarHeight = height
        bar.height(kn_tabBarHeight)
        for i in 0 ..&amp;lt; items.count {
            items[i].tag = i
            items[i].addTarget(self, action: #selector(switchTab))
        }
    }

    @objc func switchTab(button: UIButton) {
        selectedIndex = button.tag
    }
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;That’s ready for new tab bar. Just use it in a controller.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to use?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Inherit class &lt;code&gt;knTabController&lt;/code&gt; to your controller.&lt;/li&gt;
&lt;li&gt;Override &lt;code&gt;setupView&lt;/code&gt; method.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class DoctorController: knTabController {
    override func setupView() {
        let home = knTabBarItem(icon: #imageLiteral(resourceName: "home"), title: "Home")
        let appointment = knTabBarItem(icon: #imageLiteral(resourceName: "appointment"), title: "Appointment")
        let add = knTabBarItem(icon: #imageLiteral(resourceName: "add"), title: "")
        add.lock = true
        add.itemHeight = 66
        let doctors = knTabBarItem(icon: #imageLiteral(resourceName: "doctors"), title: "Doctors")
        let porfolio = knTabBarItem(icon: #imageLiteral(resourceName: "user"), title: "Porfolio")

        let red = UIViewController()
        red.view.backgroundColor = .red
        let green = UIViewController()
        green.view.backgroundColor = .green
        let blue = UIViewController()
        blue.view.backgroundColor = .white
        let yellow = UIViewController()
        yellow.view.backgroundColor = .yellow
        let gray = UIViewController()
        gray.view.backgroundColor = .gray

        setTabBar(items: [home, appointment, add, doctors, porfolio])
        viewControllers = [red, green, blue, yellow, gray]
        normalColor = .red
    }
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Run and see. The main button (Hexagon Add) is locked, don’t change the color when selected.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--b4PR_o7d--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://firebasestorage.googleapis.com/v0/b/blogs-1de93.appspot.com/o/assets%252FtabController%252Fdoctor.gif%3Falt%3Dmedia%26token%3D27df3f84-5d39-499a-9205-43eaeea87515" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--b4PR_o7d--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://firebasestorage.googleapis.com/v0/b/blogs-1de93.appspot.com/o/assets%252FtabController%252Fdoctor.gif%3Falt%3Dmedia%26token%3D27df3f84-5d39-499a-9205-43eaeea87515" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It’s much better if we have animation.&lt;/p&gt;

&lt;h1&gt;
  
  
  Add animation
&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;In &lt;code&gt;knTabController&lt;/code&gt;, change method &lt;code&gt;switchTab&lt;/code&gt; content to
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;let newIndex = button.tag
changeTab(from: selectedIndex, to: newIndex)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Add method changeTab
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt; private func changeTab(from fromIndex: Int, to toIndex: Int) {
    kn_tabBar.kn_items[fromIndex].color = normalColor
    kn_tabBar.kn_items[toIndex].color = selectedColor
    animateSliding(from: fromIndex, to: toIndex)
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;And result:&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--P3lODlCN--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://firebasestorage.googleapis.com/v0/b/blogs-1de93.appspot.com/o/assets%252FtabController%252Fdoctor_slide.gif%3Falt%3Dmedia%26token%3D2b1a56d8-aacf-4d51-924e-a44d6827a99d" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--P3lODlCN--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://firebasestorage.googleapis.com/v0/b/blogs-1de93.appspot.com/o/assets%252FtabController%252Fdoctor_slide.gif%3Falt%3Dmedia%26token%3D2b1a56d8-aacf-4d51-924e-a44d6827a99d" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Conclusion
&lt;/h1&gt;

&lt;p&gt;Hope this can help anyone want to customize a tab bar can do it effortless. Code is &lt;a href="https://github.com/nguyentruongky/knTabController"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I will add some more animations and some properties to make it more convenience in very near future. Suggestions and feedbacks are welcome.&lt;/p&gt;

&lt;h1&gt;
  
  
  Notes
&lt;/h1&gt;

&lt;p&gt;I am a fan of Auto Layout Programmatically, so usually use my library, &lt;strong&gt;knConstraints&lt;/strong&gt; for setting constraints. &lt;strong&gt;knConstraints&lt;/strong&gt; is a very simple way to setup Auto Layout with very easy to read syntax. You can try it yourself &lt;a href="https://github.com/nguyentruongky/knConstraints"&gt;here&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>ios</category>
      <category>swift</category>
      <category>uitabbarcontroller</category>
      <category>uitabbar</category>
    </item>
    <item>
      <title>UI Implementation - Confirmation popup</title>
      <dc:creator>Nguyen Truong Ky</dc:creator>
      <pubDate>Sat, 25 Apr 2020 11:39:22 +0000</pubDate>
      <link>https://dev.to/nguyentruongky/ui-implementation-confirmation-popup-5f6f</link>
      <guid>https://dev.to/nguyentruongky/ui-implementation-confirmation-popup-5f6f</guid>
      <description>&lt;p&gt;In &lt;a href="https://dev.to/nguyentruongky/ui-implementation-popup-cio"&gt;previous post&lt;/a&gt;, I shared you how to show an animated popup, and explained how to customize your popup. In this post, I share how I use the popup in my projects with confirmation and information alert.&lt;br&gt;
An information popup is used to alert user about some important information, like this&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--RaPTEM1O--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://firebasestorage.googleapis.com/v0/b/blogs-1de93.appspot.com/o/assets%252F2018-10%252F2018-10-17-popup-1.PNG%3Falt%3Dmedia%26token%3D82348803-b152-4106-b781-7deb9abcb5d2" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--RaPTEM1O--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://firebasestorage.googleapis.com/v0/b/blogs-1de93.appspot.com/o/assets%252F2018-10%252F2018-10-17-popup-1.PNG%3Falt%3Dmedia%26token%3D82348803-b152-4106-b781-7deb9abcb5d2" width="30%"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A confirmation alert is very useful to warn user about next action, for instance, confirm to remove a photo, confirm a withdrawal request… In this post, I will extend the &lt;code&gt;knPopup&lt;/code&gt; to &lt;code&gt;knConfirmation&lt;/code&gt; to display a confirmation popup.&lt;/p&gt;

&lt;p&gt;The idea is same to the &lt;a href="https://dev.to/nguyentruongky/ui-implementation-popup-cio"&gt;previous post&lt;/a&gt;, you can customize any UI you want in &lt;code&gt;setupView&lt;/code&gt;.&lt;/p&gt;
&lt;h1&gt;
  
  
  Define new controls
&lt;/h1&gt;


&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class knConfirmation: knPopup {
    private let iconImgView = UIMaker.makeImageView()
    let titleLabel = UIMaker.makeLabel(font: UIFont.boldSystemFont(ofSize: 18),
                                    color: UIColor.darkGray, numberOfLines: 2,
                                    alignment: .center)
    let contentLabel = UIMaker.makeLabel(font: UIFont.systemFont(ofSize: 15),
                                    color: UIColor.lightGray, numberOfLines: 0,
                                    alignment: .center)
    private let stack = UIMaker.makeStackView()
    private let cancelButton = UIMaker.makeButton(titleColor: .darkGray,
                                        font: UIFont.systemFont(ofSize: 15),
                                        cornerRadius: 27,
                                        borderWidth: 1,
                                        borderColor: .darkGray)
    private let buttonStack = UIMaker.makeStackView(axis: .horizontal, distributon: UIStackView.Distribution.fill, alignment: UIStackView.Alignment.fill, space: 16)

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        setupView()
    }
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;A confirmation popup needs:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;1 icon (optional)&lt;/li&gt;
&lt;li&gt;2 labels: title (optional), content&lt;/li&gt;
&lt;li&gt;2 buttons: 1 for accept action, 1 for reject action (optional). We have &lt;code&gt;okButton&lt;/code&gt; in &lt;code&gt;knPopup&lt;/code&gt;, just need one more for reject action&lt;/li&gt;
&lt;li&gt;2 stack views: 1 to contain 2 buttons, 1 to contain all controls&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;
  
  
  Layout the view
&lt;/h1&gt;

&lt;p&gt;We will setup auto layout for all controls by code in &lt;code&gt;setupView&lt;/code&gt; function&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;override func setupView() {
    // (1)
    buttonStack.addViews(cancelButton, okButton)
    cancelButton.size(toView: okButton)
    okButton.vertical(toView: buttonStack)
    cancelButton.centerY(toView: okButton)

    // (2)
    let spaceView = UIMaker.makeView()
    spaceView.height(12)

    stack.addViews(iconImgView, titleLabel, contentLabel, spaceView, buttonStack)
    iconImgView.square(edge: 56)
    iconImgView.centerX(toView: stack)
    titleLabel.horizontal(toView: stack, space: 16)
    contentLabel.horizontal(toView: stack, space: 16)
    buttonStack.horizontal(toView: stack, space: 16)

    // (3)
    container.addSubview(stack)
    stack.fill(toView: container, space: UIEdgeInsets(top: 16, bottom: 16))

    okButton.addTarget(self, action: #selector(didSelectOK), for: .touchUpInside)
    cancelButton.addTarget(self, action: #selector(dismiss), for: .touchUpInside)
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2&gt;
  
  
  (1)
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;buttonStack&lt;/code&gt; is a &lt;code&gt;UIStackView&lt;/code&gt;, so we can’t &lt;code&gt;addSubviews&lt;/code&gt; as usual, but have to &lt;code&gt;addArrangedSubview&lt;/code&gt;. I extend to new function &lt;code&gt;addViews&lt;/code&gt; to shorten the name. :)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;buttonStack&lt;/code&gt; contains the button, so when you don’t need cancel button, you can remove it from &lt;code&gt;buttonStack&lt;/code&gt;, and &lt;code&gt;okButton&lt;/code&gt; automatically fill the &lt;code&gt;superView&lt;/code&gt;. That’s why I choose UIStackView for this UI.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  (2)
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;In stackView, you can’t change specific space between 2 views, so I did this trick. Insert a space view with a height I want.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  (3)
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;We need to add &lt;code&gt;stack&lt;/code&gt; to &lt;code&gt;container&lt;/code&gt;. The &lt;code&gt;container&lt;/code&gt; is setup to animate when appear/disappear. So we don’t need to care about animation anymore.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Dynamically display what you want
&lt;/h3&gt;

&lt;p&gt;Some popups, you need to show an icon to make it be colorful. Others don’t need title and cancel button. We will dynamically init what we want.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;init(icon: UIImage? = nil, title: String? = nil, content: String, okTitle: String? = nil, cancelTitle: String? = nil) {
    super.init(frame: .zero)
    set(icon: icon, title: title, content: content, okTitle: okTitle, cancelTitle: cancelTitle)
}

private func set(icon: UIImage? = nil, title: String? = nil, content: String, okTitle: String? = nil, cancelTitle: String? = nil) {
    if icon == nil {
        iconImgView.removeFromSuperview()
    } else {
        iconImgView.image = icon
    }

    if title == nil {
        titleLabel.removeFromSuperview()
    } else {
        titleLabel.text = title
    }

    contentLabel.text = content
    if okTitle != nil {
        okButton.setTitle(okTitle, for: .normal)
    }

    if cancelTitle == nil {
        cancelButton.removeFromSuperview()
    } else {
        cancelButton.setTitle(cancelTitle, for: .normal)
    }
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Just pass &lt;code&gt;nil&lt;/code&gt; or remove that param from the &lt;code&gt;init&lt;/code&gt; function. What param is nil, the related control will be removed from UI.&lt;/p&gt;

&lt;h1&gt;
  
  
  Run the app
&lt;/h1&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
    &lt;tr&gt;
       &lt;td&gt;
           &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--OBei2wlH--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://firebasestorage.googleapis.com/v0/b/blogs-1de93.appspot.com/o/assets%252F2018-10%252F2018-10-17-popup-3.png%3Falt%3Dmedia%26token%3D30d703b0-8215-4604-b400-785e96fcce92"&gt;
       &lt;/td&gt;
       &lt;td&gt;
            &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--9GUdd4LN--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://firebasestorage.googleapis.com/v0/b/blogs-1de93.appspot.com/o/assets%252F2018-10%252F2018-10-17-popup-4.png%3Falt%3Dmedia%26token%3D6a08ca01-b74f-4356-995d-9c535bb0450b"&gt;
       &lt;/td&gt;
    &lt;/tr&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h1&gt;
  
  
  Live sample
&lt;/h1&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
  &lt;tr&gt;
    &lt;td&gt;
&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--E0pdAIpU--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://firebasestorage.googleapis.com/v0/b/blogs-1de93.appspot.com/o/assets%252F2018-10%252F2018-10-17-popup-2.png%3Falt%3Dmedia%26token%3D8ef6dbcf-cc14-407e-afee-d71a9cd68240"&gt; 
&lt;/td&gt;
    &lt;td&gt;
&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Ooef-EBY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://firebasestorage.googleapis.com/v0/b/blogs-1de93.appspot.com/o/assets%252F2018-10%252F2018-10-17-popup-5.jpeg%3Falt%3Dmedia%26token%3D7efaec5f-406c-4c08-a74c-b2380ef55aaf"&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--uoOUBTnP--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://firebasestorage.googleapis.com/v0/b/blogs-1de93.appspot.com/o/assets%252F2018-10%252F2018-10-17-popup-6.jpeg%3Falt%3Dmedia%26token%3Dd7741048-4ffb-4912-a2fd-59273828bb6e"&gt;
&lt;/td&gt;
  &lt;/tr&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h1&gt;
  
  
  Conclusion
&lt;/h1&gt;

&lt;p&gt;Hope this popup can help you save your time and efforts to display a popup. Customize what you want and share it to me via this &lt;a href="https://github.com/nguyentruongky/knPopup"&gt;repository&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>popup</category>
      <category>ios</category>
      <category>swift</category>
      <category>alertview</category>
    </item>
    <item>
      <title>UI Implementation - Popup</title>
      <dc:creator>Nguyen Truong Ky</dc:creator>
      <pubDate>Fri, 24 Apr 2020 17:52:17 +0000</pubDate>
      <link>https://dev.to/nguyentruongky/ui-implementation-popup-cio</link>
      <guid>https://dev.to/nguyentruongky/ui-implementation-popup-cio</guid>
      <description>&lt;p&gt;Popup is not the best choice to notify users. It takes the users’ attention, and need action to remove popup. Sometimes, popup is a good selection. It displays on the same view, not change eyesight.&lt;/p&gt;

&lt;p&gt;Today, I will implement a popup, inspired by the design of &lt;a href="https://dribbble.com/shots/2391749-Referral-Window"&gt;Joseph Liu&lt;/a&gt;. Change something to make it simpler.&lt;/p&gt;

&lt;p&gt;This is how it looks after coding.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--7nMk7Agr--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://firebasestorage.googleapis.com/v0/b/blogs-1de93.appspot.com/o/assets%252F2018-10%252F2018-10-09-popup.gif%3Falt%3Dmedia%26token%3D53559318-3d67-47f0-a794-1f0bdc13b37d" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--7nMk7Agr--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://firebasestorage.googleapis.com/v0/b/blogs-1de93.appspot.com/o/assets%252F2018-10%252F2018-10-09-popup.gif%3Falt%3Dmedia%26token%3D53559318-3d67-47f0-a794-1f0bdc13b37d" alt="Final work"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Prepare project
&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;Create new &lt;code&gt;Single View App&lt;/code&gt; project&lt;/li&gt;
&lt;li&gt;Add new file &lt;code&gt;ReferralPopup.swift&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  Define components
&lt;/h1&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class ReferralPopup: knView {
    let blackView: UIButton = {
        let button = UIButton()
        button.translatesAutoresizingMaskIntoConstraints = false
        button.backgroundColor = UIColor.black.withAlphaComponent(0.5)
        return button
    }()
    let container: UIView = {
        let v = UIView()
        v.translatesAutoresizingMaskIntoConstraints = false
        v.backgroundColor = .white
        v.createRoundCorner(7)
        return v
    }()
    let okButton: UIButton = {
        let button = UIButton()
        button.translatesAutoresizingMaskIntoConstraints = false
        let color = UIColor.color(r: 241, g: 66, b: 70)
        button.backgroundColor = color
        button.setTitle("COPY &amp;amp; CONTINUE", for: .normal)
        button.backgroundColor = UIColor.color(r: 71, g: 204, b: 54)
        button.height(54)
        button.createRoundCorner(27)
        return button
    }()
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;blackView&lt;/code&gt; is the transparent background cover the whole screen. We will dismiss the popup when it clicked. You can use UIView and add UIGestureRecognizer also.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;container&lt;/code&gt; is the white background container. It’s the main view for popup.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  Layout the container
&lt;/h1&gt;

&lt;p&gt;The most important part is how to layout the container&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;override func setupView() {
    let color = UIColor.color(r: 241, g: 66, b: 70)

    let instruction = "GET YOUR FREE $10 CREDITS"
    let label = UIMaker.makeLabel(text: instruction,
                                  font: UIFont.boldSystemFont(ofSize: 15),
                                  color: .white,
                                  alignment: .center)

    let circle = UIMaker.makeView(background: color)
    let logo = UIMaker.makeImageView(image: UIImage(named: "swift"), contentMode: .scaleAspectFit)
    logo.backgroundColor = .white

    let codeTitle = UIMaker.makeLabel(text: "REFERRAL CODE",
                                      font: UIFont.boldSystemFont(ofSize: 12),
                                      color: UIColor.color(r: 155, g: 165, b: 172),
                                      alignment: .center)
    let codeLabel = UIMaker.makeLabel(text: "KYNGUYEN",
                                      font: UIFont.boldSystemFont(ofSize: 40),
                                      color: UIColor.color(r: 242, g: 64, b: 65),
                                      alignment: .center)


    container.addSubviews(views: circle, label, okButton, logo, codeTitle, codeLabel)

    // (1)
    label.top(toView: container, space: 24)
    label.horizontal(toView: container, space: 24)

    // (2)
    let edge: CGFloat = UIScreen.main.bounds.width * 2
    circle.square(edge: edge)
    circle.createRoundCorner(edge / 2)
    circle.centerX(toView: container)
    circle.bottom(toAnchor: logo.centerYAnchor)

    // (3)
    let logoEdge: CGFloat = 66
    logo.square(edge: logoEdge)
    logo.centerX(toView: circle)
    logo.verticalSpacing(toView: label, space: 40)
    logo.createRoundCorner(logoEdge / 2)
    logo.createBorder(1, color: color)

    // (4)
    codeTitle.centerX(toView: container)
    codeTitle.verticalSpacing(toView: logo, space: 24)

    // (5)
    codeLabel.centerX(toView: container)
    codeLabel.verticalSpacing(toView: codeTitle, space: 8)

    // (6)
    okButton.verticalSpacing(toView: codeLabel, space: 24)
    okButton.bottom(toView: container, space: -24)
    okButton.horizontal(toView: container, space: 36)
    okButton.createRoundCorner(28)

    okButton.addTarget(self, action: #selector(dismiss), for: .touchUpInside)
    blackView.addTarget(self, action: #selector(dismiss), for: .touchUpInside)
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The sketch is like this&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--RXgKzc_0--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://firebasestorage.googleapis.com/v0/b/blogs-1de93.appspot.com/o/assets%252F2018-10%252F09-popup-frame_explaination.png%3Falt%3Dmedia%26token%3De03f6b90-c6de-4dc0-a78b-2faf586ade15" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--RXgKzc_0--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://firebasestorage.googleapis.com/v0/b/blogs-1de93.appspot.com/o/assets%252F2018-10%252F09-popup-frame_explaination.png%3Falt%3Dmedia%26token%3De03f6b90-c6de-4dc0-a78b-2faf586ade15" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  (1)
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;label&lt;/code&gt; is the instruction label, created by my helper &lt;code&gt;UIMaker&lt;/code&gt;. It is sticked to the &lt;code&gt;container's topAnchor&lt;/code&gt; with 24px spacing. It should be sticked to &lt;code&gt;left&lt;/code&gt; and &lt;code&gt;right&lt;/code&gt;, and &lt;code&gt;textAlignment&lt;/code&gt; is center to prevent long text can break the UI.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Notes
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;top&lt;/code&gt;: layout the &lt;code&gt;view1's topAnchor&lt;/code&gt; to the &lt;code&gt;view2's topAnchor&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;horizontal&lt;/code&gt;: layout the &lt;code&gt;view1's leftAnchor&lt;/code&gt; to &lt;code&gt;view2's leftAnchor&lt;/code&gt; and &lt;code&gt;view1's rightAnchor&lt;/code&gt; to &lt;code&gt;view2's rightAnchor&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  (2)
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;circle&lt;/code&gt; is the top curve. You can use an image instead. The circle has &lt;code&gt;width&lt;/code&gt; and &lt;code&gt;height&lt;/code&gt; equal to &lt;code&gt;UIScreen.main.bounds.width * 2&lt;/code&gt;. It is bigger than the view so we can put its lower edge overlay on the &lt;code&gt;container&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Layout &lt;code&gt;circle&lt;/code&gt; horizonal center to the view, so the circle looks balance. You can try align to left or right to see differences.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The &lt;code&gt;circle&lt;/code&gt;’s bottom edge will align to the &lt;code&gt;logo&lt;/code&gt; center. A little bit difficult to understand. The &lt;code&gt;logo&lt;/code&gt; is sticked to the top, and &lt;code&gt;circle&lt;/code&gt; is sticked to the &lt;code&gt;logo&lt;/code&gt;. I set the &lt;code&gt;circle&lt;/code&gt; sticked to the &lt;code&gt;container&lt;/code&gt;’s top, but the view can’t auto layout. This way, &lt;code&gt;container&lt;/code&gt; can easy auto layout, we don’t need to care the &lt;code&gt;container&lt;/code&gt;’s height.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Notes
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;square(value: CGFloat)&lt;/code&gt;: set the &lt;code&gt;view's width&lt;/code&gt; equals to &lt;code&gt;view's height&lt;/code&gt; and equal to &lt;code&gt;value&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;centerX&lt;/code&gt;: stick &lt;code&gt;view1's centerXAnchor&lt;/code&gt; to &lt;code&gt;view2's centerXAnchor&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;bottom&lt;/code&gt;: layout &lt;code&gt;view1's bottomAnchor&lt;/code&gt; to &lt;code&gt;view2's bottomAnchor&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  (3)
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;logo&lt;/code&gt; has &lt;code&gt;verticalSpacing&lt;/code&gt; to &lt;code&gt;label&lt;/code&gt; and has 40px spacing. It means the &lt;code&gt;logo&lt;/code&gt;’s top and the &lt;code&gt;label&lt;/code&gt;’s bottom has 40px spacing.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Notes
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;verticalSpacing&lt;/code&gt;: layout &lt;code&gt;view1's topAnchor&lt;/code&gt; to &lt;code&gt;view2's bottomAnchor&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  (4), (5)
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Same to &lt;code&gt;codeTitle&lt;/code&gt; and &lt;code&gt;codeLabel&lt;/code&gt;, &lt;code&gt;verticalSpacing&lt;/code&gt; will make a space between them.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  (6)
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;okButton&lt;/code&gt; has &lt;code&gt;verticalSpacing&lt;/code&gt; and &lt;code&gt;bottom&lt;/code&gt;. So keep in mind, the view can automatically calculate the height of the view.&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  Display Popup
&lt;/h1&gt;

&lt;p&gt;The popup is ready to display. Let’s display it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;func show(in view: UIView) {
    addSubviews(views: blackView, container)
    blackView.fill(toView: self)
    container.centerY(toView: self)
    container.horizontal(toView: self, space: 24)

    blackView.alpha = 0
    UIView.animate(withDuration: 0.1, animations:
        { [weak self] in self?.blackView.alpha = 1 })
    container.zoomIn(true)

    view.addSubviews(views: self)
    fill(toView: view)
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;&lt;p&gt;We will display the popup inside the controller’s view. Rememeber 3 views: &lt;code&gt;blackView&lt;/code&gt;, &lt;code&gt;container&lt;/code&gt;, &lt;code&gt;self&lt;/code&gt;. We will add &lt;code&gt;blackView&lt;/code&gt; and &lt;code&gt;container&lt;/code&gt; to &lt;code&gt;self&lt;/code&gt;. And we add &lt;code&gt;self&lt;/code&gt; to &lt;code&gt;containerView&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;view.zoomIn(true)&lt;/code&gt; will show the popup with a slight zoom animation.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  Dismiss popup
&lt;/h1&gt;

&lt;p&gt;Quite hard here for dismiss animation. The popup zooms in a little bit and zooms out to disappear.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@objc func dismiss() {
    let initialValue: CGFloat = 1
    let middleValue: CGFloat = 1.025
    let endValue: CGFloat = 0.001
    func fadeOutContainer() {
        UIView.animate(withDuration: 0.2, animations:
            { [weak self] in self?.container.alpha = 0 })
    }
    func zoomInContainer() {
        UIView.animate(withDuration: 0.05,
                       animations: { [weak self] in self?.container.scale(value: middleValue) })
    }
    func zoomOutContainer() {
        UIView.animate(withDuration: 0.3, delay: 0.05, options: .curveEaseIn,
                       animations:
            { [weak self] in
                self?.container.scale(value: endValue)
                self?.blackView.alpha = 0
            }, completion: { [weak self] _ in self?.removeFromSuperview() })
    }

    container.transform = container.transform.scaledBy(x: initialValue , y: initialValue)
    fadeOutContainer()
    zoomInContainer()
    zoomOutContainer()
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h1&gt;
  
  
  Time to run
&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;Add a button to &lt;code&gt;ViewController&lt;/code&gt; and show the popup in the button event
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@objc func showReferralPopup() {
    ReferralPopup().show(in: view)
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h1&gt;
  
  
  Do it better
&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;You can add new class &lt;code&gt;Popup&lt;/code&gt; and move components, full &lt;code&gt;show&lt;/code&gt; function, full &lt;code&gt;dismiss&lt;/code&gt; function and empty &lt;code&gt;setupView&lt;/code&gt; to &lt;code&gt;Popup&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;ReferralPopup&lt;/code&gt; is inherited from &lt;code&gt;Popup&lt;/code&gt;. You can add new popup easily just set inherit from &lt;code&gt;Popup&lt;/code&gt; and layout your new view in its &lt;code&gt;setupView&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Full code can pull from &lt;a href="https://github.com/nguyentruongky/knPopup"&gt;my Github&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>message</category>
      <category>popup</category>
      <category>ios</category>
      <category>swift</category>
    </item>
  </channel>
</rss>
