Весела математика у інтерфейсах
Під час розробки свого iOS додатку To The Shop (реліз якого вже відбувся), дуже зручного списку покупок, у мене виникло натхнення поділитися своїм вирішенням цікавої задачі, яка трапилась під час роботи. Тим паче що цей елемент зустрічається доволі часто. Але я сподіваюсь, що цей метод може бути корисним комусь навіть для задач іншого плану або надихне на вдосконалення, тому я вирішив поділитися саме детальним роз’ясненням того, як метод працює.
В процесі написання свого застосунку для iOS, виникла необхідність написати свій Page Control у вигляді кружечків, що відображають поточну позицію в списку карток.
Для початку я поясню суть задачі. Найпростіший варіант Page Control виглядає як на першій анімації нижче:
Суть проблеми у тому, що ми маємо обмеження по ширині, та на якомусь етапі кількість елементів досягає такого рівня, що загальна ширина page control вилізе за означені межі. Оскільки я не знайшов готового вирішення проблеми, яке б мені подобалось, я намалював декілька варіантів, і обрав ті, які б на мою думку були прийнятними. Відкинувши всі варіанти з пропуском елементів на кшталт трьох крапок всередині, або перетворення у слайдер, щоб користувач чітко і швидко усвідомлював, на якій позиції знаходиться, виділив наступні:
- Робити всі елементи меншими, щоб задовольняти обмеження за шириною (але поточний елемент не буде гарно видно при малих розмірах).
- Залишати один елемент первісного розміру, і однаково зменшувати всі інші.
- Зробити плавний перехід з первісного розміру елементу до меншого через зазначену кількість кроків.
Я обрав варіант #3, тому що він дає найцікавіший і найпривабливіший вигляд, та водночас ми чітко бачимо поточну сторінку, тобто найбільший виділений елемент. До того ж, задля досягнення гармонійного переходу, було вирішено зробити перехід через функцію косинусу.
Результат наочно показано у наступній анімації.
1. Рахуємо кроки
Приймемо базовий розмір елементу за та позначимо його на графіку. Кінцева ціль розрахунків це знаходження розміру найменшого елементу. Всі елементи за межами однієї хвилі косинусу матимуть такий самий розмір як найменший елемент на кінці хвилі.
Головна умова та суть задачі це зберігання постійної однакової ширини усього Page Control, тобто сума всіх елементів має бути постійною.
Для меншої кількості елементів можна вручну ввести обмеження на розмір елементу, що й було застосовано на анімації вище. Без обмеження бокові елементи ставатимуть навпаки більшими за умови нестачі елементів. Також, за умови дуже малої ширини, розміри можуть приймати від‘ємні значення. В межах цієї статті я не вводитиму ці обмеження щоб не ускладнювати статтю.
Для початку побудуємо бажаний графік:
Підбираємо функцію, яка даватиме нам відповідний графік. Приведена нижче функція дає результат в діапазоні від до , що буде в нагоді для обчислення відносного коефіцієнту для обчислення базової величини зменшення , через який обчислимо розмір найменшого елементу.
, де — це кут у радіанах.
Запам’ятаємо цю формулу, вона знадобиться нижче для розрахунків. Графік:
Наступним кроком вводимо величини, необхідні для обчислення розмірів кожного елементу.
— загальна ширина Page Control (сума всіх елементів)
— базовий розмір одного елементу
— загальна кількість елементів у рядку Page Control
— шуканий розмір найменшого елементу
— обратно пропорційний коефіцієнт зменшення розміру , від до . Наприклад, при ,
— прямо пропорційний коефіцієнт зменшення коефіцієнту
Припустимо, що базовий розмір це . Оскільки менший розмір буде зменшено на , то найменший елемент розраховуємо за формулою . Для розрахунку проміжних розмірів недостатньо використовувати , тому вводимо додатковий коефіцієнт , який дозволить брати частину в діапазоні від до . Тож тепер будь-який розмір можна розрахувати за формулою . За даною формулою для кожного елементу змінюватиметься тільки , тому сума всіх елементів розраховуватиметься так:
де — це кількість елементів (див. останній індекс). Тож для знаходження загальної ширини можемо вивести наступну остаточну формулу:
де це середнє арифметичне всіх від до .
Оскільки наша мета це знаходження розміру елементу, нам потрібно вивести з цієї формули, що ми і зробимо. Для простоти розрахунку та запобігання помилок я використав сервіс WolframAlpha (нехай пробачить мене шкільна вчителька з математики Тетяна Володимирівна).
2. Малюємо хвилі
Все що нам залишається це розрахувати всі для кожного елементу та знайти для них середнє арифметичне. Пам’ятаєте нашу функцію з косинусом?
Змістимо кут на радіан вліво, щоб інвертувати відносно графіку з розміром елементів, та отримаємо формулу:
, де це кут у радіанах (або відстань від центрального елементу).
Побудуємо графік із зазначенням необхідних величин:
Ви помітили? Звичайно! Це ж інвертований графік з попереднього малюнку у діапазоні ще невідомого :)
Згадаємо правило, розроблене вище, яке визначає вигляд нашого Page Control. Значення для останнього елементу переходу завжди припадає на радіан. Тож для всіх елементів за межами однієї хвилі визначаємо , що даватиме пряму на графіку та однаковий розмір для всіх наступних елементів.
На графіках у прикладі напівхвиля розбита на 4 секції (далі у прикладі в коді це визначатиметься як 5 елементів у напівхвилі, найбільший та найменший включно). Тож для найбільшого елементу розрахунок прийме вигляд:
, а отже
, тобто повний розмір.
А для останнього елементу хвилі розрахунок буде таким:
, а отже
, тобто базовий розмір зменшений на повний , вийшов найменший елемент.
Що далі? Далі ми розраховуємо для кожного елементу, та підставляємо у формулу, виведену у попередньому параграфі.
3. Будуємо результат
Теорія це звісно цікаво, але набагато цікавіше створити щось де вона буде корисна. Тому просто підсумуємо всі підрахунки за допомогою коду. Я використав мову Swift, але я впевнений, що вам не складе труднощів переписати це мовою, якою користуєтесь саме ви, синтаксис простий для розуміння.
Все спрацювало, розрахунки правильні. Перевірка наприкінці тестового коду дала бажану ширину 160 пунктів.
Продублюю варіант побудови реального елементу інтерфейсу, заснованого на вищезазначених розрахунках. Виглядає значно краще анімованим ;)
Тож, що можна винести з цієї статті? Я, власне, зміцнився у переконанні, що набагато веселіше проявляти креативність і вигадувати нестандартні рішення хоча б час від часу. Це не дозволяє засумувати і дає привід отримати задоволення від результату своєї роботи. Та й хто з нас не хоче відчути трішечки естетичної насолоди...
А як вважаєте ви? Додавайте свої цікаві рішення у коментарях.
18 коментарів
Додати коментар Підписатись на коментаріВідписатись від коментарів