Андроид-приложение, 55-я неделя
Использование класса «Нав хост» (NavHost)
Я вначале думал, что мне нужно использовать класс «Нав граф» (NavGraph), — оказалось, «Студия» давала подсказку не на тот вариант функции, из-за того что я не указал лямбду; указать её я должен был последним аргументом вызова.
Какие принципы отстаивает фреймворк «Джетпак Компоус»
В относительно старых видеороликах я нашёл наглядные объяснения основных принципов фреймворка:
- слабое зацепление и сильная связность кода;
- принцип «одного источника истины»;
- использование языка программирования котлин не только для проработки логики работы приложения, но и для проработки образа и поведения графического интерфейса, и как следствие — возможность воплощения сложных статичных эффектов (градиент, необычная форма макетирующих компонентов и тому подобное), а также возможность воплощения сложной анимации.
Вот ссылки на те ролики:
- «Думать понятиями „Компоуса“»;
- «„Компоус“ на примерах».
Составление предложения «на лету». Кеш предложения
Главный экран моего приложения — это экран ленты. В ленте, в числе прочего, будет список относительно длинных предложений, каждое из которых можно упростить, убрав часть слов.
Я не храню по нескольку вариантов одного и того же предложения: разные варианты будут создаваться, что называется, «на лету». Хранение полной версии предложения у меня сейчас выглядит так (образец):
Statement("2024-04-10-e1", listOf( Lexeme(3, LexemeType.F, ""), Lexeme(3, LexemeType.F, "князь"), Lexeme(3, LexemeType.L, "Болконский"), Lexeme(3, LexemeType.L, "был"), Lexeme(2, LexemeType.F, ","), Lexeme(2, LexemeType.L, "небольшого"), Lexeme(2, LexemeType.L, "роста"), Lexeme(2, LexemeType.F, ","), Lexeme(3, LexemeType.L, "весьма"), Lexeme(3, LexemeType.L, "красивый"), Lexeme(3, LexemeType.L, "молодой"), Lexeme(3, LexemeType.L, "человек"), Lexeme(1, LexemeType.F, ","), Lexeme(1, LexemeType.PL, "с"), Lexeme(1, LexemeType.PR, "определёнными"), Lexeme(1, LexemeType.PL, "и"), Lexeme(1, LexemeType.PR, "сухими"), Lexeme(1, LexemeType.L, "чертами"), Lexeme(3, LexemeType.F, "."), Lexeme(3, LexemeType.F, ""), ))
Первый параметр конструктора класса «Лексема» — это «важность», «ранг» (rank) лексемы. Обратите внимание: первый и последний элемент всегда хранят максимально возможное значение этой величины (максимально возможное в рамках данного предложения).
А вот как я создаю строку для отображения, в зависимости от «степени сжатия» (знаки «больше» и «меньше» заменены похожими по внешнему виду фигурными скобками, потому что редактор ХТМЛ-кода, которым я пользуюсь, «ругается» на них):
internal fun refine(statement: Statement, compressionLevel: Int) : String { val baseRank = statement.text[0].rank val minRank = ( if (compressionLevel {= 0 || compressionLevel }= baseRank) baseRank else compressionLevel ) val rawText = statement.text.fold("") { sum, lx -> sum + ( if (lx.rank { minRank) "" else ( if (lx.type == LexemeType.F) lx.text else ( if (lx.type == LexemeType.PR) "\u00A0" + lx.text // non-break space else " " + lx.text // regular space ) ) ) } return rawText.substring(0, 1).uppercase() + rawText.substring(1) }
Я предполагаю, что созданная однажды строка будет кешироваться, благодаря использованию функции «реме́мбер» (remember), так что моя функция «рефа́йн» (refine) не должна вызываться при повторном отображении примера во время прокрутки ленты:
package com.example.myapp.ui ... import androidx.compose.foundation.layout.Column import androidx.compose.material3.Card import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.remember ... @Composable internal fun StatementCard( statement: Statement, ... compressionLevel: Int = 1, ) { Card(...) { Column { val refinedText = remember(statement, compressionLevel) { refine(statement = statement, compressionLevel = compressionLevel) } Text( text = refinedText, ... ) } } }
Заметьте: функция «рефайн» была определена как обычная функция, а не как компоусэбэл!
Мои догадки про функции — не-компоусэблы; как и раньше, эти пункты ещё надо будет проверить и уточнить:
- Возвращаемый такими функциями результат может быть кеширован.
- Если результат вызова таких функций может быть кеширован, то эти функции не будут вызваны при рекомпозиции.
- Таким функциям не передаётся параметр «Модификатор».
«Пустая строка»
Нужно будет решить, где лучше хранить текст примеров: в прото-датасторе или в руме. Ну а пока я разрабатываю подходящий подо всё формат данных.
Так называемая «пустая строка» — чем бы она ни была на самом деле — нужна мне для обозначения границ предложения. Границы предложения должны иметь максимальный ранг; это значение используется алгоритмом (смотри выше).
Внешний отступ и внутренний отступ
Можно перевести и так: марджин — внешний отступ, паддинг — внутренний.
Выше в посте был ролик, в котором можно проследить различие между ними.
Актуализация постов
Многие посты этого сайта доступны для нахождения через поисковые системы; однако часть материала, который я публиковал ранее, устарела. Например, компоусэбэл «Леса́» перестал быть «экспериментальной особенностью», так что описание того, как им пользоваться, должно быть переделано. Я собираюсь исправлять подобные места по мере сил и возможностей...