Android EditText 中的标签或气泡

54

在此输入图片描述请问有谁可以指点我如何在EditText中实现这些气泡或标签,就像在Google+的Stream中通过添加一个圆圈或联系人来撰写内容时看到的那样?这个矩形是一个自动完成的EditText。


4
亲爱的,请在谈论其他应用程序并举例时,尽可能提供截图,以便我们能够准确理解。希望你能明白我的意思。一张截图胜过一万个字 :) - Paresh Mayani
他们过去限制图片。> <不知道为什么会上传两张照片。 - Maurice
+1 无论如何,好问题。 - Paresh Mayani
“Your circles”和“Extended circles”是不同的EditText吗? - Paresh Mayani
只有一个带有两个气泡的EditText。 - Maurice
我正在这里做类似的事情 https://dev59.com/R2gv5IYBdhLWcg3wJNhF - Etienne Lawlor
8个回答

18

@David:当你创建新的短信时,请检查短信应用程序。你将能够在多个选项之间进行选择。该短信代码是开源的。 - Macarse
这是一个相当不错的链接,让我了解了MultiAutoCompleteTextView,从而了解了自动完成部分的工作原理。代码描述它由“,”或“;”分隔,但上面显示没有分隔符和图像。很酷的一点是,当你在“气泡”上按退格键时,它会删除整个单词!这段文本中是否有背景图像,还是我漏看了什么? - Maurice
@Maurice:我猜那是一个带有灰色android:backgroundandroid:leftDrawableTextView - Macarse
据我所知,你需要使用“Spannable”系统(我在另一个答案中描述)来将可绘制对象插入到作为文本流的“TextView”/“EditText”中。 - Steve Pomeroy
适用于4+设备,但不适用于2.3...(未在任何3上测试) - madlymad
如果有人感兴趣,我已经在GitHub上发布了类似的解决方案:https://github.com/AndroidDeveloperLB/ChipsLibrary。 - android developer

8
我建立了 GitHub上的TokenAutoComplete来解决类似的问题,它也适用于您。这是一个演示应用程序的基本实现:
public class ContactsCompletionView extends TokenCompleteTextView {
    public ContactsCompletionView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    @Override
    protected View getViewForObject(Object object) {
        Person p = (Person)object;

        LayoutInflater l = (LayoutInflater)getContext().getSystemService(Activity.LAYOUT_INFLATER_SERVICE);
        LinearLayout view = (LinearLayout)l.inflate(R.layout.contact_token, (ViewGroup)ContactsCompletionView.this.getParent(), false);
        ((TextView)view.findViewById(R.id.name)).setText(p.getEmail());

        return view;
    }

    @Override
    protected Object defaultObject(String completionText) {
        //Stupid simple example of guessing if we have an email or not
        int index = completionText.indexOf('@');
        if (index == -1) {
            return new Person(completionText, completionText.replace(" ", "") + "@example.com");
        } else {
            return new Person(completionText.substring(0, index), completionText);
        }
    }
}

联系人令牌的布局代码(您可以在此处使用任何类型的布局,或者如果您想要令牌中的图像,则可以放置一个ImageView)

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_height="wrap_content"
    android:layout_width="wrap_content">

    <TextView android:id="@+id/name"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:background="@drawable/token_background"
        android:padding="5dp"
        android:textColor="@android:color/white"
        android:textSize="18sp" />

</LinearLayout>

令牌背景可绘制
<shape xmlns:android="http://schemas.android.com/apk/res/android" >
    <solid android:color="#ffafafaf" />
    <corners
        android:topLeftRadius="5dp"
        android:bottomLeftRadius="5dp"
        android:topRightRadius="5dp"
        android:bottomRightRadius="5dp" />
</shape>

人物对象代码

public class Person implements Serializable {
    private String name;
    private String email;

    public Person(String n, String e) { name = n; email = e; }

    public String getName() { return name; }
    public String getEmail() { return email; }

    @Override
    public String toString() { return name; }
}

示例活动

public class TokenActivity extends Activity {
    ContactsCompletionView completionView;
    Person[] people;
    ArrayAdapter<Person> adapter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        people = new Person[]{
                new Person("Marshall Weir", "marshall@example.com"),
                new Person("Margaret Smith", "margaret@example.com"),
                new Person("Max Jordan", "max@example.com"),
                new Person("Meg Peterson", "meg@example.com"),
                new Person("Amanda Johnson", "amanda@example.com"),
                new Person("Terry Anderson", "terry@example.com")
        };

        adapter = new ArrayAdapter<Person>(this, android.R.layout.simple_list_item_1, people);

        completionView = (ContactsCompletionView)findViewById(R.id.searchView);
        completionView.setAdapter(adapter);
    }
}

布局代码

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <com.tokenautocomplete.ContactsCompletionView
        android:id="@+id/searchView"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />

</RelativeLayout>

