Візуальний редактор діалогових дерев бота в мобільному додатку

Ми розробляємо візуальний редактор діалогових дерев для мобільних додатків. Це один із найскладніших технічно UI-компонентів: нескінченний canvas, gesture-система з кількома одночасними розпізнавачами, рендеринг тисяч елементів, undo/redo, серіалізація графа. За 5+ років на ринку ми реалізували деся

Розробка та підтримка будь-яких видів мобільних додатків:

Інформаційні та розважальні мобільні програми
Новинки, ігри, довідники, онлайн-каталоги, погодні, фітнес та здоров'я, туристичні, освітні, соціальні мережі та месенджери, квіз, блоги та подкасти, форуми, агрегатори
Мобільні програми електронної комерції
Інтернет-магазини, B2B-додатки, маркетплейси, онлайн-обмінники, кешбек-сервіси, біржі, дропшиппінг-платформи, програми лояльності, доставка їжі та товарів, платіжні системи
Мобільні програми для управління бізнес-процесами
CRM-системи, ERP-системи, управління проектами, інструменти для команди продажів, облік фінансів, управління виробництвом, логістика та доставка, управління персоналом, системи моніторингу даних
Мобільні програми електронних послуг
Дошки оголошень, онлайн-школи, онлайн-кінотеатри, платформи надання електронних послуг, платформи кешбеку, відеохостинги, тематичні портали, платформи онлайн-бронювання та запису, платформи онлайн-торгівлі

Це лише деякі з типів мобільних додатків, з якими ми працюємо, і кожен із них може мати свої специфічні особливості та функціональність, а також бути адаптованим під конкретні потреби та цілі клієнта.

Послуги, які ми пропонуємо
Показано 1 з 1Усі 1734 послуг
Візуальний редактор діалогових дерев бота в мобільному додатку
Складний
від 1 тижня до 3 місяців

Наші компетенції:

Часті запитання

Останні роботи

  • image_mobile-applications_feedme_467_0.webp
    Розробка мобільного додатка для компанії FEEDME
    897
  • image_mobile-applications_xoomer_471_0.webp
    Розробка мобільного додатку для компанії XOOMER
    784
  • image_mobile-applications_rhl_428_0.webp
    Розробка мобільного додатку для компанії RHL
    1218
  • image_mobile-applications_zippy_411_0.webp
    Розробка мобільного додатку для компанії ZIPPY
    1081
  • image_mobile-applications_affhome_429_0.webp
    Розробка мобільного додатку для компанії Affhome
    1004
  • image_mobile-applications_flavors_409_0.webp
    Розробка мобільного додатку для компанії FLAVORS
    600

Ми розробляємо візуальний редактор діалогових дерев для мобільних додатків. Це один із найскладніших технічно UI-компонентів: нескінченний canvas, gesture-система з кількома одночасними розпізнавачами, рендеринг тисяч елементів, undo/redo, серіалізація графа. За 5+ років на ринку ми реалізували десятки подібних проєктів для чат-ботів у банкінгу, e-commerce та підтримці. Наші інженери володіють як нативними стеками (Swift, Kotlin), так і крос-платформними рішеннями (Flutter, React Native). Гарантуємо коректну роботу на всіх цільових пристроях та відповідність гайдлайнам App Store і Google Play.

Як реалізувати нескінченне полотно?

Основа редактора — нескінченний масштабований простір для розміщення нод. Два принципово різних підходи — порівняємо їх у таблиці.

Критерій UIScrollView як viewport Кастомний canvas з трансформацією
Простота реалізації Висока, нативний scroll Середня, потрібна ручна обробка жестів
Масштабування тексту Проблема: шрифти масштабуються Фікс через зворотну трансформацію
Гнучкість zoom-to-fit Обмежена Повна, через матрицю
Продуктивність (100+ нод) Середня Висока (один CALayer)

На iOS UIScrollView з contentSize 5000×5000 pt — простий старт. Ноди — UIView всередині contentView. Масштабування через minimumZoomScale/maximumZoomScale. Мінус: при zoom текст стає нечитабельним. Фікс — зворотна трансформація label'ів при scrollViewDidZoom. Кастомний canvas через CATransform3D дає більше контролю: zoom-to-fit, snap-to-grid. Конфлікт жестів вирішується через UIGestureRecognizerDelegate: pan на ноді — drag, pan на порожньому місці — панорамування.

У Jetpack Compose — Modifier.graphicsLayer з pointerInput для detectTransformGestures.

Чому важливе коректне керування жестами?

Редактор одночасно використовує pan, pinch, long press та tap. Без чіткої пріоритизації дії користувача інтерпретуватимуться невірно. На iOS ми використовуємо UIGestureRecognizerDelegate з shouldRecognizeSimultaneouslyWith для pan і pinch, а hit-test на початку жесту визначає, чи перетягується нода або полотно. На Android — GestureDetector з різними слухачами. Такий підхід виключає хибні спрацювання при інтенсивній роботі.

Рендеринг ребер (стрілок)

