Решение типичных проблем

Поддержка светлой и темной темы

Есть несколько подходов при работе с различными темами.

  1. Цветовая палитра приложения задается с клиента.

    Создайте свое хранилище переменных 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.

  2. Сервер сам хочет управлять цветовой палитрой.

    В этом случае нужно знать, какая тема используется в приложении. Для этого можно завести глобальную переменную 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.

Репозиторий DivKit

Предыдущая
Следующая