Resources: fonts, images, and video

A card only refers to fonts, images, and video, while the app loads and shows them. This page describes what you need to connect on each platform for that. Element properties are described in Custom fonts, Images, and Video.

Fonts

The app maps the font name from the font_family parameter to a specific font. To do this, each platform implements a font provider that is passed to DivKit during initialization.

Android

On the Android platform, to use custom fonts, you need to implement the DivTypefaceProvider interface.

DivTypefaceProvider Implementation

import android.content.Context;
import android.graphics.Typeface;
import androidx.annotation.Nullable;
import com.yandex.div.core.font.DivTypefaceProvider;

public class CustomTypefaceProvider implements DivTypefaceProvider {
    private final Context context;

    // Cache fonts to improve performance
    private Typeface regularTypeface;
    private Typeface mediumTypeface;
    private Typeface lightTypeface;
    private Typeface boldTypeface;

    public CustomTypefaceProvider(Context context) {
        this.context = context;
    }

    @Nullable
    @Override
    public Typeface getRegular() {
        if (regularTypeface == null) {
            regularTypeface = Typeface.createFromAsset(context.getAssets(), "fonts/MyFont-Regular.ttf");
        }
        return regularTypeface;
    }

    @Nullable
    @Override
    public Typeface getMedium() {
        if (mediumTypeface == null) {
            mediumTypeface = Typeface.createFromAsset(context.getAssets(), "fonts/MyFont-Medium.ttf");
        }
        return mediumTypeface;
    }

    @Nullable
    @Override
    public Typeface getLight() {
        if (lightTypeface == null) {
            lightTypeface = Typeface.createFromAsset(context.getAssets(), "fonts/MyFont-Light.ttf");
        }
        return lightTypeface;
    }

    @Nullable
    @Override
    public Typeface getBold() {
        if (boldTypeface == null) {
            boldTypeface = Typeface.createFromAsset(context.getAssets(), "fonts/MyFont-Bold.ttf");
        }
        return boldTypeface;
    }

    // Optional: override the getTypefaceFor method for more precise control
    // over font weight matching
    @Nullable
    @Override
    public Typeface getTypefaceFor(int weight) {
        if (weight >= 0 && weight < 350) {
            return getLight();
        } else if (weight >= 350 && weight < 450) {
            return getRegular();
        } else if (weight >= 450 && weight < 650) {
            return getMedium();
        } else {
            return getBold();
        }
    }
}

Integration into Application

import com.yandex.div.core.Div2Context;
import com.yandex.div.core.DivConfiguration;
import java.util.Collections;

// When initializing DivKit: activity is your Activity, imageLoader is a DivImageLoader implementation
DivConfiguration configuration = new DivConfiguration.Builder(imageLoader)
    // Default font: for text without font_family and for unknown names
    .typefaceProvider(new CustomTypefaceProvider(activity))
    // Fonts that are selected by the name from font_family
    .additionalTypefaceProviders(
        Collections.singletonMap("MyCustomFont", new CustomTypefaceProvider(activity))
    )
    // other settings
    .build();

Div2Context div2Context = new Div2Context(
    activity,
    configuration
);

iOS

On the iOS platform, to use custom fonts, you need to implement the DivFontProvider protocol.

Adding Fonts to the Project

  1. Add font files (.ttf or .otf) to your project
  2. Make sure the fonts are included in the application resources (Bundle Resources)
  3. Add font information to Info.plist in the Fonts provided by application section:
<key>UIAppFonts</key>
<array>
    <string>MyFont-Regular.ttf</string>
    <string>MyFont-Medium.ttf</string>
    <string>MyFont-Light.ttf</string>
    <string>MyFont-Bold.ttf</string>
</array>

DivFontProvider Implementation

import UIKit
import DivKit
import VGSL

