android - Android在滑动时实现文本完成
问题描述
如何实现文本完成,如 Gmail 的智能撰写?我有一个编辑文本,用户在其中输入服务器地址,我想检测他们何时开始输入域后缀并建议完成。
谢谢。
解决方案
首先,您需要一种算法来从给定字典中获取建议。
我创建了一个简单的类SuggestionManager
,用于从给定字典中获取字符串输入的建议。它不会返回完整匹配,而是只返回给定输入的剩余部分。下面给出了一个简单的单元测试以及该类的完整源代码。您也可以到这里在线运行测试。
建议管理器.kt
class SuggestionManager(private val dictionary: Array<String>) {
companion object {
private val WORD_SPLIT_REGEX = Regex("[^A-Za-z0-9'\\-]")
/**
* To get reversed list
*/
private fun getReversedList(list: List<String>): MutableSet<String> {
val reversed = mutableSetOf<String>()
for (item in list.withIndex()) {
if (item.index != 0) {
val rev = list.subList(list.size - item.index, list.size).joinToString(" ")
reversed.add(rev)
}
}
// finally, add the full string
reversed.add(list.joinToString(" "))
return reversed
}
}
fun getSuggestionFor(_text: String?): String? {
var text = _text
// empty text
if (text.isNullOrBlank()) {
return null
}
// Getting last line only
if (text.contains("\n")) {
text = text.split("\n").last()
if (text.trim().isEmpty()) {
return null
}
}
// Splitting words by space
val words = text.split(WORD_SPLIT_REGEX).filter { it.isNotBlank() }
// Getting last word
val lastWord = if (text.endsWith(" ")) "${words.last()} " else words.last()
// Matching if last word exist in any dictionary
val suggestions = mutableSetOf<String>()
for (dicItem in dictionary) {
if (dicItem.contains(lastWord, true)) {
// Storing founded matches
suggestions.add(dicItem)
}
}
// Reverse ordering split-ed words
val pyramidWords = getReversedList(words)
val matchList = mutableListOf<String>()
for (pw in pyramidWords) {
for (sug in suggestions) {
// Storing suggestions starts with reversed word
if (sug.startsWith(pw, true)) {
matchList.add("$pw:$sug")
}
}
}
// Checking if second level match is not empty
if (matchList.isNotEmpty()) {
// Ordering by matched reversed word - (largest key first)
matchList.sortBy { -it.split(":")[0].length }
// Looping through in ascending order
for (m in matchList) {
val match = m.split(":")
val selPw: String = match[0]
var selSug: String = match.subList(1, match.size).joinToString(":")
// trimming to
selSug = selSug.replace(selPw, "", true)
if (text.endsWith(" ")) {
selSug = selSug.trim()
}
return selSug
}
}
return null
}
}
单元测试
class SuggestionManagerUrlTest {
private val suggestionManager by lazy {
val dictionary = arrayOf(
"google.com",
"facebook.com",
"gmail.com",
"yahoo.com",
"192.168.354.45"
)
SuggestionManager(dictionary)
}
@Test
fun test() {
// null of empty and null input
assertNull(suggestionManager.getSuggestionFor(null))
assertNull(suggestionManager.getSuggestionFor(""))
// matching
assertEquals("ogle.com", suggestionManager.getSuggestionFor("go"))
assertEquals("book.com", suggestionManager.getSuggestionFor("face"))
assertEquals(".168.354.45", suggestionManager.getSuggestionFor("192"))
// no match
assertNull(suggestionManager.getSuggestionFor("somesite"))
}
}
然后,您必须EditText
使用两种颜色设置文本。一个用于输入,另一个用于建议。您可以使用该Html.fromHtml
方法来执行此操作。
val text = "<font color=#cc0029>$input</font> <font color=#ffcc00>$suggestion</font>";
yourEditText.setText(Html.fromHtml(text));
结合这两个方面,您可以创建自定义EditText
.
推荐阅读
- r - 将函数应用于名称为字符串的所有变量
- java - javax.net.ssl.SSLProtocolException:连接超时(读取失败)
- python-3.x - 从字符串中提取国家
- php - PHP会话变量未存储
- azure-logic-apps - Azure Logic Apps 参数 - 如何使用它?
- python - 我的 numpy 选择语句给出了“形状不匹配”错误
- c# - 如何在uwp中传递转换器参数中的元素?
- excel - 遍历一列以查找下一个空单元格并将值复制到 Excel 中?
- postgresql - 将 2 个查询合并为 1 个查询
- matlab - Matlab中半径变化的球体的gif