【问题标题】:Contact Bubble EditText联系气泡编辑文本
【发布时间】:2012-06-04 10:53:39
【问题描述】:

我正在尝试在 MultiAutoCompleteTextView 中创建联系人气泡,类似于它在 Google+ 应用中的实现方式。下面是截图:

.

我已尝试扩展 DynamicDrawableSpan 类,以便在一段文本的背景中获得一个可扩展的可绘制对象

public class BubbleSpan extends DynamicDrawableSpan {
  private Context c;

  public BubbleSpan(Context context) {
    super();
    c = context;
  }

  @Override
  public Drawable getDrawable() {
    Resources res = c.getResources();
    Drawable d = res.getDrawable(R.drawable.oval);
    d.setBounds(0, 0, 100, 20);
    return d;
  }
}

我的椭圆形.xml 可绘制对象是这样定义的:

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle">
  <solid android:color="#352765"/>
  <padding android:left="7dp" android:top="7dp"
    android:right="7dp" android:bottom="7dp" />
  <corners android:radius="6dp" />
</shape>

在具有MulitAutoCompleteTextView 的 Activity 类中,我将气泡跨度设置如下:

final Editable e = tv.getEditableText();
final SpannableStringBuilder sb = new SpannableStringBuilder();
sb.append("some sample text");
sb.setSpan(new BubbleSpan(getApplicationContext()), 0, 6, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
e.append(sb); 

但是,字符串中的前 6 个字符后面不是显示椭圆形,而是字符不可见,并且背景中没有可绘制的椭圆形。

如果我将 BubbleSpan 的 getDrawable() 方法更改为使用 .png 而不是可绘制的形状:

public Drawable getDrawable() {
  Resources res = c.getResources();
  Drawable d = res.getDrawable(android.R.drawable.bottom_bar);
  d.setBounds(0, 0, 100, 20);
  return d;
}

然后 .png 将显示,但作为 span 的一部分的字符串中的字符将不会显示。如何使 span 中的字符显示在前台,同时自定义形状 drawable 显示在后台?

我也尝试使用ImageSpan,而不是子类化DynamicDrawableSpan,但没有成功。

【问题讨论】:

标签: android android-edittext drawable html


【解决方案1】:

感谢@chrish 的所有帮助。所以我是这样做的:

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 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;
}

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);

}

【讨论】:

  • 我发现由于缩放问题,这不适用于所有设备。更好的方法是从 convertView 返回位图,然后在设置可绘制边缘时使用实际位图的尺寸。例如。 BitmapDrawable bd = new BitmapDrawable(bitmap); bd.setBounds(0,0,bitmap.getWidth(), bitmap.getHeight()); 适用于所有设备。
  • 嗨,我可能需要在一个新问题中发布这个,但想知道您是否遇到了多行 TextViews 的问题。我在 Android 3.2 和“有时”上运行它,看起来气泡的宽度计算得不好。如在文本中不会继续到下一行,而是在TextView 之外继续。如果你看过这个,有什么建议吗?
  • 如果带有气泡的文本比自动完成更宽,气泡会在两行中创建两次。您应该将此设置为 textView: textView.setMaxWidth(this.getWidth() - SOME_PADDING);` 而且我也在使用它(如果文本太大,则在气泡中的两行中,最后带有 ...): textView.setEllipsize(TruncateAt.END); textView.setSingleLine(false); textView.setMaxLines(2);
  • 如果你从下拉列表中选择,这很好用。如果您想为edittext设置一些预定义的值,那么,我如何用边框n十字按钮包装该文本?
  • 如何将 clicklistener 添加到 textview 中的不同项目以删除文本。
【解决方案2】:

这里有一个完整的解决方案

//creating textview dynamicalyy
TextView textView=new TextView(context);
textview.setText("Lauren amos");
textview.setbackgroundResource(r.color.urovalshape);
textView.setCompoundDrawablesWithIntrinsicBounds(0, 0, R.drawable.icon_cross, 0);


BitmapDrawable dd = (BitmapDrawable) SmsUtil.getDrawableFromTExtView(textView);
edittext.settext(addSmily(dd));

//convert image to spannableString
public SpannableStringBuilder addSmily(Drawable dd) {
 dd.setBounds(0, 0, dd.getIntrinsicWidth(),dd.getIntrinsicHeight());
SpannableStringBuilder builder = new SpannableStringBuilder();
builder.append(":-)");
builder.setSpan(new ImageSpan(dd), builder.length() - ":-)".length(),builder.length(),Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);

return builder;
}

  //convert view to drawable
  public static Object getDrawableFromTExtView(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.getWidth(), view.getHeight(),
            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);

}

这是完整的项目文件,如果你想使用 Spannble

【讨论】:

  • 谢谢...您的解决方案工作正常,但我的问题是当我按下添加按钮时,气泡文本被添加到编辑文本中,但是当我清除编辑文本并尝试重新输入时(按添加按钮)之前添加的气泡仍然存在,并且也添加了新气泡。当按下右侧十字标志时,我也会删除气泡。
  • 解决第一个问题。我猜您将文本存储在列表中,而您在清除编辑文本时没有清除。我可能不是赖特,这只是一个猜测,因为我不知道你是如何编码的。
  • 我知道这是一篇旧帖子,但我需要回答我的问题..我正在构建与上图相同的应用程序..我使用 MultiAutoCompleteTextView 获取建议,然后在单击该项目时创建气泡..气泡已成功创建,但我的问题是我不希望光标出现在两个气泡之间...我正在为 MultiAutoCompleteTextView 使用空间标记器 ..任何线索如何实现这一点??
  • @chrish 感谢您提供这段代码,不过我还有一个问题。我有一种情况,我已经有了一些值,我会将它们作为可跨文本直接粘贴到编辑文本中。但是,现在我只是想知道是否可以将可跨项目的代码与这种功能结合起来。我希望能够在运行时添加删除名称,添加可能会发生在一堆,但是删除是像往常一样(一个接一个)..谢谢
【解决方案3】:

我有一个库可以满足您的需求:

  • 默认或完全可自定义(您甚至可以使用自己的布局)
  • 多行支持
  • 点击监听器

Have a look here

这里是快速入门:

将 ChipView 添加到您的布局或以编程方式创建它:

<com.plumillonforge.android.chipview.ChipView
    android:id="@+id/chipview"
    android:layout_width="match_parent"
    android:layout_height="wrap_content" />

使用扩展抽象芯片的数据列表和点击监听器(如果需要)初始化它:

List<Chip> chipList = new ArrayList<>();
chipList.add(new Tag("Lorem"));
chipList.add(new Tag("Ipsum dolor"));
chipList.add(new Tag("Sit amet"));
chipList.add(new Tag("Consectetur"));
chipList.add(new Tag("adipiscing elit"));
ChipView chipDefault = (ChipView) findViewById(R.id.chipview);
chipDefault.setChipList(chipList);
chipDefault.setOnChipClickListener(new OnChipClickListener() {
        @Override
        public void onChipClick(Chip chip) {
            // Action here !
        }
    });

默认的 ChipView 是这样渲染的:

但您可以从整体到芯片级别任意定制:

这不是 MultiAutocomplete,但你可以设法模仿它(我实际上是这样使用它的)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-04-20
    • 1970-01-01
    • 1970-01-01
    • 2012-11-12
    • 1970-01-01
    • 1970-01-01
    • 2013-10-31
    相关资源
    最近更新 更多