Криві Безьє для з'єднань між нодами — візуально краще прямі лінії. Кубічна крива від output handle до input handle:

let path = UIBezierPath() path.move(to: startPoint) let controlPoint1 = CGPoint(x: startPoint.x + (endPoint.x - startPoint.x) * 0.5, y: startPoint.y) let controlPoint2 = CGPoint(x: startPoint.x + (endPoint.x - startPoint.x) * 0.5, y: endPoint.y) path.addCurve(to: endPoint, controlPoint1: controlPoint1, controlPoint2: controlPoint2) edgeLayer.path = path.cgPath 

Кожне ребро — CAShapeLayer з strokeColor та стрілковим наконечником. При переміщенні ноди — перераховуємо всі CAShapeLayer.path для вхідних та вихідних ребер. CATransaction.begin(); CATransaction.setDisableActions(true) для миттєвого оновлення. При великій кількості ребер (50+) — рендеринг через один спільний CALayer з draw-методом: один CGContext.addPath() для всіх ребер швидше ніж 50 окремих шарів.

Інтерактивне створення зв'язків

Користувач тягне від output handle однієї ноди до input handle іншої — створюється нове ребро. Реалізація:

  1. UILongPressGestureRecognizer (duration 0.0) на handle view — початок drag
  2. При .began — створюємо temporaryEdgeLayer, початок зафіксовано на handle
  3. При .changed — оновлюємо кінець temporaryEdgeLayer на позицію пальця
  4. Hit-test при кожному .changed: canvas.hitTest(location, with: nil) — якщо потрапляємо на input handle — підсвічуємо її
  5. При .ended — якщо під пальцем input handle — створюємо постійне ребро, інакше видаляємо temporaryEdgeLayer

Запобігання невалідним зв'язкам: не можна з'єднати ноду з собою, не можна створити дублюючий зв'язок, не можна створити цикл (якщо граф має бути DAG). Перевірка циклу — DFS з target ноди. O(V + E) — швидко для типових діалогових дерев.

Редагування нод

Торкання на ноді — відкривається редактор вмісту. Для діалогового вузла типу «Message»: UITextView з rich text підтримкою для тексту повідомлення, перемикач типу (текст/медіа/кнопки), список кнопок з можливістю додати/видалити.

Bottom sheet (iOS 15+ UISheetPresentationController з .medium та .large detents) — користувач бачить граф і редактор одночасно в medium режимі. Keyboard avoidance: при появі клавіатури нижній padding UIScrollView всередині sheet збільшується на keyboardFrame.height - sheet.frame.height + sheetMaxHeight. Обробляється через UIKeyboardWillShowNotification.

Undo/Redo

Command Pattern — кожна дія (переміщення ноди, створення/видалення ребра, редагування вмісту) реалізується як об'єкт команди з методами execute() та undo().

protocol GraphCommand { func execute() func undo() } struct MoveNodeCommand: GraphCommand { let node: GraphNode let fromPosition: CGPoint let toPosition: CGPoint func execute() { node.position = toPosition } func undo() { node.position = fromPosition } } 

UndoManager — вбудований в iOS UIKit, працює з registerUndo(withTarget:handler:). Або власний CommandStack з undoStack: [GraphCommand] та redoStack: [GraphCommand]. Групування команд: переміщення кількох виділених нод — одна операція undo.

Виділення та multiple selection

Ласо-виділення: pan на порожньому просторі при утриманні натиснення — малює прямокутник виділення через CAShapeLayer з fillColor = UIColor.blue.withAlphaComponent(0.1) та strokeColor = UIColor.blue. При завершенні жесту — перевіряємо всі ноди на перетин. Виділені ноди — синя обводка через layer.borderColor. Pan на виділенні переміщує всі виділені ноди одночасно. Delete — видалення всіх виділених нод і інцидентних ребер.

Серіалізація та синхронізація

Граф → JSON з повним описом нод і ребер. Автозбереження кожні 30 секунд або при кожній зміні з debounce 2 секунди. На iOS — Combine.debounce(for: .seconds(2), scheduler: RunLoop.main) на publisher змін графа, потім URLSession.shared.dataTask для відправки на сервер.

Conflict resolution при спільному редагуванні: Last-Write-Wins на рівні ноди з timestamp сервера. updatedAt: Date на кожній ноді — при merge беремо версію з пізнішим timestamp.

Що входить в роботу?

  • Дослідження та проектування структури вузлів під ваш чат-бот
  • Реалізація кастомного canvas з нескінченним полотном та масштабуванням
  • Система undo/redo та multiple selection
  • Інтеграція з вашим бекендом через REST/GraphQL
  • Підтримка всіх типів вузлів (текст, медіа, кнопки, умови)
  • Тестування на цільових пристроях та публікація в сторах
  • Документація та навчання вашої команди

Термін: від 1 тижня до 3 місяців. Вартість розраховується індивідуально після аналізу вимог. Зв'яжіться з нами — оцінимо ваш проєкт і запропонуємо оптимальне рішення.