Quantcast
Channel: Kodeco | High quality programming tutorials: iOS, Android, Swift, Kotlin, Unity, and more
Viewing all 4400 articles
Browse latest View live

Video Tutorial: Server Side Swift with Vapor Part 1: HTTP Basics


New Course: Server Side Swift with Vapor

$
0
0

Server Side Swift with Vapor

Have you ever wanted to write your own back-end services, but didn’t know where to start? Do you love Swift and wish you could use it everywhere?

If so, my new course, Server Side Swift with Vapor, is for you!

In this 30-video course, you’ll use Vapor, a server-side Swift web framework, to create a complex application that you can talk to via an API and a website. Let’s have a look at what’s inside.

Part 1: Getting Started with Vapor

In part one, you’ll build your first Vapor application.

  1. Introduction: Get acquainted with Vapor and review what you’ll be learning throughout this course.
  2. Hello, World: Create your first Vapor app by installing the Vapor toolbox and building your first routes.
  3. HTTP Basics: Find out how HTTP works, how requests and responses work, and learn about the different methods and status codes.
  4. Accepting Data: Learn how to accept data in your Vapor applications and parse it with Codable.
  5. Challenge: Create Your Own Routes: Challenge time! You will be tasked with creating your own routes, using all the skills learnt in the previous videos.
  6. Conclusion: Review what you have learnt in the section and see what will be coming up in the next section.

Part 2: Creating an API

In the second part, you’ll learn to create data models with Fluent.

  1. Introduction:  Let’s review what we are going to cover in this section and also learn about what Fluent is and how Async works and why it is important.
  2. Models and Fluent:  Create models using Fluent and configure your databases.
  3. Controllers and CRUD:  Learn how to create controllers to organise routes and how to save and retrieve models using Fluent.
  4. Finishing CRUD:  Retrieve individual models in Fluent using parameters and learn how to update and delete models using Fluent.
  5. Challenge: Users and Categories:  Time to put all of your new knowledge to the test and create your own models and controllers.
  6. Parent-Child Relationships:  Set up parent-child relationships in Fluent and how to query models for the parent-child relationships.
  7. Sibling Relationships:  Set up sibling relationships in Fluent and how to set up queries to retrieve model’s siblings.
  8. Fluent Queries:  Learn how to take advantage of Fluent to perform powerful queries on your databases.
  9. Persisting Data with MySQL:  Setup your Vapor application to use MySQL as a database, using Docker, so your data is persisted.
  10. Conclusion:  Review what you have learnt in the section and see what will be coming up in the next section.

Part 3: Templating with Leaf

Use Leaf to create powerful templates and build a web application in this part of the course.

  1. Introduction:  Let’s review what we are going to learn in the section and have a quick look at Leaf and why it is useful.
  2. Getting Started with Leaf:  Learn how to integrate Leaf into your application and start injecting data into Leaf templates.
  3. Powerful Templates:   Learn how to build powerful templates using for loops and if expressions to generate HTML.
  4. Embedding Templates:  Learn how to take full advantage of Leaf and embed templates in other templates to reduce duplication.
  5. Beautifying Our App:  Learn how to integrate the Bootstrap framework into our application to provide easy styling.
  6. Challenge: Users and Categories:  Put all of your Leaf skills to the test and create your own pages.
  7. Creating Acronyms:  Learn how to send data with web forms and accept the data back in our Vapor application to create models.
  8. Edit and Delete Acronyms:  Learn how to reuse templates to edit models and learn how to delete models on the web.
  9. Conclusion:  Review what you have learnt in this section and see what will be coming up in the next section.

Part 4: Authentication

Try out different kinds of authentication in the final part of the course.

  1. Introduction: Let’s review what we are going to learn in the section and have a quick look at the different types of Authentication and passwords.
  2. Passwords: Change your user models to allow authentication with passwords and create a token model.
  3. API Authentication: Protect APIs with authentication using both HTTP Basic Authentication and Token Authentication.
  4. Web Authentication: Protect web pages with authentication using sessions and cookies.
  5. Conclusion: Review what you have learnt in both this section and throughout the course.

We’re Writing a Book, Too!

We’re writing a book about using Vapor 3 that goes beyond what’s covered in this course. We’ve only started, but we’ve opened up pre orders so that you can get a sweet discount on the book and be among the first to receive the early-access digital edition of the book when it’s ready!

Pre-Order the Server Side Swift with Vapor Book

Where To Go From Here?

Want to check out the course? You can watch the entire first part for free!

The rest of the course is for raywenderlich.com subscribers only. Here’s how you can get access:

  • If you are a raywenderlich.com subscriber: The first three videos are ready for you today! The rest of the course will be released over the next few weeks. You can check out the course here.
  • If you are not a subscriber yet: What are you waiting for? Subscribe now to get access to our new Server Side Swift with Vapor course and our entire catalog of over 500 videos.

Stay tuned for more new and updated courses to come. I hope you enjoy the course! :]

The post New Course: Server Side Swift with Vapor appeared first on Ray Wenderlich.

UIVisualEffectView Tutorial: Getting Started

$
0
0
Update note: This tutorial has been updated to iOS 11 and Swift 4 by Evan Dekhayser. The original tutorial was written by Ryan Nystrom.

UIVisualEffectView Tutorial: Getting Started

Ever since the design of iOS dramatically changed in iOS 7, blurs have played an important part in app design. When used appropriately, blurs can significantly improve the usability and appearance of your apps.

Let’s take a look at how Apple uses blurs at a system level. One of the most notable examples is in Control Center. The blurred background preserves the context of the action – Control Center is not its own app, but a panel shown above the active app.

Notification Center uses this effect as well, but rather than blurring the entire background, each Notification Center extension or notification has its own blurred background. Besides simply looking beautiful, this blur helps each element stand out just the right amount.

UIVisualEffectView tutorial

So how do you recreate these types of blurs in your own apps? Use the built-in UIVisualEffectView! In this UIVisualEffectView tutorial, you are going to learn everything you need to know to make your apps stand out using blurs.

Clear Facts on Blurs

Executing blurs in a tasteful – and efficient – manner takes a bit of finesse. In this section, you’ll learn about a common algorithm used to create a blurring effect.

How Blurs Work

All blurs start with an image. To achieve a blur, you apply a blurring algorithm to each pixel in the image; the resulting image then contains an evenly blurred version of the original image. Blurring algorithms vary in style and complexity, but in this section we’ll examine a common algorithm known as Gaussian blur.

Blurring algorithms generally examine each pixel of an image and use the surrounding pixels to calculate new color values for that pixel. For example, consider the following theoretical image grid:

blur-how1

Each cell in the above grid represents an individual pixel, and each pixel has a value between 1 and 10. Consider the case where the algorithm is evaluating the center pixel. The algorithm averages the values of the surrounding pixels and inserts this averaged value into the center pixel, resulting in the following new pixel grid:

blur-how2

You then repeat this process for every pixel in the original image.
The sample algorithm above only examined one pixel in each direction to create the new averaged value. You can expand this blur radius even further to increase the amount of blurring in your image, as demonstrated in the image below:

3px and 16px Gaussian Blur applied to an image

3px and 16px Gaussian Blur applied to an image

Note: Generally, the greater the blur radius, the greater the processing power required to process the image. iOS offloads most image processing activities to the GPU to keep the main thread free.

Blur Design Strategies

Humans have a tendency to pay attention to elements that are in-focus and ignore those that aren’t. Believe it or not, this is a natural consequence of how our eyes work. Focusing on an object as it moves closer or further away from the eye is known as accommodation; it’s what helps you perceive the depth and distance of objects around you.

App designers exploit this fact and blur unimportant items on the screen to direct the user’s attention to the remaining non-blurred elements, as demonstrated in this screenshot of the popular Twitter client Tweetbot:

The user interface in the background is barely recognizable in the image above. This provides contextual awareness to the user about where they are in the navigational hierarchy. For instance, you’d expect to return to the blurred-out view in the background once you select one of the accounts displayed.

Note: Be careful about the overuse of blurs in your mobile apps. Although blurs can provide great-looking effects, they can be distracting and annoying if used inappropriately or too often.

Follow the standard design approach to use blurs to direct a user’s attention to things that matter and you’ll seldom go wrong. See the Designing for iOS section of the iOS Human Interface Guidelines document found on Apple’s iOS developer center for more on this subject.

Getting Started

To learn how to implement blurring, you’ll add some blur effects to a brand new Brothers Grimm fairytale app – aptly named Grimm.

The app displays a library of fairytales to the user. When the user taps on a fairytale, the app presents the full story on screen. The user can customize the display font, text alignment, or even the color theme for daytime or nighttime reading.

Start by downloading the starter project, then open Grimm.xcodeproj in Xcode. Open Main.storyboard and take a look at the view controllers contained in the app as illustrated below:

You can ignore the very first view controller in the image above as it’s simply the root navigation controller of the app. Taking each numbered view controller in turn, you’ll see the following:

  1. The first view controller is StoryListController, which displays a list of all of the fairy tales in the database.
  2. Tapping a story in the list segues the user to StoryViewController, which displays the title and text of the selected fairy tale.
  3. OptionsController is contained within StoryViewController and displays the available font, text alignment, and color options. To display it, simply tap the top-right ellipses icon in the detail controller.

Build and run. You’ll see the initial screen as shown below:

Have some fun exploring the app; select different stories, tap the ellipsis icon and swipe to different fonts and reading modes to understand how the user interface functions.

Once you have a handle on how the app behaves, head straight to the next section to learn how to apply blur effects to the app.

Blur Effects using UIVisualEffectView

UIKit provides an entire suite of visual effects goodies. UIBlurEffect, a subclass of UIVisualEffect, is particularly relevant to your interests. UIBlurEffect provides the nice blurs you see in navigation bars, Notification Center, and Control Center – and you can use it in your apps as well.

Adding a UIBlurEffect

In this project, you will use blur to make the OptionsController stand out on top of the story. Let’s jump right in!

Open OptionsController.swift and add the following code to the end of viewDidLoad:

// 1
view.backgroundColor = .clear
// 2
let blurEffect = UIBlurEffect(style: .light)
// 3
let blurView = UIVisualEffectView(effect: blurEffect)
// 4
blurView.translatesAutoresizingMaskIntoConstraints = false
view.insertSubview(blurView, at: 0)

Taking each numbered comment in turn:

  1. In order for the UIVisualEffectView to actually blur the content, its superview must be transparent. To do this, you change the background color to be clear.
  2. Create a UIBlurEffect with a UIBlurEffectStyle.light style. This defines what style of blur is used. The other available styles are .extraLight and .dark, .extraDark, regular, and prominent.
  3. Create a UIVisualEffectView with the blur you just created. This class is a subclass of UIView; its sole purpose is to define and display complex visual effects.
  4. Disable translating the auto-resizing masks into constraints on the blurView — you’ll manually add constraints in just a moment — and add it at the bottom of the view stack. If you just added blurView on top of the view, it would end up blurring all of the controls underneath it instead!

Now you need to ensure your blurView is laid out properly with the rest of the view.

Add the following code to the end of viewDidLoad:

NSLayoutConstraint.activate([
  blurView.heightAnchor.constraint(equalTo: view.heightAnchor),
  blurView.widthAnchor.constraint(equalTo: view.widthAnchor),
  ])

These constraints keep the frame of the blurView consistent with that of the OptionsController view.

Build and run. Select a fairy tale, tap the ellipsis button, and then scroll the text. Behold as the blur updates in real-time.

OptionsController with applied UIVisualEffectView

You now have a dynamic blur effect in your app that was not only easy to implement but looks great too.

Adding Vibrancy to your Blur

Blur effects are great – but as usual, Apple has taken it to the next level with UIVibrancyEffect, which when used in combination with UIVisualEffectView adjusts the colors of the content to make it feel more vivid.

The following image demonstrates how vibrancy makes your labels and icons pop off the screen, while at the same time blending with the background itself:

vibrancy

The left side of the image shows a normal label and button, while the right side shows a label and button with vibrancy applied.

Note: UIVibrancyEffect must be added to the contentView of a UIVisualEffectView that has been set up and configured with a UIBlurEffect object; otherwise, there won’t be any blurs to apply a vibrancy effect to!

Open OptionsController.swift and add the following code to the end of viewDidLoad:

// 1
let vibrancyEffect = UIVibrancyEffect(blurEffect: blurEffect)
// 2
let vibrancyView = UIVisualEffectView(effect: vibrancyEffect)
vibrancyView.translatesAutoresizingMaskIntoConstraints = false
// 3
vibrancyView.contentView.addSubview(optionsView)
// 4
blurView.contentView.addSubview(vibrancyView)

Taking each numbered comment in turn:

  1. Create a UIVibrancyEffect that uses the blurEffect you set up earlier. UIVibrancyEffect is another subclass of UIVisualEffect.
  2. Create a UIVisualEffectView to contain the vibrancy effect. This process is exactly the same as creating a blur. Since you’re using Auto Layout, you make sure to disable auto-resizing translations here.
  3. Add optionsView as a subview of your vibrancy view’s contentView; this ensures the vibrancy effect will be applied to the view that contains all of the controls.
  4. Finally you add the vibrancy view to the blur view’s contentView to complete the effect.

