How to add a video that plays behind your controls in iOS

Having a video playing behind the controls of your app’s main menu immediately catches the eye of your users and people around them.

This feature is not difficult to implement; it’s actually very simple. Let me show you how to do it. The video at the bottom of this page shows the result. If you want to download a project that uses this technique, click here.

A canvas to draw on

Objects of type UIView are the visible components in iOS. Every UIView has a layer property of type CALayer. This is where the visual content exists.

CALayers can be used to draw shapes, particles, text, gradients, video, etc. For the specific case of video, a CALayer subclass called AVPlayerLayer simplifies the process of video playback.

To display video on a UIView object, the recipe is as follows:

1-Create an AVPlayerLayer object.

2-Assign a video player object (AVPlayer) to the AVPlayerLayer.player property.

3-Set the frame of your AVPlayerLayer object

4-Add the AVPlayerLayer as a sublayer of your view’s layer property.

5-Start playback by calling play() on the video player object.

This is the code:

A helper class

The example project at the top contains a helper UIView class to make our lives easier when implementing the video feature. It’s called PlayVideoView. In it, an object of type AVPlayerLooper is used to loop the video.

This is how to use the helper class:
1-Add a PlayVideoView object to your view controller’s main view, either programmatically or via Interface Builder.

2- In your view controller’s viewDidLoad method, call the setVideo method of the PlayVideoView object to set the video to play

3-In your view controller’s viewWillAppear method, get the player associated to the PlayVideoView object and call play() on it.

4- In your view controller’s viewWillDisappear method, get the player associated to the PlayVideoView object and call pause() to stop playback.

Here’s how to implement it:

Interruption handling

The above code pauses/resumes playback when the view is shown or hidden.

But what happens when you minimize the app and then open it again (keep in mind viewWillDisappear won’t be called when the app is minimized)?

Well, it depends. In iOS 13, video will resume playing automatically, as expected.

In iOS 12 and less, however, it won’t resume playing automatically. That’s not good.

To fix this glitch, your view controller must respond to the following notifications:

  • UIApplication.didBecomeActiveNotification
  • UIApplication.willResignActiveNotification

When you receive the didBecomeActiveNotification notification, call play() on the video player. For the willResignActiveNotification notification, call pause().

It doesn’t hurt if you implement these and your app runs in iOS 13; it won’t break anything. The example project implements interruption handling.

The fine print

Video playback is a demanding task, for this reason it’s recommended to use short videos and to limit this feature to the sections where it’s really needed.

Depending on the type of app you’re developing, you might want to play the video silently or with music. A game I worked on some time ago played a video with music in the main menu, which was appropriate for this type of app. Another app I worked, for a very different type of audience, solemnly displayed a silent video in the main menu.


Custom Controls not working in AVPlayerViewController in iOS 12

I recently stumbled across a bug in the AVPlayerViewController class. If you’re not familiar with this AVKit class, it’s a handy object used to play videos in iOS.

The bug happens when you use custom playback controls. Under some circumstances, your controls will stop responding. The bug is fixed in the upcoming iOS 13, but the app I was developing will be used in devices that currently have iOS 12 and can’t be upgraded. So finding a solution was our only option. It turned out that solution was easy to implement. Let me explain the details of the bug and how to fix it.

System-supplied and custom playback controls

By default, an AVPlayerViewController object shows system-supplied playback controls. You can combine or replace these controls with your own custom controls.

The showsPlaybackControls property of AVPlayerViewController objects controls whether you want the system-supplied playback controls.

To provide your custom controls, access the contentOverlayView property and add your views using addSubview

Custom controls not responding

For my case, I needed the following:

1-Start playback with custom playback controls.

2-At some point, hide the custom controls and show the system-supplied playback controls.

3-After some time, go back to the custom playback controls.

The problem was that, after hiding the system-supplied playback controls (point 3, above), the custom controls stopped working. See the video below for more details.

The view hierarchy explains it all

If you examine the view hierarchy you will find that the system-supplied playback controls are contained in a view of type AVPlaybackControlsView (this class is private and was introduced in iOS 11).

In iOS 12, starting playback with showsPlaybackControls = false will result in an object with no AVPlaybackControlsView view, as shown in Image 1 below.

Image 1 – Starting playback with showsPlaybackControls = false will result in an object with no AVPlaybackControlsView view

If you later set showsPlaybackControls = true, a view of type AVPlaybackControlsView will be created. However, if later on you deactivate the system-supplied playback controls using showsPlaybackControls = false, its view will stay at the top of the hierarchy, thus preventing input from reaching your custom controls. See Image 2 below.

Image 2 – Even if you deactivate the system-supplied playback controls, its view (of type AVPlaybackControlsView) will stay at the top of the hierarchy, thus preventing input from reaching your custom controls.

The fix

Since an AVPlaybackControlsView view is blocking the input, we can either remove it or hide/disable it.

I have found that, if removed, it won’t be added again when setting showsPlaybackControls = true. So the best fix simply consists in hiding/disabling it. Of course, if later on you want to show the system controls again, you will need to unhide/enable it.

The video below shows the result after the above fix is applied.

A demo project

You can download a project which implements the fix.


Using DispatchSemaphore to make synchronous calls in Swift

