在Instagram等社交媒体应用中,经常看到用户通过@符号来标记其他用户,这是一个非常实用的功能。本文将介绍如何在Android应用中实现类似的功能,包括用户输入时的筛选和点击标签跳转到用户资料页面的实现方法。
在本文中,不会深入讨论后端Web服务的细节,而是专注于Android端的实现。目标是在用户输入@符号时调用用户列表,然后根据用户输入的字符继续筛选用户列表。此外,希望在用户点击标签时能够链接到标记的用户名,并显示用户的个人资料页面。
首先,需要一个EditText控件供用户输入文本。更喜欢使用RelativeLayout。在EditText控件下方,有一个ListView控件,其可见性设置为"gone",宽度和高度设置为"match_parent"。这是关键,因为当找到一个用户标签时,ListView将变为可见,并填满屏幕,允许用户选择要标记的用户。
<EditText
android:id="@+id/myEditText"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="textMultiLine"
android:minLines="5"
android:maxLines="5" />
<ListView
android:id="@+id/myUsers"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:divider="#E6E6E6"
android:dividerHeight="2dip"
android:paddingLeft="20dip"
android:paddingRight="20dip"
android:visibility="gone"
android:background="#ffffff" />
接下来,为EditText控件添加TextWatcher。在TextWatcher类中,当用户在EditText控件中输入时,afterTextChanged方法将被触发,并向Editable参数传递来自EditText控件的值。使用正则表达式来查找跟随@字符的小写和大写字母数字字符串,包括-和.字符。不允许空格或其他特殊字符。重要的是仅在从光标当前位置开始的匹配上执行。这将允许在EditText控件中输入多个标签。一旦找到了当前的标签,那就是想要获取的子字符串,不包括@,并将其作为参数传递给后端服务,后端服务将返回用户列表。这也是想要将ListView的可见性设置为VISIBLE的地方。在RelativeLayout中,将ListView放置在底部,并将match_parent作为宽度和高度值,将使其覆盖布局中的所有其他控件。
this.mEditText.addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
}
@Override
public void afterTextChanged(Editable editable) {
String text = editable.toString();
Pattern p = Pattern.compile("[@][a-zA-Z0-9-.]+");
Matcher m = p.matcher(text);
int cursorPosition = mEditText.getSelectionStart();
while (m.find()) {
if (cursorPosition >= m.start() && cursorPosition <= m.end()) {
final int s = m.start() + 1;
final int e = m.end();
// add 1 to ommit the "@" tag
loadUsersFromBackEnd(text.substring(s, e));
break;
}
}
}
});
当查看其他用户的帖子或评论时,希望找到标签并使其在TextView中可点击。再次使用Pattern和Matcher类来找到标签。ClickableSpan类用于使文本的子串可点击。当找到用户标签的模式匹配时,创建ClickableSpan类的实例,覆盖onClick方法。在这个例子中,创建了一个Intent,将用户的友好名称(不包括@字符)传递给用户资料活动。同样,不会覆盖Intent和在活动之间传递值。这段代码片段很可能会在一个Adapter类中,该类将数据记录绑定到ListView。当用户滚动ListView内容时,用户标签将像超链接一样出现。点击它们将执行ClickableSpan的onClick方法。
Pattern p = Pattern.compile("[@][a-zA-Z0-9-.]+");
Matcher m = p.matcher(ss);
while (m.find()) {
final int s = m.start() + 1; // add 1 to omit the "@" tag
final int e = m.end();
ClickableSpan clickableSpan = new ClickableSpan() {
@Override
public void onClick(View textView) {
Intent intent = new Intent(mContext, com.myawesomeapp.UserActivity.class);
intent.putExtra(UserActivity.EXTRA_FRIENDLY_NAME, wallPost.getMessage().substring(s, e));
mContext.startActivity(intent);
}
};
ss.setSpan(clickableSpan, m.start(), m.end(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
}