Next, you need to set up the Auto Layout constraints for the vibrancy view so that it has the same dimensions as the blur view, and for the options view to be centered in the vibrancy view.

Add the following constraints at the end of viewDidLoad:

NSLayoutConstraint.activate([
  vibrancyView.heightAnchor.constraint(equalTo: blurView.contentView.heightAnchor),
  vibrancyView.widthAnchor.constraint(equalTo: blurView.contentView.widthAnchor),
  vibrancyView.centerXAnchor.constraint(equalTo: blurView.contentView.centerXAnchor),
  vibrancyView.centerYAnchor.constraint(equalTo: blurView.contentView.centerYAnchor)
  ])

NSLayoutConstraint.activate([
  optionsView.centerXAnchor.constraint(equalTo: vibrancyView.contentView.centerXAnchor),
  optionsView.centerYAnchor.constraint(equalTo: vibrancyView.contentView.centerYAnchor),
  ])

There’s one thing you have left to do before this will work. If you look at the beginning of viewDidLoad, you already added optionsView as a subview – and views can only have a single superview.

At the beginning of viewDidLoad, comment out the following code:

view.addSubview(optionsView)

NSLayoutConstraint.activate([
  view.centerXAnchor.constraint(equalTo: optionsView.centerXAnchor),
  view.centerYAnchor.constraint(equalTo: optionsView.centerYAnchor)
  ])

Build and run. Bring up the options view to see your new vibrancy effect in action:

Light-styled UIVisualEffectView with Vibrancy on

Unless you have high-contrast vision, the vibrancy effect makes it really difficult to read the labels and controls. What’s going on?

Ah – the content behind the blur view is light and you’re applying a UIBlurEffectStyle.light effect. That’s counterproductive, to be sure.

Modify the line near the top of viewDidLoad that initializes the blurEffect:

let blurEffect = UIBlurEffect(style: .dark)

This changes the blur effect to add more contrast between the background and text.

Build and run. You’re now experiencing some true vibrancy:

Dark-styled UIVisualEffectView with Vibrancy on

Accessibility

When it comes to blurs, there is one last thing you need to consider: what if the user has blurs disabled?

In the simulator or on your device, open the Settings app and go to General\Accessibility\Increase Contrast, and enable Reduce Transparency. Go back to the app, and open the options view once again.

Well, that isn’t going to work at all! In this situation, going back to what you started out with is a better alternative.

Luckily, you can check if this accessibility setting is enabled using UIAccessibilityIsReduceTransparencyEnabled(). If you know that this setting is enabled, you can change the way your app looks and behaves.

Using the code you commented out before, add the following right before you set the view’s background color in viewDidLoad:

guard UIAccessibilityIsReduceTransparencyEnabled() == false else {
  view.addSubview(optionsView)

  NSLayoutConstraint.activate([
    view.centerXAnchor.constraint(equalTo: optionsView.centerXAnchor),
    view.centerYAnchor.constraint(equalTo: optionsView.centerYAnchor)
    ])

  return
}

This code checks to see if Reduce Transparency is enabled. If it is, you ignore all the code you just wrote and go back to the original layout without any blurring.

Build and run the app, and you’ll see that the options menu looks normal once again.

Where to Go From Here?

You can download the finished project here.

You’ve seen how images can be blurred, as well as how to create real-time blur effects using UIVisualEffectView. You can just as easily add advanced blur effects to your own app! There’s many more effects and options you could dive in to, and the best place to continue your exploration would be in Apple’s official UIVisualEffectView documentation.

UIVisualEffectViews update in real-time, so you can achieve all sorts of weird and wonderful things with these effects. While you might be tempted to go ahead and blur all the things, keep in mind what was discussed earlier in the tutorial regarding using these effects sparingly and only where appropriate. As is often the case, with blur and vibrancy, less is definitely more.

If you have any questions or comments about this UIVisualEffectView tutorial or visual effects in general, please join the forum discussion below!

The post UIVisualEffectView Tutorial: Getting Started appeared first on Ray Wenderlich.

Video Tutorial: Server Side Swift with Vapor Part 1: Accepting Data

Android Architecture Components: Getting Started

$
0
0

Android Architecture Components: Getting Started

Android and the Android SDK have improved a great deal over the years. We’ve received major API upgrades and additions. The UI has changed completely throughout the versions. However, some aspects of the SDK are still challenging, and can leave us with quite a headache.

An example headache is the Android application lifecycle. More often than not it follows the Uncertainty Principle. When you’re not paying attention, it works just like you want it to. But when you’re relying on it, it tends to work its own way. :[

Another issue, which goes along tightly with the lifecycle, is app architecture. Even though Android architecture changes faces about as often as Arya Stark does, the same issues usually remain. Namely, data flow problems, persistence, and stability. But how do you tackle these without complicating your code base?

Believe it or not, you’re now finally able to build a stable architecture in Android. It only took 9 years! And you don’t have to hack, complicate things, or build it yourself! You can do this by using the awesome Android Architecture Components framework from Google.

In this tutorial, you’ll dive into the vast world of Android Architecture Components, model your use case, and build an app to back it all up. In doing so, you’ll learn:

  • Some of the primary Android Architecture Components and why they exist
  • How to structure your app to conform to Model-View-ViewModel (MVVM)
  • How to observe data in a safe way

Note: This Android Architecture Components overview assumes that you’re familiar with the basics of Android development and application structuring. If you’re new to Android, please check out our Beginner Android series and other Android tutorials.

Getting Started

In a little bit, you’ll download the starter project and dive into code. I know you’re hungry for some Kotlin, but you’ll understand the code and logic much better if you learn about the Android Architecture Components in theory first. :]

We’ll be covering Lifecycle, LiveData, and ViewModel, but leaving other Android Architecture Components such as Room for other tutorials.

Lifecycle: Cycling

Android Architecture Components encapsulate three major architectural aspects of app development. And they’ve made way for a new style of application structuring. Even more so, they address issues of stability, data persistence and flow in a very serious manner. With this in mind, we will likely see the quality of Android apps grow in the future like wildfire.

But enough talk: you’re due for an example! Let’s start off with one of the most important concepts, the Lifecycle.

You’ve more likely than not seen the lifecycle graph for activities and fragments. It’s a bit of a mess when you first look at it, isn’t it? Most bad things happen when we do something in the incorrect app state. If something like this popped into your head:

java.lang.IllegalStateException: Can not perform this action after onSaveInstanceState

then you know how frustrating it can be when you forget to unsubscribe a request. To make the Android world a little more crash-free, Google’s built Lifecycle.

It branches out to three concepts, Lifecycle LifecycleObserver, and LifecycleEvent. As a result, you can act on state changes from lifecycle you’re in by annotating methods. This means you can shoot out requests, and update the UI, knowing you’re in safe state.

You might say: “It seems pointless, why don’t I use onCreate or onStart to handle state?”. Well, the Android lifecycle is about as stable as a chair with two legs, so the callbacks don’t provide much safety. So for the most part you’re right, but in some cases callbacks aren’t either accessible or enough.

Have a look at the following example:

class MyLocationListener(private val lifecycle: Lifecycle) : LifecycleObserver {

  @OnLifecycleEvent(Lifecycle.Event.ON_START)
  fun start() {
    if (lifecycle.currentState.isAtLeast(Lifecycle.State.STARTED)) {
      // connect if not connected
    }
  }

  @OnLifecycleEvent(Lifecycle.Event.ON_STOP)
  fun stop() {
    // disconnect if connected
  }
}

Often we need user location updates. But if the user leaves our app, we should stop listening to save data and battery. In fact Lifecycle tells us when it’s safe to listen, and when it isn’t. Moreover, we don’t have to create custom listeners for onStart and onStop events.

To sum up, we’ve seen how this basic yet powerful concept can make our life easier. We’ve seen how easy it is to replace horrid listeners with a LifecycleObserver in our existing code. But we still haven’t addressed the issue of supplying data to the UI!

LiveData: It’s Aliiiiiive!

Continuing in the same spirit, look at another common scenario:

override fun onFailure(call: Call<BeersResponse>?, t: Throwable?) {
  view.hideLoading()
  view.showNoData()
  ...
}

This is a situation we often face, receiving an error from the backend. Of course, we need to handle errors, but how do we do this in a clean way?

In the case that we have a View that displays an error, it is crucial to have both show() and hide() methods for the error. Although this might seem OK, we’re adding methods to the View. Furthermore, the business logic layer shouldn’t know what the view can do and what happens on the UI.

Also, this makes you write a ton of boilerplate interfaces and method declarations for each screen. You know how painstaking that can be. But, once again, Architecture Components save the day. This time featuring LiveData!

What is LiveData made of? Other than sweets and magical essence, it’s basically just an Observable value that is also Lifecycle aware. Quite simple in it’s nature, yet very powerful. It is aware of the app state. So if you do go into background, but your response decides to arrive anyway, the data value is set, but not emitted. Once you’re back in the positive state of mind (read onStart) the data is sent, and the UI gets updated.

The main difference to the typical approach of requesting data from an API is that the UI subscribes to the data, and then knows what to do with it when it arrives. The business logic layer no longer imperatively says what to do.

Although it might seem that you’re moving logic from the business layer into the view, that’s not the case. In reality, all the view knows is that there is data to listen to. You’ll achieve it by subscribing this Lifecycle to a LiveData object.

Since our business logic doesn’t tell the UI what to do, we’ve achieved a nice separation of concerns. That will help us unit test our app. You’ll see how this separation is done later on in the sample project.

ViewModel: Modelling Gig

Luckily I’m not talking about fashion models, it’s not really my strong suit. The type of models we’ll be confronting are ViewModels!

In order to understand them we’ll go through an example in the sample project. For now, you need to know ViewModels are persistent throughout a Lifecycle scope. Meaning, if you create it in an Activity, as long as the Activity lives in the stack, so does the ViewModel. Knowing this, we can create a ViewModel in Activity scope, and use it in multiple Fragments, effectively sharing data between them.

Activities and fragments are owners of a Lifecycle, as they implement the LifecycleOwner interface. This means they can provide their instance of Lifecycle when asked.

Also, calling for ViewModel instances will always return the Lifecycle bound instance. They even persist through orientation changes! So, by combining LiveData with ViewModels, you have data persistence such as for the savedInstanceState. This will save you from tons of crashes!

You’ve survived my excruciatingly long introduction, way to go! :]

One Project to Implement Them All

In order to show you the full extent of Android Architecture Components, we’ve created a sample project. Also, we’ve found a real life example to make each component as clear as possible. Shall we begin?

Start off by downloading the sample starter project here. Open the project in Android Studio 3.0.1 or greater and build and run to make sure all is well:

Starter app

Let’s go over the project structure, which you can see is modular by package. The api and interaction packages are part of the model layer, the connection to backend. The di package contains, well – the dependency injection setup! The rest should be pretty self explanatory, with ui containing Android specific files and models containing our data classes. We’ve also added all of the needed dependencies to Gradle and separated them a bit for better understanding.

You’re using Retrofit for network requests, Glide for image loading, and Dagger for dependency injection.

The model classes look as follows:

data class Beer(val name: String = "",
                val style: BeerStyle = BeerStyle(),
                val labels: BeerLabels = BeerLabels())

data class BeerLabels(val large: String = "",
                      val medium: String = "")

data class BeerStyle(val name: String = "")

data class BeerResponse(@SerializedName("data") val beers: List<Beer>,
                        val currentPage: Int)

The labels contain your beer images so you can see what you drink. You’ll also display the beer name, and a style. The beer response models the beer data coming back from the API.

The ViewHolders to display the beers are also prepared for you in the starter project, and they’re fairly simple:

class BeerHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {

  fun showBeer(beer: Beer): Unit = with(itemView) {
    beerStyle.text = beer.style.name
    beerName.text = beer.name

    val mediumImage = beer.labels.medium
    val largeImage = beer.labels.large

    // load whichever image exists
    Glide.with(itemView).load(if (largeImage.isNotBlank()) {
      largeImage
    } else {
      mediumImage
    }).into(beerImage)
  }
}

Since we’re using Kotlin Android Extensions, we don’t have to manually initialize Views using findViewById.

Waiter, I’ll have a beer please :]

We’ve chosen the best sample app purpose we could: beer drinking! However, beers don’t magically appear in your hands (sadly). You must first create an application at the BreweryDB. Create a new account, if you haven’t got one already.

Create BreweryDB account

Go to the Developers page, and click “Start Developing Now”. Next, accept the license to sell your soul to the Beer Gods:

BreweryDB TOS

Finally, create an API key to use in your requests by clicking “Register A New App” and giving your app the name BottomsUp:

BreweryDB Register New App

You should see your app now, with the API key:

BreweryDB API Key

It may take a day or two for BreweryDB to approve your app, so you’ll see a “Pending Activation” message on the app screen. Calls to the API won’t work until the app is approved.

Since our app is simple, you can store your new key at the end of AppConstants.kt:

const val API_KEY = "your-api-key"

If this were a production app, you’re advised you to keep the key in a safe environment.

Mmmmm Beer

Hitchhiking Through Components

While 42 may be the answer to what life is about, this app will be about a reactive, lifecycle aware structure. You’ve got a backend now, and most of the core setup, but you need to integrate the Architecture Components. With LiveData you will make the UI update on data changes. ViewModel will make the requests survive orientation changes. Additionally, you’ll safely execute requests in the proper app state thanks to Lifecycle.