Modern-day CPUs are capable of running multiple execution threads simultaneously. This capability is called multi-threading and allows executing multiple tasks at the same time.

In programming, this capability is closely related to what is called synchronous (sync) calls and asynchronous (async) calls. A synchronous call will block the execution of the thread until the call is completed.

An asynchronous call, on the other hand, will not block the current thread because it will be executed in a different thread.

Nowadays, many API calls are asynchronous. When the call completes, the result is passed to the calling thread. That’s the current state of things, and we’re happy and grateful for that.

Nevertheless there are some cases where you might want to wait, that is, block execution, until a number of async calls complete. To accomplish this, you can use a semaphore. The following playground code shows how:

import UIKit

func synchronousTask(taskID : Int) {
    let semaphore = DispatchSemaphore(value: 0) // see note below
    print("Waiting for task \(taskID) to complete")

    // dispatch work to a different thread .background).async {
        print("Starting task \(taskID)")
        sleep(3)    // simulate the duration of the task
        print("Ending task \(taskID)")
    semaphore.wait()        // block until the task completes
    print("Task \(taskID) is completed")

// semaphores shouldn't be used on the main thread .background).async {
    synchronousTask(taskID: 1)

Value used for semaphore initialization.

The value used in the DispatchSemaphore initialization is related to its purpose. According to Apple: “Passing zero for the value is useful for when two threads need to reconcile the completion of a particular event.”

Since this is what we want, we initialize the semaphore with a value of zero.

The above code produces the following output:

Waiting for more than one task to complete.

If you need to wait for the completion of more than 1 task, simply write a wrapper function to call the synchronous code, as shown in the following code:

import UIKit

func synchronousTask(taskID : Int) {
    let semaphore = DispatchSemaphore(value: 0)
    print("Waiting for task \(taskID) to complete")

    // dispatch work to a different thread .background).async {
        print("Starting task \(taskID)")
        sleep(1)    // simulate the duration of the task
        print("Ending task \(taskID)")

    semaphore.wait()        // block until the task completes
    print("Task \(taskID) is completed")

func synchronousCall() {
    print("Waiting for tasks to be executed")
    for i in 1...3 {
        synchronousTask(taskID: i)
    print("All tasks were executed")

// semaphores shouldn't be used on the main thread .background).async {

The above code produces the following output:

Cómo crear contenido con tu celular (memes, videos, etc.)

La creación de contenido es la sangre nueva que ayuda a mantener la vitalidad del internet.

Si tienes inclinación hacia el periodismo basado en fotos y videos, o si simplemente quieres hacer reir a la gente con memes, aquí te presento varias apps, todas gratuitas, que te ayudarán a crear contenidos usando tu celular o tableta.

Creación de memes

Si llegaste a esta página buscando una app para hacer memes, no esperes más y descarga Meme Generator (iOS, Android). Hay miles de apps para memes, pero esta es, a mi juicio, una de las fáciles de usar. Al final de este documento encontrarás ejemplos de memes creados con esta app.

Combinar varias fotos

Hay ocasiones en que es más conveniente una foto combinada que publicar varias fotos por separado.

Pic Stitch (iOS, Android) te ayuda a combinar fotos con diferentes diseños. También permite aplicar efectos, calcomanías y agregar texto.

Agregar textos llamativos a tus fotos

¿Aburrido con la forma en que Messenger te permite poner texto en tus fotos? Over (iOS) ofrece una buena cantidad de textos predefinidos, de calidad profesional. También puedes escribir tu propio texto. Esta app es usada por revistas para dar un toque especial a sus imágenes.

Rotación de videos, iOS

Rotate & Flip (iOS) es una app que te permite, fácilmente, rotar tus videos. Increíblemente fácil de usar.

Rotación de videos, Android

Para Android, Google Photos te permite rotar tus videos. Probablemente esta app ya viene instalada en tu dispositivo, pero si no fuera así, puedes instalarla a partir de este enlace: Google Photos

Agregar texto a tus videos

Vont (iOS) es tan fácil de usar que te tomará sólo un par de minutos entenderlo. Y la cantidad de tipos de letra que incluye es impresionante.

Atención periodistas: esta es la app perfecta para agregar una marca de agua a sus videos y evitar que otros se adjudiquen, indebidamente, su autoría.

Recortar y combinar videos

[A partir de septiembre de 2019 esta app ya no está disponible. En su lugar puedes usar Adobe Spark, que también es gratis] Adobe Premiere Clip (iOS, Android) te permitirá recortar tus videos y combinar varios videos en uno solo.
Para usarla, necesitas crear una cuenta de Adobe, la cual es gratuita. Vale la pena.


Ejemplos de contenidos creados con estas apps

Importante: Los siguientes archivos fueron manualmente reducidos en calidad para disminuir el ancho de banda usado. 

Ejemplo de meme creado con Meme Generator, usando una de mis fotos.
Meme Generator incluye gran cantidad de graciosas fotos que puedes utilizar para crear tus memes
Over agrega texto a tus fotos de manera atractiva. Es usado por revistas y otros medios impresos y digitales.

El siguiente video muestra las capacidades de Vont para agregar texto.

A continuación un video creado combinando varios clips con Adobe Premiere Clip