class CustomFontProvider: DivFontProvider {
    func font(family: String, weight: DivFontWeight, size: CGFloat) -> Font {
        // If a specific font family is specified
        if family == "MyCustomFont" {
            let fontName: String
            switch weight {
            case .light:
                fontName = "MyFont-Light"
            case .regular:
                fontName = "MyFont-Regular"
            case .medium:
                fontName = "MyFont-Medium"
            case .bold:
                fontName = "MyFont-Bold"
            }

            if let font = UIFont(name: fontName, size: size) {
                return Font(uiFont: font)
            }
        }

        // Return system font if custom font is not found
        let uiFont: UIFont
        switch weight {
        case .light:
            uiFont = UIFont.systemFont(ofSize: size, weight: .light)
        case .regular:
            uiFont = UIFont.systemFont(ofSize: size, weight: .regular)
        case .medium:
            uiFont = UIFont.systemFont(ofSize: size, weight: .medium)
        case .bold:
            uiFont = UIFont.systemFont(ofSize: size, weight: .bold)
        }

        return Font(uiFont: uiFont)
    }

    // The method for getting a font by numerical weight is already implemented in the protocol extension
}

Integration into Application

import DivKit

// When initializing DivKit
let components = DivKitComponents(
    divCustomBlockFactory: nil,
    fontProvider: CustomFontProvider(),
    // other parameters
)

Web

On the Web platform, to use custom fonts, you need to:

  1. Connect fonts using standard CSS methods (via @font-face or external services)
  2. Use the typefaceProvider parameter when initializing DivKit

Connecting Fonts via CSS

The font family in CSS does not have to match the name in JSON.

Don't forget to provide all the styles and weights options that you will need in your markup (in this example, 400, 500, and 700 are added). Another option is to use variable fonts.

@font-face {
  font-family: 'MyCustomFont';
  src: url('fonts/MyFont-Regular.woff2') format('woff2'),
       url('fonts/MyFont-Regular.woff') format('woff');
  font-weight: 400;
  font-style: normal;
}

@font-face {
  font-family: 'MyCustomFont';
  src: url('fonts/MyFont-Medium.woff2') format('woff2'),
       url('fonts/MyFont-Medium.woff') format('woff');
  font-weight: 500;
  font-style: normal;
}

@font-face {
  font-family: 'MyCustomFont';
  src: url('fonts/MyFont-Bold.woff2') format('woff2'),
       url('fonts/MyFont-Bold.woff') format('woff');
  font-weight: 700;
  font-style: normal;
}

Using typefaceProvider

import { render } from '@divkitframework/divkit/client';

render({
    id: 'my-divkit-container',
    target: document.querySelector('#root'),
    json: {
        card: {
            log_id: 'custom_fonts_example',
            states: [{
                state_id: 0,
                div: {
                    type: 'text',
                    font_family: 'MyCustomFont',
                    font_weight_value: 500,
                    text: 'Text with custom font'
                }
            }]
        }
    },
    typefaceProvider: (fontFamily, opts) => {
        // You can implement mapping of font names from JSON to CSS
        if (fontFamily === 'MyCustomFont') {
            return 'MyCustomFont, sans-serif';
        }

        // For the default option, you can return an empty string.
        return '';
    }
});

Recommendations

  1. Performance Optimization: Cache font instances to avoid reloading.
  2. Support for Different Weights: Implement support for different font weights to ensure design flexibility.
  3. Fallback Options: Always provide fallback font options in case the custom font fails to load.
  4. Font Preloading: For the web platform, it is recommended to preload fonts to avoid text flickering when the page loads.
  5. Testing: Check font rendering on various devices and under different conditions to ensure correct display.

Images

Images are loaded by the app: on Android you connect an image loader for that, and on iOS local images are taken from the app bundle.

iOS

On iOS, to restrict access to resources, all divkit asset images must start with the 'divkit.' prefix. For example, if you use "image_url": "divkit-asset://image.png", the image must be named divkit.image.png in your app's main bundle.

Multiple bundle support

iOS supports specifying a specific bundle for loading images using the bundle parameter in the URL:

{
  "type": "image",
  "image_url": "divkit-asset://image.png?bundle=com.example.app"
}

This feature is useful in modular architectures or when using multiple bundles in an application. On Android, the bundle parameter is ignored.

