首页 > 解决方案 > Android在滑动时实现文本完成

问题描述

如何实现文本完成,如 Gmail 的智能撰写?我有一个编辑文本,用户在其中输入服务器地址,我想检测他们何时开始输入域后缀并建议完成。

谢谢。

标签: android

解决方案


首先,您需要一种算法来从给定字典中获取建议。

我创建了一个简单的类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.


推荐阅读