You’ll start off by requesting beers from the backend API. Then you’ll supply the ViewModel‘s LiveData mini cooler with said beers. And last but not least, you’ll provide the view with a cold one from the ViewModel by letting it subscribe to LiveData changes.

Building your ViewModel

Start by creating a viewmodel package in the app root. Then create a BeersViewModel class, which extends ViewModel, in the package:

class BeersViewModel : ViewModel() {
}

Your ViewModel needs a reference to the BreweryInteractor prepared in the starter project. Do this by adding a lazily computed value named interactor, at the top of the class, provided by the AppComponent from the application subclass App:

private val interactor by lazy { App.component.breweryInteractor() }

Next, you need to request beers from the interactor. For now, add a method getBeers() to request the first page of beers, and add a callback in your ViewModel just under the variable declarations:

fun getBeers() {
  interactor.getBeers(1, beersCallback())
}

private fun beersCallback() = object : Callback<BeerResponse> {
  override fun onFailure(call: Call<BeerResponse>?, t: Throwable?) {
  }

  override fun onResponse(call: Call<BeerResponse>?, response: Response<BeerResponse>?) {
  }
}

When prompted to import classes such as Code or Response, be sure to use the Retrofit2 classes.

Now you have everything a ViewModel needs, except for LiveData (which you’ll add below)! :]

One last thing you need to do before you move on to LiveData is add the ViewModel to the top of BeersActivity.kt:

private val viewModel by lazy { getViewModel<BeersViewModel>() }

The sample project comes with a few neat extension functions that help to tidy up your code. So instead of calling ViewModelProviders.of(target).get(viewModelClass), here you instead call getViewModel().

You might have noticed how your DI is currently done by lazy values. This is not necessarily the best approach, but Dagger and ViewModels don’t work together out of the box. In order to create a ViewModel with Dagger, you have to declare a custom Factory, which is done by using mapped binding or subcomponents.

For the purposes of simplicity though, the project will use lazy values. You can check out Google’s sample app on Architecture Components to see the subcomponent approach. :]

A Time for Change (or Being Reactive)

Everything moves and changes fast. The key is being able to react to changes. You’re now going to use LiveData to do so. LiveDatas. Instead of complicating your apps with Observable, you can use a LiveData structure. Simple as that. :]

You’re moving to the final task of our little tutorial – adding the data. Think about what data you need. When we first talked about components, we had an example with loading and error states. This is something our app should handle. In case of an error, we need to tell the UI that loading should stop, and an error should be shown.

Start off by adding two LiveData properties to the top of your ViewModel:

val errorData = MutableLiveData<Boolean>()
val loadingData = MutableLiveData<Boolean>()

Updating their values in onFailure, like so:

override fun onFailure(call: Call<BeerResponse>?, t: Throwable?) {
  loadingData.value = false
  errorData.value = true
}

For the rest of the data, you need one to hold the page value, because you have lazy loading in the sample project. In addition to that, you need one to hold the list of Beers. Add them right after the loading and error ones:

val pageData = MutableLiveData<Int>()
val beerData = MutableLiveData<List<Beer>>()

Update their value from the response

override fun onResponse(call: Call<BeerResponse>?, response: Response<BeerResponse>?) {
  loadingData.value = false //data has come, stop the loading
  errorData.value = false

  response?.body()?.run {
    updateData(this)
  }
}

Add the updateData method to the bottom of the view model:

private fun updateData(data: BeerResponse) {
  pageData.value = data.currentPage + 1 // increment the page
  beerData.value = data.beers
}

All that you need to do now is wire up the view, and you’ll be ready to serve some brewskies! :]

Add a BeerAdapter under the ViewModel declaration in BeersActivity:

private val adapter = BeersAdapter()

Replace the single TextView in activity_beers.xml with the following:

<android.support.v4.widget.SwipeRefreshLayout
  android:id="@+id/pullToRefresh"
  android:layout_width="0dp"
  android:layout_height="0dp"
  app:layout_constraintTop_toTopOf="parent"
  app:layout_constraintBottom_toBottomOf="parent"
  app:layout_constraintStart_toStartOf="parent"
  app:layout_constraintEnd_toEndOf="parent">

  <android.support.v7.widget.RecyclerView
    android:id="@+id/beersList"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:scrollbars="vertical" />

</android.support.v4.widget.SwipeRefreshLayout>

<TextView
  android:id="@+id/errorView"
  android:layout_width="wrap_content"
  android:layout_height="wrap_content"
  android:text="Error getting beers!"
  app:layout_constraintBottom_toBottomOf="parent"
  app:layout_constraintLeft_toLeftOf="parent"
  app:layout_constraintRight_toRightOf="parent"
  app:layout_constraintTop_toTopOf="parent" />

Add the following private helper methods into BeersActivity, which in turn initialize the UI, handle the loading state, and handle possible error conditions:

private fun initializeUi() {
  beersList.layoutManager = GridLayoutManager(this, 2)
  beersList.itemAnimator = DefaultItemAnimator()
  beersList.adapter = adapter
}

private fun showLoading(isLoading: Boolean) {
  pullToRefresh.isRefreshing = isLoading
}

private fun setErrorVisibility(shouldShow: Boolean) {
  errorView.visibility = if (shouldShow) View.VISIBLE else View.GONE
  beersList.visibility = if (!shouldShow) View.VISIBLE else View.GONE
}

Now, call the initializeUI() helper in onCreate(), and make a call to the view model to get beers:

override fun onCreate(savedInstanceState: Bundle?) {
  super.onCreate(savedInstanceState)
  setContentView(R.layout.activity_beers)

  initializeUi()

  // add subscriptions

  viewModel.getBeers() // request the data for the first time
}

But wait you’re missing something! Where are those subscriptions to the view model LiveData? Replace the “// add subscriptions” comment in onCreate with the following:

viewModel.errorData.subscribe(this, this::setErrorVisibility)
viewModel.loadingData.subscribe(this, this::showLoading)
viewModel.pageData.subscribe(this, adapter::clearIfNeeded)
viewModel.beerData.subscribe(this, adapter::addItems)

These subscriptions add callbacks to the data changes in your LiveData. I’ll walk you through them one-by-one:

The errorData callback is the setErrorVisibility method:

)
private fun setErrorVisibility(shouldShow: Boolean) {
  errorView.visibility = if (shouldShow) View.VISIBLE else View.GONE
  beersList.visibility = if (!shouldShow) View.VISIBLE else View.GONE
}

When the shouldShow argument is true, an error is displayed, and the list is hidden for the moment. On the other hand, if the argument is false, the error is removed, and the list is displayed.

Next, the loadingData callback in showLoading just displays the loading state on true events and hides it on false ones.

Finally, the page and beers data govern what you will display by making calls into the BeerAdapter:

fun clearIfNeeded(page: Int) {
  if (page == 1) {
    beers.clear()
  }
}

fun addItems(newBeers: List<Beer>) {
  beers.addAll(newBeers.filter { beer ->
    beer.labels.medium.isNotBlank() || beer.labels.large.isNotBlank()
  })
  notifyDataSetChanged()
}

In case the user pulls to refresh, and resets the page to 1, you will clear the data before adding newly received items. Adding items is the standard adapter procedure. To implement pull-to-refresh, first update the BeersViewModel to modify the getBeers method and add onRefresh:

BeersViewModel.kt

fun getBeers() {
  interactor.getBeers(pageData.value ?: 1, beersCallback())
}

fun onRefresh() {
  pageData.value = 1
  getBeers()
}

Now add the following call at the end of initializeUi in BeersActivity:

private fun initializeUi() {
  ...
  pullToRefresh.setOnRefreshListener(viewModel::onRefresh)
}

To conclude, you see the input is the data from your ViewModel, whereas the output is the resulting UI changes. Now you should have everything you need to get the long awaited beers! :]

Run the app to get some beers. Everything should be working as planned (fingers crossed):

Final app

The implementation of infinite scroll to load the subsequent pages is not the focus of this tutorial. However, just call viewModel.getBeers() when you want to load a new page. The page increment has already been taken care of.

Reinventing the Wheel

You’ve used LiveData in this tutorial, but it’s quite the same as using Rx programming isn’t it? Well, not quite. While it follows the same core principle of the Observer pattern, LiveData has one huge advantage: it has a built in subscribe/unsubscribe system.

While Google encourages you to use whichever you prefer, they advise that by using Rx, you have to handle the unsubscribing yourself.

From what I’ve seen, Rx is very lightly used in most projects. So having a huge dependency just for passing data around from API requests is not my recommendation. Unless you’re doing Rx style operations like combining multiple requests, you’re better off with LiveData.

Where to Go From Here?

You can download the final project here.

There is a ton of materials on Android Architecture Components, since they’ve become one of the main things the Android community is actively researching and using. You can find a lot of articles out there, some of which are:

And of course be on the lookout for more of our tutorials on Android Architecture Components!

If you have any questions or comments, please join the discussion in the comments below.

The post Android Architecture Components: Getting Started appeared first on Ray Wenderlich.

Video Tutorial: Server Side Swift with Vapor Part 1: Challenge: Create Your Own Routes

Video Tutorial: Server Side Swift with Vapor Part 1: Conclusion

Video Tutorial: Server Side Swift with Vapor Part 2: Introduction


Video Tutorial: Server Side Swift with Vapor Part 2: Models And Fluent

RWDevCon 2018 Sold Out

$
0
0
RWDevCon 2016 is sold out

RWDevCon 2018 is sold out

This is just a quick update that RWDevCon 2018 is now sold out!

I am amazed and overjoyed by the enthusiastic response from the community for this conference – we are set to have ~265 attendees at the conference this year.

The team and I are hard at work on the conference – we’ll make this an event to remember!

If you didn’t manage to get a ticket:

  • If you are a student you still have one more chance – we are offering 5 student scholarships, thanks to our amazing patrons. Applications are currently open: apply now!
  • Stay tuned for the RWDevCon 2018 Vault – we will be selling a package of videos, materials, and our conference book at some point after the conference. We usually have a special deal in the first week it’s available, so don’t miss it!
  • Otherwise, be sure to sign up for our waiting list to get notified if any tickets become available this year or next.

For the attendees and sponsors of RWDevCon – thanks so much for being a part of the conference, and we can’t wait to see you in DC! :]

The post RWDevCon 2018 Sold Out appeared first on Ray Wenderlich.

Coordinator Tutorial for iOS: Getting Started

$
0
0

Coordinator Tutorial for iOS: Getting Started

The Model-View-Controller (“MVC”) design pattern is useful, but it doesn’t scale well. As projects grow in size and complexity, this limitation becomes more apparent. In this Coordinator tutorial, you’ll try a different approach: Coordinators.

If you’re unfamiliar with the term, don’t worry! It’s a simple architecture that doesn’t require any third party frameworks, and it’s easy to adopt in your existing MVC projects.

By the end of this Coordinator tutorial, you’ll be able to decide which approach works best for you when building your apps.

Note: If you’re not familiar with MVC, check out Design Patterns in iOS.

Getting Started

To kick things off, start by downloading the starter project, Kanji List.

Note: The kanji data used in this Coordinator tutorial was provided by Kanji Alive Public API

Kanji List is an app for learning Kanji (Chinese characters used in the Japanese language), and it’s currently using the MVC design pattern.

Let’s take a closer look at the functionality this app provides and how:

  1. KanjiListViewController.swift contains a list of the kanji.
  2. KanjiDetailViewController.swift contains information specific to the selected kanji, as well as the list of words that use that kanji.
  3. When a user selects a word from the list, the application pushes KanjiListViewController.swift and shows the list of kanji for that word.

Coordinator Tutorial application

There’s also Kanji.swift, which holds the data models; and KanjiStorage.swift, which is a shared instance. It’s used to store parsed kanji data.

Pretty straightforward, huh?

Current Implementation Problems

At this point, you may be thinking, “The app works. What’s the problem?”

That’s a great question! Let’s take a look.

Open Main.storyboard.

OK, this looks fishy. The app has a segue from KanjiListViewController to KanjiDetailViewController; and also from KanjiDetailViewController to KanjiListViewController.

The reason is because of the app’s business logic:

  • First you push KanjiDetailViewController.swift.
  • Then you push KanjiListViewController.swift.

If you think the problem is in the segues, you’re partially right.

Segues bind two UIViewControllers together, making those UIViewControllers very difficult to reuse.

Reusability Problems

Open KanjiListViewController.swift. Notice it has a property named kanjiList:

var kanjiList: [Kanji] = KanjiStorage.sharedStorage.allKanji() {
  didSet {
    kanjiListTableView?.reloadData()
  }
}

kanjiList is a datasource for KanjiListViewController, and its default is to display all of the kanji from the shared KanjiStorage.

There’s also a property named word. This property is a hack that allows you to reuse KanjiListViewController for both the first and third screens:

var word: String? {
  didSet {
    guard let word = word else {
      return
    }
    kanjiList = KanjiStorage.sharedStorage.kanjiForWord(word)
    title = word
  }
}

By setting word, you change both kanjiList and the title that’s displayed in the UINavigationBar:

Consider for a moment. KanjiListViewController knows the following things:

  • There might be a word selected.
  • The word has kanji.
  • If there is no word selected, then the app should show all of the kanji in kanjiList.
  • KanjiListViewController knows that it’s in a UINavigationController, and that it should change the title if a word is selected.

That seems pretty complicated for something as simple as a UIViewController displaying a list of items.

One way to fix this unnecessary complexity is to pass the list of kanji to the KanjiListViewController; but who should pass it?

You can create a UINavigationController subclass and inject the data into its child, but does this code belong in the UINavigationController‘s subclass? Shouldn’t UINavigationController be a simple container for UIViewControllers?

Another problematic place is prepare(for:sender:), which is located in KanjiDetailViewController.swift:

override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
  super.prepare(for: segue, sender: sender)

  guard let listViewController = segue.destination as? KanjiListViewController else {
    return
  }

  listViewController.shouldOpenDetailsOnCellSelection = false
  listViewController.word = sender as? String
}

This code means that KanjiDetailViewController knows about the next UIViewController, which in this case is KanjiListViewController.

If you were to reuse KanjiDetailViewController, the code would quickly get out of hand, because this method would need to grow into a giant switch statement so it knew which view controller to push next. This is why the logic shouldn’t be inside of another view controller — it creates a strong connection between view controllers, making them have more responsibility than they should.

Coordinator Pattern

The Coordinator pattern is a potential solution to all of the problems mentioned above. This pattern was first introduced to the iOS community by Soroush Khanlou (@khanlou) in his blog and during his presentation at the NSSpain conference.

The idea of the Coordinator pattern is to create a separate entity — a Coordinator — which is responsible for the application’s flow. The Coordinator encapsulates a part of the application. The Coordinator knows nothing of its parent Coordinator, but it can start its child Coordinators.

Coordinators create, present and dismiss UIViewControllers while keeping the UIViewControllers separate and independent. Similar to how UIViewControllers manage UIViews, Coordinators manage UIViewControllers.

Coordinator Protocol

It’s time to dive into some coding!

First, create a Coordinator protocol. From the main menu, click File\New\File…. Then, select the iOS\Source\Swift File and name the new file Coordinator.swift. When you’re done, click Next and then Create.

Now, replace its contents with the following:

protocol Coordinator {
  func start()
}

Believe it or not, that’s it! All the Coordinator protocol needs is one start() function!

Apply the Coordinator Pattern

Because you want the Coordinator to handle the application’s flow, you need to provide a way, within the code, to create UIViewControllers. For this Coordinator tutorial, you’ll use .xib files instead of storyboards. With these files, you’ll be able to create UIViewControllers by calling the following:

UIViewController(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?)

Note: The Coordinator pattern doesn’t require that you use .xib files. You can create UIViewControllers in code, and you can also instantiate them from storyboards, which you’ll see at the end of the Coordinator tutorial.

Add these .xib files to the project target by dragging and dropping them into the Project navigator in Xcode. Open KanjiDetailViewController.xib and KanjiDetailViewController.swift in the Assistant editor and make sure that all of the outlet connections are properly set. Do the same for KanjiListViewController.xib and KanjiListViewController.swift.

Note: In the File inspector, make sure that both .xib files are added to the target.

Adding target membership to a file in Xcode

You need to replace Main.storyboard as the application starting point.

Right-click Main.storyboard, choose Delete then click Move to Trash.

Click on the KanjiList project in the File navigator and open the KanjiList target > General, and delete Main as the Main interface:

Removing main interface from project

Now you need to create your own starting point.

Application Coordinator

It’s time to create the application coordinator. Click File\New\File… and select the iOS\Source\Swift file. Name the file ApplicationCoordinator.swift. Click Next, and then Create.

Replace its contents with the following:

import UIKit

class ApplicationCoordinator: Coordinator {
  let kanjiStorage: KanjiStorage //  1
  let window: UIWindow  // 2
  let rootViewController: UINavigationController  // 3
  
  init(window: UIWindow) { //4
    self.window = window
    kanjiStorage = KanjiStorage()
    rootViewController = UINavigationController()
    rootViewController.navigationBar.prefersLargeTitles = true
    
    // Code below is for testing purposes   // 5
    let emptyViewController = UIViewController()
    emptyViewController.view.backgroundColor = .cyan
    rootViewController.pushViewController(emptyViewController, animated: false)
  }
  
  func start() {  // 6
    window.rootViewController = rootViewController
    window.makeKeyAndVisible()
  }
}

Let’s take a closer look at the code:

  1. ApplicationCoordinator will have kanjiStorage with data from JSON. Right now kanjiStorage is used as a shared instance, but you’ll use dependency injection instead.
  2. ApplicationCoordinator sets up its presentations in the app’s window, which will be passed to ApplicationCoordinator in its initializer.
  3. rootViewController is a UINavigationController.
  4. Initialize the properties.
  5. Since there’s no child Coordinator to present, this code will allow you to test if the presentation is set up correctly.
  6. start() is where things kick off. Specifically, the window is presented with its rootViewController.

All you need to do now is to call start() to create the ApplicationCoordinator.

Open AppDelegate.swift and replace its contents with this:

import UIKit

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
  var window: UIWindow?
  private var applicationCoordinator: ApplicationCoordinator?  // 1
  
  func application(_ application: UIApplication,
                   didFinishLaunchingWithOptions launchOptions:
                     [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
    
    let window = UIWindow(frame: UIScreen.main.bounds)
    let applicationCoordinator = ApplicationCoordinator(window: window) // 2
    
    self.window = window
    self.applicationCoordinator = applicationCoordinator
    
    applicationCoordinator.start()  // 3
    return true
  }
}

Here’s what’s happening:

  1. Keep a reference to applicationCoordinator.
  2. Initialize applicationCoordinator with the window that you just created.
  3. Start applicationCoordinator‘s main presentation.

Build and run the app. Now you should see the following screen:

Presenting an empty view controller with the Coordinator pattern

Kanji List Coordinator

Now it’s time to present the KanjiListViewController. For this you’ll create another Coordinator. The main tasks of this Coordinator are to present a list of kanji and, later, to start another Coordinator responsible for displaying KanjiDetailViewController.

Similar to before, create a new file AllKanjiListCoordinator.swift.

Replace its contents with the following code:

import UIKit

class AllKanjiListCoordinator: Coordinator {
  private let presenter: UINavigationController  // 1
  private let allKanjiList: [Kanji]  // 2
  private var kanjiListViewController: KanjiListViewController? // 3
  private let kanjiStorage: KanjiStorage // 4

  init(presenter: UINavigationController, kanjiStorage: KanjiStorage) {
    self.presenter = presenter
    self.kanjiStorage = kanjiStorage
    allKanjiList = kanjiStorage.allKanji()  // 5
  }

  func start() {
    let kanjiListViewController = KanjiListViewController(nibName: nil, bundle: nil) // 6
    kanjiListViewController.title = "Kanji list"
    kanjiListViewController.kanjiList = allKanjiList
    presenter.pushViewController(kanjiListViewController, animated: true)  // 7

    self.kanjiListViewController = kanjiListViewController
  }
}

Here’s the breakdown:

  1. The presenter of AllKanjiListCoordinator is a UINavigationController.
  2. Since AllKanjiListCoordinator presents a list of all kanji, it needs a property to access the list.
  3. Property to keep a reference to the KanjiListViewController that you’ll be presenting.
  4. Property to store KanjiStorage, which is passed to AllKanjiListCoordinator‘s initializer.
  5. Initialize properties.
  6. Create the UIViewController that you want to present.
  7. Push the newly created UIViewController to the presenter.

Now you need to create and start AllKanjiListCoordinator. To do that, open ApplicationCoordinator.swift and add this property to the top of the file, right below where you declared the rootViewController:

let allKanjiListCoordinator: AllKanjiListCoordinator

Now, in init(window:), replace all of the code below // Code below is for testing purposes // 5 with this:

allKanjiListCoordinator = AllKanjiListCoordinator(presenter: rootViewController,
                                                  kanjiStorage: kanjiStorage)

Lastly, in start(), below this line:

window.rootViewController = rootViewController

add this:

allKanjiListCoordinator.start()

Build and run. Now it looks the same as it did before the refactor!

Coordinator tutorial Kanji list application

However, if you select a kanji, it will crash. This is because when a cell is selected in KanjiListViewController, a segue is performed, but that segue doesn’t exist.

You need to fix this! Instead of directly performing an action when the cell is selected, you’ll trigger a delegate callback. This removes the action logic from the UIViewController.

Open KanjiListViewController.swift and add this above the class declaration:

protocol KanjiListViewControllerDelegate: class {
  func kanjiListViewControllerDidSelectKanji(_ selectedKanji: Kanji)
}

Now, in KanjiListViewController, add a new property:

weak var delegate: KanjiListViewControllerDelegate?

Lastly, replace tableView(_:didSelectRowAt:) with this:

func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
  let kanji = kanjiList[indexPath.row]
  delegate?.kanjiListViewControllerDidSelectKanji(kanji)
  tableView.deselectRow(at: indexPath, animated: true)
}

Great! You just made KanjiListViewController simpler. It now has the single responsibility of displaying the list of kanji and notifying the delegate when someone selects an item. Nobody is listening yet, though.

Open AllKanjiListCoordinator.swift and add this to the end of the file, outside of AllKanjiListCoordinator:

// MARK: - KanjiListViewControllerDelegate
extension AllKanjiListCoordinator: KanjiListViewControllerDelegate {
  func kanjiListViewControllerDidSelectKanji(_ selectedKanji: Kanji) {

  }
}

This sets up AllKanjiListCoordinator so that it conforms to KanjiListViewControllerDelegate. Later you’ll add code inside kanjiListViewControllerDidSelectKanji(_:) that calls start() in DetailsCoordinator.

Lastly, add this code inside of start(), right below where you instantiate kanjiListViewController:

kanjiListViewController.delegate = self

Now build and run your app! Although it runs, the code inside kanjiListViewControllerDidSelectKanji is still empty, so nothing happens when you select a cell. Don’t worry; you’ll add this code shortly.

When to Create a Coordinator?

At this point, you might be wondering, “When do I need to create a separate coordinator?” There is no strict answer to this question. Coordinators are useful for a specific part of the application that might be presented from different places.

For displaying kanji details, you could create a new kanji details UIViewController inside of AllKanjiListCoordinator, and push it when the delegate callback is called. One good question to ask yourself is, “Should AllKanjiListCoordinator know about details related UIViewControllers?” The name suggests that it shouldn’t. Also, by creating a separate Coordinator for details, you’ll end up with an independent component that can display details for a kanji, without any additional dependencies on the app. This is powerful!

Suppose one day you want integrate Spotlight search. If you’ve put detail display into a separate Coordinator, it becomes simple to do: create a new DetailsCoordinator and call start().

The key takeaway is that Coordinators help create independent components that, together, build the app.

Kanji Detail Coordinator

Now let’s create the KanjiDetailCoordinator.

Similar to before, add a new file named KanjiDetailCoordinator.swift and replace the contents with the following code:

import UIKit

class KanjiDetailCoordinator: Coordinator {
  private let presenter: UINavigationController  // 1
  private var kanjiDetailViewController: KanjiDetailViewController? // 2
  private var wordKanjiListViewController: KanjiListViewController? // 3
  private let kanjiStorage: KanjiStorage  // 4
  private let kanji: Kanji  // 5

  init(presenter: UINavigationController, // 6
       kanji: Kanji,
       kanjiStorage: KanjiStorage) {

    self.kanji = kanji
    self.presenter = presenter
    self.kanjiStorage = kanjiStorage
  }

  func start() {
    let kanjiDetailViewController = KanjiDetailViewController(nibName: nil, bundle: nil) // 7
    kanjiDetailViewController.title = "Kanji details"
    kanjiDetailViewController.selectedKanji = kanji    

    presenter.pushViewController(kanjiDetailViewController, animated: true) // 8
    self.kanjiDetailViewController = kanjiDetailViewController  
  }
}

There’s a lot going on here, so let’s break it down:

  1. KanjiDetailCoordinator‘s presenter is a UINavigationController.
  2. Reference to KanjiDetailViewController, which you’re presenting in start().
  3. Reference to KanjiListViewController, which you’ll present when a user selects a word.
  4. Property to store KanjiStorage, which is passed to KanjiDetailViewController‘s initializer.
  5. Property to store the selected kanji.
  6. Initialize properties.
  7. Create the UIViewController that you want to present.
  8. Present the UIViewController that you just created.

Now let’s create KanjiDetailCoordinator. Open AllKanjiListCoordinator.swift and add a new property below the kanjiStorage declaration:

private var kanjiDetailCoordinator: KanjiDetailCoordinator?

Next, replace the empty body of kanjiListViewControllerDidSelectKanji(_:) in the extension with this:

let kanjiDetailCoordinator = KanjiDetailCoordinator(presenter: presenter, 
                                                    kanji: selectedKanji, 
                                                    kanjiStorage: kanjiStorage)
kanjiDetailCoordinator.start()

self.kanjiDetailCoordinator = kanjiDetailCoordinator

With this function, you create and start KanjiDetailCoordinator when a user selects a kanji.

Build and run.

Coordinator tutorial Kanji list application details screen