Android

Image loader support

DivKit for Android supports popular image loading libraries:

  • Coil - modern image loader for Kotlin
  • Glide - traditional image loader

Both loaders support all image formats and effects, including animated WebP and GIF.

Bitmap size limitation

To prevent crashes when loading large images and GIF files, DivKit automatically limits the bitmap size. This feature is enabled by default and helps avoid memory issues on devices.

How the limitation works:

  • The maximum bitmap size is determined by the maximum screen resolution of the device
  • Images exceeding this size are automatically scaled down
  • For SVG images, a separate limitation mechanism is applied
  • The feature is supported by the CoilDivImageLoader and GlideDivImageLoader loaders

Configuring the limitation:

Bitmap size limitation is enabled by default. If you need to disable this feature (for example, when working with very large images), you can configure it in the image loader implementation:

// Example for CoilDivImageLoader
val imageLoader = CoilDivImageLoader(
    context = context,
    limitImageBitmapSizeEnabled = false // Disable limitation
)

Warning

Disabling bitmap size limitation may lead to application crashes when working with very large images. Use this setting with caution.

Video

With DivKit, you can use a standard player or your own one. The latter comes in handy, for example, when you want to play videos in a format that's not supported by the standard player.

Standard player

By default, DivKit uses a standard player for all platforms except Android, where you need to connect the player explicitly.

Android

DivKit uses ExoPlayer as a standard player for Android.

Because ExoPlayer initialization is a heavy operation, the player is only connected when you explicitly specify it in the DivConfiguration class. If you don't plan to use a video player in your app, don't call the .divPlayerFactory method in the DivConfiguration class builder.

To work with the standard player, pass ExoDivPlayerFactory from the com.yandex.div.video.m3 package (div-video-m3 module) to the DivConfiguration builder as a .divPlayerFactory() method argument.

The DivConfiguration class for supporting video will generally look like this:

DivConfiguration.Builder(imageLoader)
    .divPlayerFactory(ExoDivPlayerFactory(context))
    .build()

If you don't connect the player in the DivConfiguration class, there will be an empty block in place of and the same size as the player when rendering the screen with the video element.

Other platforms

On iOS and Web, you don't need to connect the standard player: when a video element is created, the platform-standard video player is used.

Custom player support

Your own video player is connected differently on each platform:

  • Android: a factory that implements the DivPlayerFactory interface is passed to the .divPlayerFactory() method of the DivConfiguration builder. The details are given below.
  • iOS: a factory that implements the PlayerFactory protocol is passed to DivKitComponents in the playerFactory parameter.
  • Web: a player provider is passed to the render function in the videoPlayerProvider parameter, see Parameters of the render function.

Android

To connect your own video player to DivKit, create a factory that provides a player and a view for it at the request of the DivKit app. The factory must implement the DivPlayerFactory interface.

The video player created by the factory must implement the DivPlayer interface and thus be a proxy for calls from DivKit. When implementing a custom player, note that JSON object properties (such as player_settings_payload) may contain expressions that need to be processed using expressionResolver.

Note

When player_settings_payload changes while the app is running, DivKit will automatically call the setSource method with updated settings. Make sure your custom player correctly handles dynamic playback settings updates.

To take one example, here's how DivPlayer methods for ExoPlayer are implemented in Kotlin.

See sample code
val player: ExoPlayer by lazy {
     ExoPlayer.Builder(context).build()
     }

     override fun play() {
     player.play()
     }

     override fun pause() {
     player.pause()
     }

     override fun seek(toMs: Long) {
     player.seekTo(toMs)
     }

     override fun setSource(sourceVariants: List<DivVideoSource>, config: DivPlayerPlaybackConfig) {
     val mediaSource = sourceVariants.toMediaSource()

     player.setMediaSource(mediaSource)
     player.prepare()
     }

     override fun release() {
     player.release()
     }

Learn more

You can discuss topics of interest in the DivKit user community in Telegram: https://t.me/divkit_community_en.

DivKit Repository