1
嘿,我遇到了这个错误:java.lang.ClassNotFoundException: 没有找到类“com.tokenautocomplete.TokenActivity”。 - user1051505
@user1051505,请检查您的主XML文件。 - appukrb

4
您可以通过创建一个android.text.style.DynamicDrawableSpan子类来实现此操作。 ImageSpan就是一个这样的例子:它使用图片替换了文本范围内的样式。
以下示例将在编辑框中插入一颗星星,替换文本“test”。请在布局中创建一个id为“text”的EditText,并将以下代码放置在onCreate()中(或其他位置):
    EditText mText = (EditText) findViewById(R.id.text);
    final Editable e = mText.getEditableText();
    final SpannableStringBuilder sb = new SpannableStringBuilder();
    sb.append("test");
    sb.setSpan(new ImageSpan(this, android.R.drawable.btn_star), 0, 4, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
    e.append(sb);

我没有看到任何可以将普通文本包装成可绘制对象的类,但是通过覆盖getDrawable()方法并自己渲染文本,这个问题可以很容易地解决。


这很有趣。您可以将图像放入EditText中,但必须按退格键4次才能删除整个图像。 - Maurice
回退几次实际上取决于Spannable.SPAN_INCLUSIVE_EXCLUSIVE部分的跨度。尝试玩弄几个不同的设置-总共有4个。 - Steve Pomeroy
就文本中的“你的圈子”而言,您可能是正确的。您还可以使用Macarse答案中指向的Annotation类将额外信息添加到文本的流程中。我猜最终答案将同时使用这两个类。 - Steve Pomeroy
啊,那么可能是 span 的位置出了问题。我对我的答案中的示例代码进行了一些修改,所以你可能有一个早期版本。确保 span 的范围从 0 到 4。我马上会发布一组完整的可工作代码。 - Steve Pomeroy
这是类:http://staticfree.info/clip/2011-11-19T235307 和布局 http://staticfree.info/clip/2011-11-19T235336 - Steve Pomeroy
显示剩余7条评论

4

我在这里解决了这个问题 联系人气泡编辑框

final SpannableStringBuilder sb = new SpannableStringBuilder();
TextView tv = createContactTextView(contactName);
BitmapDrawable bd = (BitmapDrawable) convertViewToDrawable(tv);
bd.setBounds(0, 0, bd.getIntrinsicWidth(),bd.getIntrinsicHeight());

sb.append(contactName + ",");
sb.setSpan(new ImageSpan(bd), sb.length()-(contactName.length()+1),sb.length()-1,Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
to_input.setText(sb);

public static Object convertViewToDrawable(View view) {
  int spec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
  view.measure(spec, spec);
  view.layout(0, 0, view.getMeasuredWidth(), view.getMeasuredHeight());
  Bitmap b = Bitmap.createBitmap(view.getMeasuredWidth(), view.getMeasuredHeight(),
        Bitmap.Config.ARGB_8888);
  Canvas c = new Canvas(b);
  c.translate(-view.getScrollX(), -view.getScrollY());
  view.draw(c);
  view.setDrawingCacheEnabled(true);
  Bitmap cacheBmp = view.getDrawingCache();
  Bitmap viewBmp = cacheBmp.copy(Bitmap.Config.ARGB_8888, true);
  view.destroyDrawingCache();
  return new BitmapDrawable(viewBmp);

}

public TextView createContactTextView(String text){
  //creating textview dynamically
  TextView tv = new TextView(this);
  tv.setText(text);
  tv.setTextSize(20);
  tv.setBackgroundResource(R.drawable.oval);
  tv.setCompoundDrawablesWithIntrinsicBounds(0, 0, R.drawable.ic_clear_search_api_holo_light, 0);
  return tv;
}

上述图像没有任何分隔符...是否可以使用空分隔符而不是使用“,”?我尝试过不给出任何标记器,但多自动完成文本视图没有显示任何建议。 - VijayRaj

0
如果您指的是提示,您可以使用以下代码简单地添加它们:
android:hint="@string/myHint"

当EditText为空时,这将在其中放置灰色标签。


不要提示,它看起来像一个对象。 - Maurice

0

要在EditText左侧设置圆形图标,您可以更改leftDrawable

您可以在布局xml文件中执行此操作android:drawableRight="@drawable/search_icon"或使用setCompoundDrawablesWithIntrinsicBounds函数进行编程。

如果您还想提供气泡样式,则必须通过9-patch更改背景可绘制对象以具有该样式。 这里您可以找到一个用于Google地图的9-patch气泡教程。

希望它有所帮助! :)


我认为这不是他所问的。他只有一个编辑文本,并且文本条目可以进行样式设置。对吗? - davidcesarino

0
我认为可以使用setCompoundDrawables()方法将图片插入到编辑文本中。

那已经在Jordi的回答中提到了,但是那种可绘制对象与海报想要的文本不相符。 - Steve Pomeroy

-1

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