As you can see, you now have KanjiDetailViewController presented correctly when a user selects a cell on KanjiListViewController. However, if you select a word from the list on KanjiDetailViewController, your app will crash because, like before, you’re triggering a segue that no longer exists.

Time to fix this!

Open KanjiDetailViewController.swift. Just like with KanjiListViewController, add the delegate protocol above the class declaration:

protocol KanjiDetailViewControllerDelegate: class {
  func kanjiDetailViewControllerDidSelectWord(_ word: String)
}

Then, add the following property inside KanjiDetailViewController:

weak var delegate: KanjiDetailViewControllerDelegate?

To trigger the delegate, replace tableView(_:didSelectRowAt:) with this:

func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
  defer {
    tableView.deselectRow(at: indexPath, animated: true)
  }

  guard indexPath.section == 1,
    let word = selectedKanji?.examples[indexPath.row].word else {
      return
  }
  delegate?.kanjiDetailViewControllerDidSelectWord(word)
}

Excellent! Now the app won’t crash when you select a cell, but it still won’t open a list.

To fix this, open KanjiDetailCoordinator.swift, and add the following code at the bottom of the file — outside of KanjiDetailCoordinator — which confirms the delegate:

// MARK: - KanjiDetailViewControllerDelegate
extension KanjiDetailCoordinator: KanjiDetailViewControllerDelegate {
  func kanjiDetailViewControllerDidSelectWord(_ word: String) {
    let wordKanjiListViewController = KanjiListViewController(nibName: nil, bundle: nil)
    let kanjiForWord = kanjiStorage.kanjiForWord(word)
    wordKanjiListViewController.kanjiList = kanjiForWord
    wordKanjiListViewController.title = word

    presenter.pushViewController(wordKanjiListViewController, animated: true)
  }
}

Inside of start(), add this below where you instantiated KanjiDetailViewController:

kanjiDetailViewController.delegate = self

Build and run the project. The app should work the same way as it did before the refactoring.

Coordinator tutorial application word screen

Project Clean Up

There are still a few things you can change to make this even better.

First of all, in KanjiListViewController.swift and KanjiDetailViewController.swift remove the prepare(for:sender:) method. You remove this code, because it will never get triggered with this architecture.

Still in KanjiListViewController.swift, remove this variable:

var word: String? {
  didSet {
    guard let word = word else {
      return
    }
    kanjiList = KanjiStorage.sharedStorage.kanjiForWord(word)
    title = word
  }
}

This variable is also no longer used.

Now take a look at var shouldOpenDetailsOnCellSelection = true in KanjiListViewController.swift. This flag was used to specify whether or not the UIViewController will push KanjiDetailViewController. Since this logic is now not in the KanjiListViewController you need to make a small change.

Replace this:

var shouldOpenDetailsOnCellSelection = true

With this:

var cellAccessoryType = UITableViewCellAccessoryType.disclosureIndicator

And in tableView(_:cellForRowAt:) change this:

cell.accessoryType = shouldOpenDetailsOnCellSelection ? .disclosureIndicator : .none

To this:

cell.accessoryType = cellAccessoryType

This property allows you to set the specific accessory type for cells. The problem is now that when a word is selected, you display the kanji list with a disclosure indicator.

Disclosure indicator inside a table view

To fix that, open KanjiDetailCoordinator.swift and look for kanjiDetailViewControllerDidSelectWord(_:). After you instantiate wordKanjiListViewController, set its cell accessory type like this:

wordKanjiListViewController.cellAccessoryType = .none

wordKanjiListViewController‘s cellAccessoryType is set to .none, because the logic for setting this property is handled in KanjiDetailCoordinator. This saves wordKanjiListViewController from knowing too much about the application.

Now for the last improvement. Open KanjiStorage.swift and delete this static variable:

static let sharedStorage = KanjiStorage()

Deleting this static variable is not enough; it’s still in use in KanjiListViewController.swift, where you set it as the default value for kanjiList. Instead of giving kanjiList a default value of the entire KanjiStorage, display an empty list.

Change this line:

var kanjiList: [Kanji] = KanjiStorage.sharedStorage.allKanji()

To this:

var kanjiList: [Kanji] = []

Now you have a working app, with arguably cleaner and more flexible architecture, as well as no shared instances.

You can download the finished project here.

The Coordinator pattern might seem like an over-complication — and for a small project, it might be — but as soon as the application begins to grow, this pattern keeps the project straightforward and UIViewControllers independent. Coordinators are great, as they provide you with a clean architecture while requiring a relatively small number of changes to integrate with existing projects.

Extras: Coordinator Pattern with Storyboards

If you like storyboards, you can create a new file named Extensions.swift file and replace it with the following contents:

import UIKit

protocol StoryboardInstantiable: NSObjectProtocol {
  associatedtype MyType  // 1
  static var defaultFileName: String { get }  // 2
  static func instantiateViewController(_ bundle: Bundle?) -> MyType // 3
}

extension StoryboardInstantiable where Self: UIViewController {
  static var defaultFileName: String {
    return NSStringFromClass(Self.self).components(separatedBy: ".").last!
  }

  static func instantiateViewController(_ bundle: Bundle? = nil) -> Self {
    let fileName = defaultFileName
    let sb = UIStoryboard(name: fileName, bundle: bundle)
    return sb.instantiateInitialViewController() as! Self
  }
}

Here’s what’s going on:

  1. You create an associated type to use inside of the protocol.
  2. Returns the filename, which is the name of a class without the module name.
  3. This is the main function; it searches for the Storyboard with the same name as defaultFileName, instantiates the first UIViewController from the Storyboard and returns it.

In the code above, you also created the StoryboardInstantiable extension for UIViewController. With it, you can just conform any UIViewController to StoryboardInstantiable, and you will be able to instantiate it.

To instantiate the UIViewController, add this code to the bottom of the UIViewController‘s file:

extension MyViewController: StoryboardInstantiable {
}

Inside the UIViewController, add the following:

let viewController = MyViewController.instantiateViewController()

For example, if you wanted to use this code with KanjiDetailViewController, it would look like the following:

extension KanjiDetailViewController: StoryboardInstantiable {
}
class KanjiDetailViewController: UIViewController {
   let viewController = KanjiDetailViewController.instantiateViewController()
   // keep the other code within this class below
}

With great power comes great responsibility (and limitations). To use this extension, you need to create a separate storyboard for each UIViewController. The name of the storyboard must match the name of the UIViewController‘s class. This UIViewController must be set as the initial UIViewController for this storyboard.

As a homework exercise, feel free to switch from .xib files to this approach, and please share your thoughts in the comments section below.

Where To Go From Here?

This concludes the Coordinator tutorial. One of the best advantages the Coordinator architectural pattern provides is the ability to easily change the application flow (show login screen, show tutorial screen, etc.) As an exercise in testing this, play around with the project and try creating and presenting a login screen instead of a list.

If you want to learn more about the Coordinator pattern, check out the videos below. They have some great explanations:

Coordinators presentation at NSSpain by Soroush Khanlou
Boundaries in Practice by Ayaka Nonaka at try! Swift
MVVM with Coordinators & RxSwift – Łukasz Mróz

The coordinator pattern is one of many useful design patterns you can use in iOS development. To learn more about other patterns, check out our video series on iOS design patterns. Also check out the video tutorials on our site for in-depth explanations on other iOS topics.

As always, if you have any questions, feel free to ask in the comment section below. :]

The post Coordinator Tutorial for iOS: Getting Started appeared first on Ray Wenderlich.

Screencast: Testing Using a BDD Framework

$
0
0

Writing tests using XCTest alone can make it difficult to organize your tests and keep them readable and maintainable. Using a BDD testing framework helps solve these problems and makes it easier and more enjoyable to write tests.

The post Screencast: Testing Using a BDD Framework appeared first on Ray Wenderlich.

Reminder: RWDevCon Student Scholarship Applications Due Thursday

$
0
0

RWDevCon Scholarship

As you might know, this year we offering 5 student scholarships for RWDevCon 2018.

The 5 lucky students will win a free ticket to the conference and will get to attend our team-only pre-conference fun day!

Not only is this an amazing opportunity for students to learn a ton about Swift and iOS development, but it’s also the only way to get a ticket to the conference at the moment, because RWDevCon 2018 is sold out.

This post is a quick reminder that applications for RWDevCon 2018 student scholarships are due this Thursday, February 22 – so if you’re a student and haven’t applied yet, now’s the time!

Keep reading for a reminder about find out who’s eligible, how to apply, and who to thank for this great opportunity.

Eligibility and How To Apply

To be eligible to win, there are three requirements:

  • You must be enrolled in a full-time educational program (such as high school, college/university, or a full-time immersive boot camp).
  • You also must be able to attend the conference and the pre-conference fun day (Apr 5 – April 7, 2018).
  • You must be able to pay for your own travel and hotel expenses (they are not included; the scholarship includes a ticket to the conference and an invitation to the team-only pre-conference fun day only).

Applying is simple:

  • Just send us an email about why you’re interested in programming and why you’d like to attend RWDevCon. Please include proof that you are in a full-time educational program (a scanned ID or receipt is fine).

Applications are due in 2 weeks – February 22, 2018 – so apply now! :]

Last year’s student scholarship winners!

Introducing the Patrons

The RWDevCon 2018 scholarships are sponsored by 5 generous patrons of the iOS community, who bought a special ticket that included the cost of the student tickets.

I asked each of our patrons to write some advice for students studying programming. Here’s what they had to say:

Don Clore, Really Old Bit-Wrangler

“One thing I have discovered in my programming journey is that in order to make software that works well, you have to care, and be willing simply to do the hard work.

There’s lore in the brogramming world that says that it’s a virtue for an engineer to be arrogant and lazy. I have not found this to be true. Humility and a willingness to persevere are more effective in building things that are actually useful.

You have to embrace the fact that executing your vision means that most of your efforts will be spent handling errors and exceptional cases.

Sometimes it’s going to feel like you’re pushing a piano uphill. But the result is more than worth it. I love this work now, 27 years after I started, more than I ever have.”

Larry Ketchersid, CEO of Media Sourcery, Inc; owner of JoSara MeDia

LarryKetchersid

“You’ll learn more working with others than in isolation. Learning from someone is great, but also try teaching someone what you’ve learned; whether the subject is programming, cooking, martial arts or anything, you’ll find that you truly understand a topic when you attempt to explain it to someone else, and hear their questions on what you are trying to convey. It’s also a great way to give back to the programming community.”

Kevin Legg, Co-Owner of Five Pack Creative

KevinLegg

“Work on things you are passionate about and don’t forget to have fun. Do good things even when not required and you will go far.”

Carey McLean, Innovation Software Engineer at The Shop @ VSP Global

“The most amazing thing about the tech industry is that there is an abundance of opportunities. As long as we are willing to fail, learn from our failures and move onto the next thing, our path to a successful career is endless. Failing fast is the quickest way to finding out what works!”

Note: One of our generous patrons wishes to remain anonymous so is not listed here.

Where To Go From Here?

If you, or a student you know, wants to take advantage of an amazing learning opportunity that will pay some major dividends in life, don’t miss this chance!

Just send us an email about why you’re interested in programming and why you’d like to attend RWDevCon. Please include proof that you are in a full-time educational program (a scanned ID or receipt is fine).

We wish the best of luck to all of the applicants, and we look forward to seeing you at RWDevCon 2018!

Note: Missed your chance to get a RWDevCon ticket? Be sure to sign up to our mailing list to get notified if any tickets become available this year or next.

The post Reminder: RWDevCon Student Scholarship Applications Due Thursday appeared first on Ray Wenderlich.

Chameleon on iOS: Getting Started

$
0
0

Chameleon on iOS: Getting Started

Colors are beautiful! They’re all around us — even in our apps. But adding colors to your app can be difficult to manage; some may work together, while others may not. Even worse, if you select the wrong color combinations, your app’s visual elements may be difficult to see. That’s where Chameleon steps in!

Chameleon is a color management framework that makes it easy to add a splash of color to your app. In this tutorial, you’ll learn how to use Chameleon to do the following:

  • Differentiate your UI with Chameleon’s hand-picked color palette
  • Create just the right random colors
  • Use hex codes to create UIColors
  • Theme your entire app based on your favorite color
  • Generate color schemes on the fly
  • Ensure that your labels are always visible by using contrasting colors
  • Keep all the status bar icons visible by contrasting them against their background
This tutorial assumes some familiarity with iOS development and Swift. If you need some help with these things, take a look at our iOS and Swift tutorials first.

Getting Started

The starter project, HomeSplash, is an interior design app. You can paint things, like furniture, different colors to see how they’d look in your living room (ARKit integration still coming!). Use the Download Materials button at the top or bottom of this tutorial to download the starter project.

Once downloaded, open the starter project in Xcode using HomeSplash.xcworkspace, and give it a build and run. Tap one of the furniture items, and you’ll see the color picker. Select a color, and watch as it’s painted onto your living room set.

chameleon on iOS

Take a look at the project and you’ll see that it consists of two view controllers:

  • ViewController.swift: The root view controller containing the image views for the furniture
  • ColorPickerViewController.swift: The palette of different colors that update the root view controller when selected

It also includes a utility class that paints an image with a color using Core Image, ImagePainter.swift. You don’t need to worry about this class now.

