Решение типичных проблем
Поддержка светлой и темной темы
Есть несколько подходов при работе с различными темами.
-
Цветовая палитра приложения задается с клиента.
Создайте свое хранилище переменных
DivVariableStorage
и передайте его вDivKitComponents
.let applicationStorage = DivVariableStorage() let themeVariable: DivVariables = [ DivVariableName(rawValue: "palette"): .dict([ "text_color": "#ffffff", "text_background": "#0077FF" ]) ] applicationStorage.put(themeVariable) let variablesStorage = DivVariablesStorage(outerStorage: applicationStorage) let divkitComponents = DivKitComponents(variablesStorage: variablesStorage)
Тогда сама верстка будет выглядеть так:
{ "card": { "log_id": "text", "states": [ { "state_id": 0, "div": { "type": "text", "text": "Hello, DivKit!", "height": { "type": "fixed", "value": 48 }, "border": { "corner_radius": 16 }, "background": [ { "type": "solid", "color": "@{getColorFromDict(palette, 'text_background')}" } ], "margins": { "top": 20, "left": 20, "right": 20 }, "font_size": 14, "text_alignment_vertical": "center", "text_alignment_horizontal": "center", "text_color": "@{getColorFromDict(palette, 'text_color')}" } } ] } }
Здесь стоит обратить внимание, что верстка из JSON ничего не знает о существовании переменной
palette
, и с клиента нужно прокинуть эту переменную.
Чтобы избежать ошибок, добавьте значение по умолчанию через функциюgetOptColorFromDict
. -
Сервер сам хочет управлять цветовой палитрой.
В этом случае нужно знать, какая тема используется в приложении. Для этого можно завести глобальную переменную
app_theme
:let applicationStorage = DivVariableStorage() let themeVariable: DivVariables = [ DivVariableName(rawValue: "app_theme"): .string("dark") ] applicationStorage.put(themeVariable) let variablesStorage = DivVariablesStorage(outerStorage: applicationStorage) let divkitComponents = DivKitComponents(variablesStorage: variablesStorage)
Сама верстка будет выглядеть так:
{ "card": { "variables": [ { "name": "palette", "type": "dict", "value": { "light": { "text_color": "#ffffff", "text_background": "#0077FF" }, "dark": { "text_color": "#000000", "text_background": "#0077FF" } } } ], "log_id": "text", "states": [ { "state_id": 0, "div": { "type": "text", "text": "Hello, DivKit!", "height": { "type": "fixed", "value": 48 }, "border": { "corner_radius": 16 }, "background": [ { "type": "solid", "color": "@{getColorFromDict(palette, app_theme, 'text_background')}" } ], "margins": { "top": 20, "left": 20, "right": 20 }, "font_size": 14, "text_alignment_vertical": "center", "text_alignment_horizontal": "center", "text_color": "@{getColorFromDict(palette, app_theme, 'text_color')}" } } ] } }
Работа с ошибками в DivKit
Для упрощения отладки верстки на клиенте в DivKit есть индикатор с ошибками в верстке. По умолчанию он выключен. Чтобы его включить, нужно дополнительно передать DebugParams
:
divView.setSource(DivViewSource(kind: .data(jsonData),
cardId: "ExampleCard"),
debugParams: DebugParams(isDebugInfoEnabled: true))
Для примера передадим в corner_radius
невалидное значение:
"border": {
"corner_radius": "incorrect_value"
},
В этом случае на верстке появится индикатор ошибки:
При нажатии на индикатор можно посмотреть ошибки в панели отладки.
Чтобы логировать ошибки, нужно передать в DivKitComponents
параметр reporter
.
Не работают visibility_actions
Рассмотрим верстку, в которой через 1 секунду вызывается visibility_action
и меняется текст кнопки.
{
"card": {
"variables": [
{
"name": "button_text",
"type": "string",
"value": "Waiting visibility action"
}
],
"log_id": "text",
"states": [
{
"state_id": 0,
"div": {
"type": "text",
"text": "@{button_text}",
"height": {
"type": "fixed",
"value": 48
},
"border": {
"corner_radius": 16
},
"background": [
{
"type": "solid",
"color": "#0077FF"
}
],
"margins": {
"top": 20,
"left": 20,
"right": 20
},
"font_size": 14,
"text_alignment_vertical": "center",
"text_alignment_horizontal": "center",
"visibility_actions": [
{
"log_id": "example",
"visibility_duration": 1000,
"url": "div-action://set_variable?name=button_text&value=Visibility%20action%20called!"
}
]
}
}
]
}
}
Если ничего не делать со стороны клиента, этот action
вызван не будет. DivView
не знает, насколько она видна на экране. Когда DivView
станет видна на экране, нужно вызвать метод onVisibleBoundsChanged
:
divView.onVisibleBoundsChanged(to: visibleSize)
Умеет ли DivKit работать с right-to-left интерфейсом?
Да, достаточно передать параметр layoutDirection
в DivKitComponents
, тогда RTL-элементы будут отображаться корректно.
let divkitComponents = DivKitComponents(layoutDirection: .rightToLeft)
Можно ли использовать локальные картинки при работе с DivView?
DivKit по умолчанию умеет загружать картинки из папки divkit
в main bundle приложения с помощью ссылки вида divkit-asset://image.png
.
Также можно написать свою логику по подстановке картинок. Для этого нужно создать свою ImageHolderFactory
, которая может превращать URL в путь до картинки в файловой системе.
let imageHolderFactory = ImageHolderFactory(localImageProvider: self, requestPerformer: URLRequestPerformer(urlTransform: nil))
let divkitComponents = DivKitComponents(imageHolderFactory: imageHolderFactory)
extension ViewController: LocalImageProviding {
func localImage(for url: URL) -> BasePublic.ImageHolder? {
guard url.scheme == "localImage" else { return nil }
return UIImage(named: url.host()!)
}
}
Сам JSON будет выглядеть так:
{
"card": {
"log_id": "image",
"states": [
{
"state_id": 0,
"div": {
"type": "container",
"items": [
{
"type": "image",
"image_url": "localImage://image",
"height": {
"type": "match_parent"
}
}
],
"width": {
"type": "match_parent"
},
"height": {
"type": "fixed",
"value": 100
},
"margins": {
"top": 8,
"bottom": 8,
"left": 8,
"right": 8
}
}
}
]
}
}
Узнать больше
Следите за новостями DivKit в Telegram-канале: http://t.me/divkit_news.
Также вы можете обсуждать интересующие вас темы в сообществе пользователей DivKit в Telegram: https://t.me/divkit_community_ru.