安卓:类似于Facebook应用的自动完成TextView

31
我在我的应用程序中有一个AutoCompleteTextView。该应用程序使用Facebook SDK。我按照这个Stack Overflow问题https://dev59.com/3mjWa4cB1Zd3GeqPpUwC#12363961 中的代码完全一致,并拥有一个可以搜索(过滤)的活动。
现在,当用户键入“@”符号并仍然保留用户输入的其他文本时,如何获得类似Facebook应用程序的内联自动完成列表?所讨论的活动是“状态更新”,其中可能包含用户的朋友和其他文本。自动完成TextView或EditText自然会是多行的。对于状态更新而言,您可以看到。
我知道因为这篇文章中没有任何代码,我冒着被downvote甚至关闭问题的风险。但这确实是标准的过滤器代码。
编辑:Android上的FriendCaster应用程序也是这样做的。

这个链接可能会帮助你了解如何创建自定义的Android自动完成功能? - Omarj
这个问题没有现成的解决方案,一种方法是你可以反编译Facebook应用程序并查看代码。有很多反编译器可用。但它们基本上所做的是扩展EditText视图并根据需要进行自定义。我认为Twitter也是这样做的。 - Nitin
@Nitin:我不太确定我是否想要反编译别人的作品。此外,即使我这样做了,最多也只能得到他们的XML文件。而我认为必须得到他们的JAVA文件才行。 - Siddharth Lele
@SkiddharD 无论价值多少,你会获得明文的JAVA代码,我知道,因为我做过。 - Nitin
2个回答

35

首先将您的EditText转换为MultiAutoCompleteTextView。MultiAutoCompleteTextView允许您替换文本中的某些部分,例如“@”后面的文本。

然后您可以像这样操作:

final MultiAutoCompleteTextView inputEditText = (MultiAutoCompleteTextView) dialog.findViewById(R.id.MyEditText);

String[] COUNTRIES = new String[] { "Belgium", "France", "Italy", "Germany", "Spain" };
ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, android.R.layout.simple_dropdown_item_1line, COUNTRIES);
inputEditText.setAdapter(adapter);
inputEditText.setThreshold(1); //Set number of characters before the dropdown should be shown

//Create a new Tokenizer which will get text after '@' and terminate on ' '
inputEditText.setTokenizer(new Tokenizer() {

  @Override
  public CharSequence terminateToken(CharSequence text) {
    int i = text.length();

    while (i > 0 && text.charAt(i - 1) == ' ') {
      i--;
    }

    if (i > 0 && text.charAt(i - 1) == ' ') {
      return text;
    } else {
      if (text instanceof Spanned) {
        SpannableString sp = new SpannableString(text + " ");
        TextUtils.copySpansFrom((Spanned) text, 0, text.length(), Object.class, sp, 0);
        return sp;
      } else {
        return text + " ";
      }
    }
  }

  @Override
  public int findTokenStart(CharSequence text, int cursor) {
    int i = cursor;

    while (i > 0 && text.charAt(i - 1) != '@') {
      i--;
    }

    //Check if token really started with @, else we don't have a valid token
    if (i < 1 || text.charAt(i - 1) != '@') {
      return cursor;
    }

    return i;
  }

  @Override
  public int findTokenEnd(CharSequence text, int cursor) {
    int i = cursor;
    int len = text.length();

    while (i < len) {
      if (text.charAt(i) == ' ') {
        return i;
      } else {
        i++;
      }
    }

    return len;
  }
});

这种方式的一个“问题”是弹出窗口将出现在EditText视图下方。为了将其移动并放置在当前编写文本下方,您可以执行以下操作:

inputEditText.addTextChangedListener(new TextWatcher() {

  @Override
  public void onTextChanged(CharSequence s, int start, int before, int count) {
    Layout layout = inputEditText.getLayout();
    int pos = inputEditText.getSelectionStart();
    int line = layout.getLineForOffset(pos);
    int baseline = layout.getLineBaseline(line);

    int bottom = inputEditText.getHeight();

    inputEditText.setDropDownVerticalOffset(baseline - bottom);

  }

  @Override
  public void beforeTextChanged(CharSequence s, int start, int count, int after) {
  }

  @Override
  public void afterTextChanged(Editable s) {
  }
});

注意:目前还没有处理下拉菜单位置的问题,如果编辑文本中有超过编辑文本可以显示的行数,则需要注意。

1
正是我所需要的!运行得非常好。 :-) - Siddharth Lele
问吧,虽然不能保证我能回答 :) - Heinrisch
1
你需要让它实现Filterable接口。然后重写getFilter()方法,你可以参考https://android.googlesource.com/platform/frameworks/base/+/refs/heads/master/core/java/android/widget/ArrayAdapter.java中的示例。然后在ArrayFilter中,你可能还想重写convertResultToString(Object resultValue)方法。 - Heinrisch
MultiAutoCompleteTextView与自定义适配器不兼容。你能帮我吗? - user1767260
如何使用它来显示来自Web的结果,而不是静态数组? - MAY3AM
显示剩余5条评论

0

https://github.com/dhaval001/linkable_text_view.git

使用多自动完成文本视图在Android TextView和EditText中创建链接文本的简单方法,例如@username或#hashtag。 链接Facebook和Instagram

特点

匹配单个字符串或正则表达式模式以设置链接 更改链接文本的颜色 设置链接文本的样式:BOLD,ITALIC或BOLD_ITALIC 设置链接文本的下划线 指定特定单词的点击操作 LinkableEditText的OnTextChangedListener监听器


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接