I know what you’re thinking! For an app about color, it’s pretty bland at the moment. But don’t worry, you’re about to liven things up.

Here’s what you’ll be doing to spruce it up:

  • Change the UIKit colors to the sparkly Chameleon color palette
  • Apply different colors to different items based on color schemes
  • Lighten or darken the painted furniture with a stepper control
  • Generate random colors for when you’re not feeling too artistic
  • Update the entire app’s theme to the selected color by using global theming

Building the color picker

One look at Chameleon’s API and you’ll notice plenty of references to flat colors. This raises the question:

What Are Flat Colors?

Flat colors, often referred to as solid colors, are generally regarded as colors with little to no gradient or changes in hue. They also have no transparency; their Alpha values are set to 1.0. In the context of Chameleon, whenever a method uses the term flat color, it’s referring to Chameleon’s Flat Color Palette.

The Flat Color Palette is a collection of 24 hand-picked colors in two shades, which gives you a total of 48 colors. When Chameleon talks about generating a flat color, it generates one from that palette.

Adding Flat Colors to the Picker

Open Main.storyboard and locate the Color Picker Scene.

Each of the different-colored squares represent the colors that the user can select. Right now, they’re the stock-standard UIKit colors. All of the colors are set in the storyboard, so if you want to play around with the different Flat Colors there, you need to add the Chameleon Storyboard Add-On.

Download the Chameleon Palette, which you can find on Chameleon’s GitHub page. This will allow you to access the Chameleon colors from Interface Builder.

Once downloaded, open it, and then run the Palette Installer.pkg.

You may get a security warning when running the Palette Installer. Read through the warning, and then allow the installation in your Mac’s Security and Privacy settings if you’re happy.

Choose Open Anyway and make your way through the installer.

Once the installation is complete, restart Xcode and open Main.storyboard.

In the Color Picker Scene, click on one of the Color Views and show the Attributes inspector.

Click on the dropdown next to the Background property, and select Other… from the list. You’ll be presented with a color picker.

Click on the Color Palettes tab (third from the left), and you’ll see the Color View’s color selected in the Apple Color Palette. This is the default color palette that you use when using the standard colors such as UIColor.green.

Open the Color Palette dropdown, and you’ll see there are quite a few more palettes from which to choose, including the newly-added Chameleon Color Palette. Select it to see all of the beautiful new crayons you just added to your color arsenal! :]

Select some of your favorite flat colors and apply them to the nine Color Views in the storyboard. Build and run the app, and you’ll see the colors you choose from the palette.

So many new colors at your disposal!

It’s super easy to reference the Chameleon Flat Colors in code too – as easy as the UIKit colors. They’re all declared as extensions on UIColor, with color names starting with flat:
let flatMint = UIColor.flatMint
let flatMintDark = UIColor.flatMintDark

Random Colors

The usual way to generate random colors is to pass random values to UIColor.init(red:green:blue:). Following this approach, it’s common to end up with a collection of colors that don’t fit well together.

With Chameleon, finding the perfect random color is easier because it’s a little less random. :] Take the following, for example:

// A random color from the Flat Color Palette
let randomFlatColor = UIColor.randomFlat
 
// A random color from the 24 light shades of the Flat Color Palette
let randomLightFlatColor = UIColor(randomFlatColorOf: .light)
 
// A random color from an array
let myFavoriteColors = [UIColor.red, UIColor.flatGreen, UIColor(white: 0.5, alpha: 1.0)]
let randomColorFromArray = UIColor(randomColorIn: myFavoriteColors)

// A random color from the Flat Color Palette except for those in the array
let reds = [UIColor.flatRed, UIColor.flatRedDark]
let random = UIColor(randomFlatColorExcludingColorsIn: reds)

You can see that most of the methods and properties return a color from the Flat Color Palette. The only exception is UIColor(randomColorIn:), which returns one of the colors passed into it.

Adding a Random Color to the Picker

Currently, the button titled “Random” in the color picker doesn’t actually do anything. However, with the help of Chameleon, that’s about to change!

Open ColorPickerViewController.swift and import Chameleon at the top of the file, like this:

import ChameleonFramework

Now, locate randomColorTapped(_:), and update the selected color to a random color by adding the following implementation:

let randomColor = UIColor.randomFlat
updateAndPop(color: randomColor)

This generates a random color from Chameleon’s palette. It then passes this color back to the initial view controller.

Build and run the app. Now, tap one of the furniture items to navigate to the color picker. Then, tap on the Random button. Cool! Your imaginary living room is now painted with the creativity of a random color generator. Huzzah!

Hex Color Codes

You may have noticed the button, Ray Wenderlich Green, doesn’t work either. You’ll fix that next — because honestly, who doesn’t want their furniture to be Ray’s favorite shade of green, right? :]

The hex color code for Ray Wenderlich Green is #0B560E. But there’s no need to find a hex-to-RGB converter in order to use the standard UIColor initializer.

Inside ColorPickerViewController, locate rayWenderlichGreenTapped(_:), and add this bit of code:

let rayWenderlichGreen = UIColor(hexString: "0B560E")!
updateAndPop(color: rayWenderlichGreen)

This creates a UIColor straight from the hex string, which is then used to update the selected color.

Build and run the app, and marvel at what your living room will look like after you paint it Ray Wenderlich Green!

Color Schemes

Whenever you’re working with more than one color, you want to make sure they work together. Let’s face it, the wrong combination of colors can lead to a UI that’s either too bland or too glaring. Luckily, for less artistic people such as myself, you can make use of color schemes.

A color scheme is a selection of colors that share a particular relationship. Chameleon can generate color schemes of three types:

  • Analogous
  • Complementary
  • Triadic

Analogous colors are those that sit next to each other on a color wheel.

They live close to each other on the light spectrum. They also blend well together.

Complementary colors sit across from each other on a color wheel.

Their contrast makes for a striking UI.

Triadic colors are evenly spaced on a color wheel.

Use them to create a vivid, colorful design.

Creating Color Schemes from the Selected Color

Open Main.storyboard and find the first view controller. It has a segmented control with the default First, Second, Third segment titles:

Click on the segmented control and select the Attributes inspector. Change the titles for each segment as follows:

  • Segment 0: Analogous
  • Segment 1: Complementary
  • Segment 2: Triadic

Changing button titles is fun and all, but the functionality is unaffected. To change this, open ViewController.swift and start by importing Chameleon.

import ChameleonFramework

Next, add this property beneath selectedColor:

var selectedColorScheme = ColorScheme.analogous {
  didSet {
    paintImages()
  }
}

This defines a color scheme with the initial value of ColorScheme.analogous. Whenever the scheme updates, it calls paintImages().

Now, find the method stub for colorSchemeSelectionChanged(_:), and add the following code to update the selected scheme:

switch sender.selectedSegmentIndex {
case 0:
  selectedColorScheme = .analogous
case 1:
  selectedColorScheme = .complementary
case 2:
  selectedColorScheme = .triadic
default:
  return
}

The switch statement sets the selectedColorScheme based on the selected segment.

Great work! The selected scheme is updated, and now you can use it to paint the images.

paintImages() creates UIImages for the image views and paints them with the selected color. It’s time to change it so that it paints the images with colors from a color scheme. Update paintImages() to the following:

func paintImages() {
  let baseColor = selectedColor
  
  // 1
  let colorsFromScheme = ColorSchemeOf(selectedColorScheme,
                                       color: baseColor,
                                       isFlatScheme: false)
  
  // 2
  imageView.image = imagePainter.paint(image: UIImage(named: "sofa"),
                                       color: colorsFromScheme[1])
  imageView2.image = imagePainter.paint(image: UIImage(named: "armchair"),
                                        color: colorsFromScheme[2])
  imageView3.image = imagePainter.paint(image: UIImage(named: "bookshelf"),
                                        color: colorsFromScheme[3])
}

Here’s a closer look at what’s happening:

  1. Generate an array of colors from the selected scheme.
  2. For each image, grab a color from the colorsFromScheme array and use it to paint the image. Index 2 is the selectedColor. You then use it to paint the center image.

Build and run the app. Select your favorite color, and take a look at your new interior design abilities! :]

Shades

The variety of colors for the living room grew three-fold by introducing schemes. Now you’ll add even more possibilities by adding shades :]

In Main.storyboard, take a look at the Shade Stepper.

Its initial value is 0, and it can range from -100 to 100. It steps in values of 10s. You’ll use this value to shade the selected color by a certain percentage.

In ViewController.swift, find selectedColor, and create a new property below it:

var selectedColorWithShade: UIColor {

// 1
  let shadePercentage = CGFloat(abs(stepperValue / 100))

  if stepperValue >= 0 {
// 2
    return selectedColor.lighten(byPercentage: shadePercentage)!
  } else {
// 3
    return selectedColor.darken(byPercentage: shadePercentage)!
  }
}

Here’s what’s happening:

  • stepperValue holds the value of the stepper. Use its value to create a CGFloat between 0.0 and 1.0 representing the shade percentage.
  • If the stepper’s value is positive, use lighten(byPercentage:) to shade the color lighter.
  • If the stepper’s value is negative, use darken(byPercentage:) to shade the color darker.

Now, back to paintImages() where all the magic happens. The first line of the method sets the color you’ll use to create the color scheme for the images.

let baseColor = selectedColor

Change this line to use the shaded color as the base color instead:

let baseColor = selectedColorWithShade

Great! Now build and run the app, and play around with the stepper. Now you can design a living room set for even the most pickiest of couch potatoes :]

Theming the App

The color picker has reached its final form! But the app itself is still looking rather dull. Luckily, Chameleon still has a few tricks up its sleeves.

In ViewController.swift find updateAppTheme(), which fires whenever you update selectedColor. Give the method the following implementation:

Chameleon.setGlobalThemeUsingPrimaryColor(selectedColor, with: .contrast)

And before you can say Voilà, you’ve updated the entire app’s theme!

Build and run the app. Now, select a new color, and see how this simple bit of code adds some liveliness to the app.

There are a few problems, though. For instance, the stock-standard UIButtons in the Color Picker don’t look so great with the new theming.

Fortunately, you can fix that with a bit of styling. In ColorPickerViewController.swift, locate styleButtons(). Add the following code to make the buttons a bit more pleasing to the eye:

buttons.forEach {
  $0.layer.cornerRadius = 10
  $0.contentEdgeInsets = UIEdgeInsets(top: 8, left: 8, bottom: 8, right: 8)
}

buttons is an IBOutletCollection that contains the offending Random and Ray Wenderlich Green buttons. styleButtons() rounds the borders of each button and applies an inset to give them some padding. Build and run to see the difference.

There’s another interesting thing to note with the global app theming. Were you wondering what .contrast does in the line of code you added to updateAppTheme()? That’s the UIContentStyle.

It can be one of three values:

  • UIContentStyle.contrast
  • UIContentStyle.light
  • UIContentStyle.dark

Build and run the app, and select a dark color from the color picker. Take a look at the text color of the buttons in the color picker:

Now, select a light color.

UIContentStyle.contrast ensures that the text is always readable; you get white text on dark backgrounds, and black text on light backgrounds.

Setting the global app theme gets you most of the way to a snazzy app, but there’s still some work to do! Such as, the navigation bar is still white. It’d look much better if it matched the app’s theme. To do this, inside ViewController.swift you can update its tint color in updateAppTheme() by adding:

navigationController?.navigationBar.barTintColor = selectedColor

Do a build and run. Then select a few different colors.

Uh-oh! The navigation bar still isn’t correct. The title doesn’t update to contrast the bar’s tint color. The status bar also stays the same, making it difficult to read.

Thankfully, Chameleon can fix that too!

Adding Contrast

To fix this discrepancy between the colors of the back button and navigation title, ensure that the navigation bar title color contrasts the selectedColor. Add the following to the end of updateAppTheme():

let contrastingColor = UIColor(contrastingBlackOrWhiteColorOn:selectedColor, 
                               isFlat: true)
navigationController?.navigationBar.titleTextAttributes = [.foregroundColor : contrastingColor]

Great! With that addition, updateAppTheme() should look like this.

func updateAppTheme() {
  Chameleon.setGlobalThemeUsingPrimaryColor(selectedColor, with: .contrast)
  navigationController?.navigationBar.barTintColor = selectedColor
  let contrastingColor = UIColor(contrastingBlackOrWhiteColorOn:selectedColor, isFlat: true)
  navigationController?.navigationBar.titleTextAttributes = 
    [.foregroundColor : contrastingColor]
}

It’s time for another build and run. This time, the navigation bar’s text always updates to contrast the background.

Setting the global app theme like you did earlier with setGlobalThemeUsingPrimaryColor(_:with:) will update the status bar as well. So why isn’t it changing?

To fix the status bar, open Info.plist. Hover over Information Property List, and tap the plus button to add a new property. Enter View controller-based status bar appearance as the name, set the type to Boolean and the value to NO.

This is all you need to give Chameleon control over the status bar. Build and run the app, and you should see the navigation bar’s back button, title, and the status bar, all change as you switch colors.

Gradient Colors

You’ve applied global app theming and you did the extra work to keep the colors compatible with each other. Now, there’s one last change you can do to make the app stand out.

In ViewController.swift, find showColorPicker(_:), and add the following line before calling navigationController?.pushViewController:

