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
- Add font files (.ttf or .otf) to your project
- Make sure the fonts are included in the application resources (Bundle Resources)
- Add font information to Info.plist in the
Fonts provided by applicationsection:
<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:
- Connect fonts using standard CSS methods (via
@font-faceor external services) - Use the
typefaceProviderparameter 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
- Performance Optimization: Cache font instances to avoid reloading.
- Support for Different Weights: Implement support for different font weights to ensure design flexibility.
- Fallback Options: Always provide fallback font options in case the custom font fails to load.
- Font Preloading: For the web platform, it is recommended to preload fonts to avoid text flickering when the page loads.
- 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
CoilDivImageLoaderandGlideDivImageLoaderloaders
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
DivPlayerFactoryinterface is passed to the.divPlayerFactory()method of theDivConfigurationbuilder. The details are given below. - iOS: a factory that implements the
PlayerFactoryprotocol is passed toDivKitComponentsin theplayerFactoryparameter. - Web: a player provider is passed to the
renderfunction in thevideoPlayerProviderparameter, 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.