colorPicker.view.backgroundColor = selectedColor

This will set the color picker’s background color to the last color you selected. Give it a build run, and take a look.

No, thanks! The selected color blends in with the buttons, the navigation bar, and the other colors. A gradient color would work better here. You can add some life to the empty part of the color picker while keeping the rest of it with a plain, white background.

Remove the line of code that you added to showColorPicker(_:) and replace it with this:

colorPicker.view.backgroundColor = UIColor(gradientStyle: .topToBottom,
                                           withFrame: colorPicker.view.frame,
                                           andColors: [.flatWhite, .flatWhite, 
                                                       selectedColor])

This sets the background color to a top-to-bottom gradient. The top two-thirds is Chameleon’s flat white and the bottom one-third is the selected color. You pass colorPicker.view.frame for Chameleon to determine how to break up the different colors in the gradient.

You’re done! Build and run the app, and take a look at your finished product.

Where To Go From Here?

As you’ve seen, Chameleon lets you work with colors and theme your app with ease. You can download the completed version of the project using the Download Materials button at the top or bottom of this tutorial.

Don’t forget to take a look at the Chameleon Documentation to stay up-to-date with all the new features.

Do you want to learn more about Color Theory? Building the projects from our iOS Tutorials will help to develop an eye for UI design.

If you have any questions about this tutorial, or about Chameleon and color theory in general, we’d love to hear from you in the discussion forum below!

The post Chameleon on iOS: Getting Started appeared first on Ray Wenderlich.

Android ListView Tutorial with Kotlin

$
0
0

Update Note: This tutorial is now up to date with the latest version of Android Studio version 3.0.1, and uses Kotlin for app development. Update by Joe Howard. Original tutorial by Odie Edo-Osagie.

How many times have you needed an app to display a group of related items in a list? How about all the time. :]

Displaying a specific list is essential to the function of almost any app that queries a set of data and returns a list of results, so many apps need to do this at one point or another. For instance, maybe you have a chat app that queries a certain social platform’s database to find your friends, and then want to display them in a list that lets you select which friends to connect with.

Any time you need to display a lot of data and make it easy to navigate, you’ve got a job for Android’s ListView, which handily creates scrollable lists.

In recent years, ListView has been supplanted by RecyclerView. Nevertheless, studying ListView still has it’s benefits:

  • You can gain insights into why RecyclerView works the way it does
  • You may run into ListView in legacy code, and it’s best to know how to work with it

By working through this tutorial, you’ll become familiar with ListView, and you’ll do so by creating a recipe list app. Specifically, you’ll learn:

  • How to construct and populate a ListView
  • How to customize the layout
  • How to style and beautify a ListView
  • How to optimize a ListView’s performance

You’re welcome to up your game in the kitchen by learning the recipes too, but maybe wait until you’ve built the app, okay?

Note: If you’re new to Android Development or Kotlin, it’s highly recommended that you start with Beginning Android Development with Kotlin to learn your way around the basic tools and concepts.

Getting Started

To kick things off, start by downloading the materials for this tutorial (you can find a link at the top or bottom of the page) and open Android Studio 3.0.1 or greater.

In the Welcome to Android Studio dialog, select Open an existing Android Studio project.

Welcome to Android Studio

In the following dialog, select the top-level directory of the starter project AllTheRecipes-Starter and click OK.

Open Dialog

Inside the imported project, you’ll find some assets and resources that you’ll use to create your app, such as strings, colors, XML layout files, and fonts. Additionally, there’s some boilerplate code modeling a Recipe and a bare bones MainActivity class.

Build and run. You should see something like this:

First run

Are you ready to get cracking on this list thing? Awesome!

Add Your First ListView

The first order of business is to add a ListView to MainActivity.

Open res/layout/activity_main.xml. As you may know, this is the file that describes the layout of MainActivity. Add a ListView to MainActivity by inserting the following code snippet inside the ConstraintLayout tag:

<ListView
  android:id="@+id/recipe_list_view"
  android:layout_width="0dp"
  android:layout_height="0dp"
  app:layout_constraintBottom_toBottomOf="parent"
  app:layout_constraintEnd_toEndOf="parent"
  app:layout_constraintStart_toStartOf="parent"
  app:layout_constraintTop_toTopOf="parent" />

Open MainActivity and add an instance variable for your ListView with the following line:

private lateinit var listView ListView

Add the following snippet below the existing code inside the onCreate method:

listView = findViewById<ListView>(R.id.recipe_list_view)
// 1
val recipeList = Recipe.getRecipesFromFile("recipes.json", this)
// 2
val listItems = arrayOfNulls<String>(recipeList.size)
// 3
for (i in 0 until recipeList.size) {
  val recipe = recipeList[i]
  listItems[i] = recipe.title
}
// 4
val adapter = ArrayAdapter(this, android.R.layout.simple_list_item_1, listItems)
listView.adapter = adapter

Here’s a breakdown of what’s happening in there:

  1. This loads a list of Recipe objects from a JSON asset in the app. Notice that the starter project contains a Recipe class that models and stores the information about the recipes that will be displayed.
  2. This creates an array of strings that’ll contain the text to be displayed in the ListView.
  3. This populates the ListView’s data source with the titles of the recipes loaded in section one.
  4. This creates and sets a simple adapter for the ListView. The ArrayAdapter takes in the current context, a layout file specifying what each row in the list should look like, and the data that will populate the list as arguments.

Enough talk! Your ListView has all that it needs to function. Build and run the project. You should see something like this:

First ListView

Adapters: Servants of the ListView

Your recipe app is starting to look functional, but not all that appetizing…yet.

In the previous section, you successfully built a list of recipe titles. It works, but it’s nothing to get excited about. What if you needed to show more than just the titles? More than just text? Maybe even add some screen-licking worthy thumbnails?

For these cases, the simple ArrayAdapter you just used won’t cut it. You’ll have to take matters into your own hands and write your own adapter. Well, you won’t actually write your own adapter, per se; you’ll simply extend a regular adapter and make some tweaks.

What Exactly is an Adapter?

An adapter loads the information to be displayed from a data source, such as an array or database query, and creates a view for each item. Then it inserts the views into the ListView.

Adapters not only exist for ListViews, but for other kinds of views as well; ListView is a subclass of AdapterView, so you can populate it by binding it to an adapter.

Adapters

The adapter acts as the middle man between the ListView and data source, or its provider. It works kind of like this:

The ListView asks the adapter what it should display, and the adapter jumps into action:

  • It fetches the items to be displayed from the data source
  • It decides how they should be displayed
  • It passes this information on to the ListView
  • In short, The ListView isn’t very smart, but when given the right inputs it does a fine job. It fully relies on the adapter to tell it what to display and how to display it.

    Building Adapters

    Okay, now that you’ve dabbled in theory, you can get on with building your very own adapter.

    Create a new class by right-clicking on the com.raywenderlich.alltherecipes package and selecting New > Kotlin File/Class. Name it RecipeAdapter and define it with the following:

    class RecipeAdapter : BaseAdapter() {
    }
    

    You’ve made the skeleton of the adapter. It extends the BaseAdapter class, which requires several inherited methods you’ll implement after taking care of one more detail.

    Update the RecipeAdapter class as follows:

    class RecipeAdapter(private val context: Context,
                        private val dataSource: ArrayList<Recipe>) : BaseAdapter() {
      
      private val inflater: LayoutInflater
          = context.getSystemService(Context.LAYOUT_INFLATER_SERVICE) as LayoutInflater
    }
    

    In here, you’ve added the properties that will be associated with the adapter and defined a primary constructor for RecipeAdapter.

    Your next step is to implement the adapter methods. Kick it off by placing the following code at the bottom of RecipeAdapter:

    //1
    override fun getCount(): Int {
      return dataSource.size
    }
    
    //2
    override fun getItem(position: Int): Any {
      return dataSource[position]
    }
    
    //3
    override fun getItemId(position: Int): Long {
      return position.toLong()
    }
    
    //4
    override fun getView(position: Int, convertView: View?, parent: ViewGroup): View {
      // Get view for row item
      val rowView = inflater.inflate(R.layout.list_item_recipe, parent, false)
        
      return rowView
    }
    

    Here’s a step-by-step breakdown:

    1. getCount() lets ListView know how many items to display, or in other words, it returns the size of your data source.
    2. getItem() returns an item to be placed in a given position from the data source, specifically, Recipe objects obtained from dataSource.
    3. This implements the getItemId() method that defines a unique ID for each row in the list. For simplicity, you just use the position of the item as its ID.
    4. Finally, getView() creates a view to be used as a row in the list. Here you define what information shows and where it sits within the ListView. You also inflate a custom view from the XML layout defined in res/layout/list_item_recipe.xml — more on this in the next section.

    Defining the Layout of the ListView’s Rows

    You probably noticed that the starter project comes with the file res/layout/list_item_recipe.xml that describes how each row in the ListView should look and be laid out.

    Below is an image that shows the layout of the row view and its elements:

    List item row

    Your task is to populate each element of the row view with the relevant recipe data, hence, you’ll define what text goes in the “title” element, the “subtitle” element and so on.

    In the getView() method, add the following code snippet just before the return statement:

    // Get title element
    val titleTextView = rowView.findViewById(R.id.recipe_list_title) as TextView
    
    // Get subtitle element
    val subtitleTextView = rowView.findViewById(R.id.recipe_list_subtitle) as TextView
    
    // Get detail element
    val detailTextView = rowView.findViewById(R.id.recipe_list_detail) as TextView
    
    // Get thumbnail element
    val thumbnailImageView = rowView.findViewById(R.id.recipe_list_thumbnail) as ImageView
    

    This obtains references to each of the elements (or subviews) of the row view, specifically the title, subtitle, detail and thumbnail.

    Now that you’ve got the references sorted out, you need to populate each element with relevant data. To do this, add the following code snippet under the previous one but before the return statement:

    // 1
    val recipe = getItem(position) as Recipe
    
    // 2
    titleTextView.text = recipe.title
    subtitleTextView.text = recipe.description
    detailTextView.text = recipe.label
    
    // 3
    Picasso.with(context).load(recipe.imageUrl).placeholder(R.mipmap.ic_launcher).into(thumbnailImageView)
    

    Here’s what you’re doing in the above snippet:

    1. Getting the corresponding recipe for the current row.
    2. Updating the row view’s text views so they are displaying the recipe.
    3. Making use of the open-source Picasso library for asynchronous image loading — it helps you download the thumbnail images on a separate thread instead of the main thread. You’re also assigning a temporary placeholder for the ImageView to handle slow loading of images.
    Note: You should never perform long-running tasks on the main thread. When you do, you expose yourself to the risk of blocking the UI, and that would make scrolling your lists a nightmare!

    Now open up MainActivity so that you can get rid of the old adapter. In onCreate, replace everything below (but not including) this line:

    val recipeList = Recipe.getRecipesFromFile("recipes.json", this)
    

    With:

    val adapter = RecipeAdapter(this, recipeList)
    listView.adapter = adapter
    

    You just replaced the rather simple ArrayAdapter with your own RecipeAdapter to make the list more informative.

    Build and run and you should see something like this:

    Using recipe adapter

    Now you’re cooking for real! Look at those recipes — thumbnails and descriptions sure make a big difference.

    Styling

    Now that you’ve got the functionality under wraps, it’s time to turn your attention to the finer things in life. In this case, your finer things are elements that make your app more snazzy, such as compelling colors and fancy fonts.

    Start with the fonts. Look for some custom fonts under res/font. You’ll find three font files: josefinsans_bold.ttf, josefinsans_semibolditalic.ttf and quicksand_bold.otf.

    Open RecipeAdapter.java and go to the getView() method. Just before the return statement, add the following:

    val titleTypeFace = ResourcesCompat.getFont(context, R.font.josefinsans_bold)
    titleTextView.typeface = titleTypeFace
        
    val subtitleTypeFace = ResourcesCompat.getFont(context, R.font.josefinsans_semibolditalic)
    subtitleTextView.typeface = subtitleTypeFace
    
    val detailTypeFace = ResourcesCompat.getFont(context, R.font.quicksand_bold)
    detailTextView.typeface = detailTypeFace
    

    In here, you’re assigning a custom font to each of the text views in your rows’ layout. You access the font by creating a Typeface, which specifies the intrinsic style and typeface of the font, by using ResourcesCompat.getFont(). Next you set the typeface for the corresponding TextView to set the custom font.

    Now build and run. Your result should look like this:

    Custom fonts

    On to sprucing up the colors, which are defined in res/values/colors.xml. Open up RecipeAdapter and add the following below the inflater declaration:

    companion object {
      private val LABEL_COLORS = hashMapOf(
          "Low-Carb" to R.color.colorLowCarb,
          "Low-Fat" to R.color.colorLowFat,
          "Low-Sodium" to R.color.colorLowSodium,
          "Medium-Carb" to R.color.colorMediumCarb,
          "Vegetarian" to R.color.colorVegetarian,
          "Balanced" to R.color.colorBalanced
      ) 
    }
    

    You’ve created a hash map that pairs a recipe detail label with the resource id of a color defined in colors.xml.

    Now go to the getView() method, and add this line just above the return statement:

    detailTextView.setTextColor(
        ContextCompat.getColor(context, LABEL_COLORS[recipe.label] ?: R.color.colorPrimary))
    

    Working from the inside out:

    • Here you get the resource id for the color that corresponds to the recipe.label from the LABEL_COLORS hash map.
    • getColor() is used inside of ContextCompat to retrieve the hex color associated with that resource id.
    • Then you set the color property of the detailTextView to the hex color.

    Build and run. Your app should look like this:

    Adding label colors

    User Interaction

    Now your list has function and style. What’s it missing now? Try tapping or long pressing it. There’s not much to thrill and delight the user.

    What could you add here to make the user experience that much more satisfying? Well, when a user taps on a row, don’t you think it’d be nice to show the full recipe, complete with instructions?

    You’ll make use of AdapterView.onItemClickListener and a brand spanking new activity to do this with elegance.

    Make a New Activity

    This activity will display when the user selects an item in the list.

    Right-click on com.raywenderlich.alltherecipes then select New > Activity > EmptyActivity to bring up a dialog. Fill in the Activity Name with RecipeDetailActivity. Leave the automatically populated fields as-is. Check that your settings match these:

    New Activity dialog

    Click Finish.

    Open res/layout/activity_recipe_detail.xml and add a WebView by inserting the following snippet inside the ConstraintLayout tag:

    <WebView
      android:id="@+id/detail_web_view"
      android:layout_width="0dp"
      android:layout_height="0dp"
      app:layout_constraintBottom_toBottomOf="parent"
      app:layout_constraintEnd_toEndOf="parent"
      app:layout_constraintStart_toStartOf="parent"
      app:layout_constraintTop_toTopOf="parent" />
    

    WebView will be used to load and display a webpage containing the selected recipe’s instructions.

    Open up RecipeDetailActivity, and add a WebView reference as a property by adding the following line within the class definition:

    private lateinit var webView: WebView
    

    Add the following below the webView property declaration:

    companion object {
      const val EXTRA_TITLE = "title"
      const val EXTRA_URL = "url"
    
      fun newIntent(context: Context, recipe: Recipe): Intent {
        val detailIntent = Intent(context, RecipeDetailActivity::class.java)
    
        detailIntent.putExtra(EXTRA_TITLE, recipe.title)
        detailIntent.putExtra(EXTRA_URL, recipe.instructionUrl)
          
        return detailIntent
      }
    }
    

    This adds a companion object method to return an Intent for starting the detail activity, and sets up title and url extras in the Intent.

    Head back to MainActivity and add the following to the bottom of the onCreate method:

    val context = this
    listView.setOnItemClickListener { _, _, position, _ ->
      // 1
      val selectedRecipe = recipeList[position]
    
      // 2
      val detailIntent = RecipeDetailActivity.newIntent(context, selectedRecipe)
    
      // 3
      startActivity(detailIntent)
    }
    

    Note: Before you dive into the explanation, make sure you understand the four arguments that are provided by onItemClick; they work as follows:

    • parent: The view where the selection happens — in your case, it’s the ListView
    • view: The selected view (row) within the ListView
    • position: The position of the row in the adapter
    • id: The row id of the selected item

    You’re setting the OnItemClickListener object for the ListView, and inside doing the following:

    1. Get the recipe object for the row that was clicked
    2. Create an intent to navigate to your RecipeDetailActivity to display more information
    3. Launch the RecipeDetailActivity by passing the intent object you just created to the startActivity() method.
    Note: To learn more about intents, check out the awesome Android Intents Tutorial.

    Once again, open RecipeDetailActivity and add the following snippet at the bottom of the onCreate method:

    // 1
    val title = intent.extras.getString(EXTRA_TITLE)
    val url = intent.extras.getString(EXTRA_URL)
    
    // 2
    setTitle(title)
    
    // 3
    webView = findViewById(R.id.detail_web_view)
    
    // 4
    webView.loadUrl(url)
    

    You can see a few things happening here:

    1. You retrieve the recipe data from the Intent passed from MainActivity by using the extras property.
    2. You set the title on the action bar of this activity to the recipe title.
    3. You initialize webView to the web view defined in the XML layout.
    4. You load the recipe web page by calling loadUrl() with the corresponding recipe’s URL on the web view object.

    Build and run. When you click on the first item in the list, you should see something like this:

    Recipe detail

    Optimizing Performance

    Whenever you scroll the ListView, its adapter’s getView() method is called in order to create a row and display it on screen.

    Now, if you look in your getView() method, you’ll notice that each time this method is called, it performs a lookup for each of the row view’s elements by using a call to the findViewById() method.

    These repeated calls can seriously harm the ListView’s performance, especially if your app is running on limited resources and/or you have a very large list. You can avoid this problem by using the View Holder Pattern.

    Implement a ViewHolder Pattern

    To implement the ViewHolder pattern, open RecipeAdapter and add the following after the getView() method definition:

    private class ViewHolder {
      lateinit var titleTextView: TextView
      lateinit var subtitleTextView: TextView
      lateinit var detailTextView: TextView
      lateinit var thumbnailImageView: ImageView
    }
    

    As you can see, you create a class to hold your exact set of component views for each row view. The ViewHolder class stores each of the row’s subviews, and in turn is stored inside the tag field of the layout.

    This means you can immediately access the row’s subviews without the need to look them up repeatedly.

    Now, in getView(), replace everything above (but NOT including) this line:

    val recipe = getItem(position) as Recipe
    

    With:

    val view: View
    val holder: ViewHolder
    
    // 1
    if (convertView == null) {
    
      // 2
      view = inflater.inflate(R.layout.list_item_recipe, parent, false)
    
      // 3
      holder = ViewHolder()
      holder.thumbnailImageView = view.findViewById(R.id.recipe_list_thumbnail) as ImageView
      holder.titleTextView = view.findViewById(R.id.recipe_list_title) as TextView
      holder.subtitleTextView = view.findViewById(R.id.recipe_list_subtitle) as TextView
      holder.detailTextView = view.findViewById(R.id.recipe_list_detail) as TextView
    
      // 4
      view.tag = holder
    } else {
      // 5
      view = convertView
      holder = convertView.tag as ViewHolder
    }
    
    // 6
    val titleTextView = holder.titleTextView
    val subtitleTextView = holder.subtitleTextView
    val detailTextView = holder.detailTextView
    val thumbnailImageView = holder.thumbnailImageView
    

    Here’s the play-by-play of what’s happening above.

    1. Check if the view already exists. If it does, there’s no need to inflate from the layout and call findViewById() again.
    2. If the view doesn’t exist, you inflate the custom row layout from your XML.
    3. Create a new ViewHolder with subviews initialized by using findViewById().
    4. Hang onto this holder for future recycling by using setTag() to set the tag property of the view that the holder belongs to.
    5. Skip all the expensive inflation steps and just get the holder you already made.
    6. Get relevant subviews of the row view.

    Finally, update the return statement of getView() with the line below.

    return view
    

    Build and run. If your app was running a bit slow on the last build, you should see it running smoother now. :]

    Where to Go From Here?

    You can download the completed project using the download button at the top or bottom of this tutorial.

    When you develop for Android, AdapterViews are a common concept that you’ll run into over and over again.

    If you want to know more about the inner workings of the ListView and performance details, check out this article on performance tips for Android ListViews.

    There are other ways to create lists, such as subclassing a ListActivity and ListFragment. Both of these links take you to the official Android developer site so that you can learn more about how they work.

    Both of these alternatives impose the restriction that the respective activity or fragment can only contain a ListView as its child view. Suppose you wanted an activity that had a ListView as well as some other views, it would be impossible with a ListActivity. The same goes for the ListFragment scenario.

    And be sure to check out our RecyclerView and Intermediate RecyclerView tutorials to see the more modern way to show lists on Android. Unlike ListView, RecyclerView enforces the use of the ViewHolder pattern and is much more flexible in terms of layout and animation.

    Feel free to share your feedback, findings or ask any questions in the comments below or in the forums. Talk to you soon!

    The post Android ListView Tutorial with Kotlin appeared first on Ray Wenderlich.


    Video Tutorial: Server Side Swift with Vapor Part 2: Models And Fluent

    Video Tutorial: Server Side Swift with Vapor Part 2: Controllers and CRUD

    Readers’ App Reviews – February 2018

    $
    0
    0

    Now that the year has begun, everyone has been hard at work on some cool new apps. Let’s check them out!

    I’m honored you are taking a quick break to see what the community has been building. Every month, readers like you release great apps built with a little help from our tutorials, books, and videos.

    Today, I’d like to highlight a few to give just a peek at what our fantastic readers are creating.

    This month we have:

    • An interesting reminder app
    • A cool side-scroller game
    • A tip calculator
    • And of course, much more!

    Keep reading to see the latest apps released by raywenderlich.com readers just like you.

    TipMyBill


    If you are ever at a restaurant and have a hard time figuring out how much you should tip your server, Tip My Bill is here to lend you a hand.

    Tip My Bill is an app that is designed to help you figure out how much you should tip. All you have to do is put in the amount you spent on food, drinks, and tax. Then, select what percentage tip you want to give and Tip My Bill will tell you how much to tip as well as what your total will be after tipping.

    This is a quick and easy way to figure out your tip. Download Tip My Bill and be ready for the next time you go out to eat!

    Break the Bricks


    If you love brick breaker game as much as I do, then you will really enjoy Break the Bricks.

    Break the Bricks is a block breaker game where you have to bounce a ball off of a platform so that it can travel up and break the line of bricks above you. This is a classic game, but Break the Bricks is filled with fun power-ups such as extra balls, speed increases, platform width increases, and many more.

    I had a lot of fun playing Break the Bricks and I am sure you will too. Download it and give it a try!

    Coiny Block


    Are you a fan of clocker games like Clicker Hero or Cookie Clicker, but think that they could use a little extra? Coiny Block thought so too, so they added a twist!

    Coiny Block is similar to other clicker games except that there are obstacles that you must avoid while you are clicking.

    This mechanic completely changes how enjoyable and engaging games like this are. Instead of just mindlessly clicking the same spot multiple times until you level up, you must pay attention to the objects on screen and dodge them while you are clicking. Otherwise, you will lose your lives and all that clicking will be for nothing!

    Coiny Block is a simple game, but it is very fun! Download it and try it out!

    Bouncy Ball NG


    Side scrollers have been a staple in video games since their beginnings, but Bouncy Ball NG helps to spice up the genre a bit more by adding one new mechanic.

    In Bouncy Ball NG you control a ball that must move through a multitude of levels and collect green bricks. After you collect enough, a blue brick will appear somewhere in the level that will allow you to exit.

    The difference between this and other games, however, is that your ball is constantly moving up and down and you must time the left and right motions correctly in order to move through the level. This is a very fun concept and a great take on a classic genre.

    Download Bouncy Ball and play it for a few minutes, hours, weeks, its great!

    Work Hours Agent


    Do you work on your own schedule or would like to schedule yourself in a more efficient way? Well, Work Hours Agent is here to help.

    Work Hours Agent allows you to start and stop your work hour times. You can also pause and play the timer in the case of any breaks or disruptions you might experience during your work time. Then, after your work day is over if logs your times and keeps track of them. You can even print your times out in a PDF format if you need to.

    Work Hours Agent is a great app for keeping up with your work times and might even help you win your overtime claims! Download it and try it out on your next work cycle.

    Orson Remind Me


    If you have trouble keeping all of your tasks in order and making sure you have everything done for the day, then Orson Remind Me might be just what you need in order to fix this issue.

    Orson Remind Me is a reminder app that gives you a new cat assistant named Orson! Orson will help to remind you of things you need to do in three different ways. The first is a little nudge, the second is a normal reminder, and the third will pester you multiple times to make sure that you do the task. Also, there is an achievement system that you can get rewards from for completing tasks on time.

    Orson Remind Me is a simple and fun way to make sure that you are getting everything done! If you need more organization, download it and let Orson be your guide.

    Tiny Crossword Blitz


    Crossword puzzles are always a fantastic way to pass time, have fun, and keep your brain engaged. Tiny Crossword Blitz is here to supply you with many great crossword puzzles to complete.

    Tiny Crossword Blitz is a crossword puzzle app that is really easy to use. Just select your game type and drag in the letters from the bottom of the screen into the spot where you think they need to go. There are some handy buttons at the bottom for undoing a previous move, clearing the entire board, and giving you a hint if you are stuck.

    Tiny Crossword Blitz has over three hundred levels for you to complete! So, you should download it and get started!

    Where To Go From Here?

    Each month, I really enjoy seeing what our community of readers comes up with. The apps you build are the reason we keep writing tutorials. Make sure you tell me about your next one, submit here.

    If you saw an app you liked, hop to the App Store and leave a review! A good review always makes a dev’s day. And make sure you tell them you’re from raywenderlich.com; this is a community of makers.

    If you’ve never made an app, this is the month! Check out our free tutorials to become an iOS star. What are you waiting for – I want to see your app next month.

    The post Readers’ App Reviews – February 2018 appeared first on Ray Wenderlich.

    Video Tutorial: Server Side Swift with Vapor Part 2: Finishing CRUD

    Video Tutorial: Server Side Swift with Vapor Part 2: Challenge: Users And Categories

    Viewing all 4400 articles
    Browse latest View live


    <script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>