Связаться с Bubble EditText


89

Я пытаюсь создать пузыри контактов MultiAutoCompleteTextViewаналогично тому, как это реализовано в приложении Google+. Ниже приведен снимок экрана:

Скриншот Google+ Compose Post .

Я попытался расширить 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;
  }
}

Где мой объект oval.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>

В моем классе Activity, который имеет MulitAutoCompleteTextView, я устанавливаю диапазон пузырьков следующим образом:

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 символами в строке, символы не видны, и на заднем плане нет овала, который можно рисовать.

Если я изменю метод getDrawable () BubbleSpan на использование .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, но символы в строке, которые являются частью диапазона, не появятся. Как я могу сделать так, чтобы символы в диапазоне отображались на переднем плане, в то время как настраиваемая фигура, которую можно рисовать, отображалась в фоновом режиме?

Я попытался также использовать ImageSpanвместо подкласса, DynamicDrawableSpanно безуспешно.



Как вы получаете выбранные контактные номера
шрихари,

github.com/splitwise/TokenAutoComplete может быть полезным для некоторых
john-salib 08

Ответы:


55

Спасибо @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);

}

13
Я обнаружил, что это работает не на всех устройствах из-за проблем с масштабированием. Лучший способ сделать это - вернуть растровое изображение из convertView, а затем использовать фактические размеры растрового изображения при установке рисуемых краев. Например, BitmapDrawable bd = new BitmapDrawable(bitmap); bd.setBounds(0,0,bitmap.getWidth(), bitmap.getHeight()); это работает на всех устройствах.
dmon

Привет, мне может потребоваться опубликовать это в новом вопросе, но я хотел знать, не возникали ли у вас проблемы с многострочными TextView. Я запускаю это на Android 3.2 и "иногда", похоже, ширина пузыря не рассчитывается. Как и в тексте, не перейдет к следующей строке, а вместо этого продолжит за пределами TextView. Если вы это видели, какие-нибудь советы?
Johann Hilbold

1
Если текст с пузырьком шире, то при автозаполнении пузырь создается дважды в две строки. Вы должны установить это в textView: textView.setMaxWidth (this.getWidth () - SOME_PADDING); `И я также использую это (если текст слишком большой, находится в двух строках в пузыре и с ... в конце): textView.setEllipsize (TruncateAt.END); textView.setSingleLine (ложь); textView.setMaxLines (2);
SocialError

это отлично работает при выборе из раскрывающегося списка. В случае, если вы хотите установить некоторые предопределенные значения для редактирования текста, тогда как я могу обернуть этот текст кнопкой пересечения границы n?
Braj

5
как добавить прослушиватель кликов к другому элементу в текстовом окне, чтобы удалить текст.
Nambi

21

Вот вам полное решение

//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


1
спасибо ... ваше решение работает нормально, но мои проблемы заключаются в том, что когда я нажимаю кнопку ДОБАВИТЬ, пузырьковый текст добавляется в текст редактирования, но когда я очищаю текст редактирования и пытаюсь повторно ввести (нажмите кнопку Добавить), ранее добавленный пузырь остается и добавляется и новый. И я также удаляю пузырь, когда нажимаю крестик с правой стороны.
Govind Rathod

Решение первой проблемы. Я думаю, вы сохранили текст в списке, и вы не очистили его при очистке текста редактирования. Я не могу быть прав, это было только предположение, поскольку я не знаю, как вы кодируете.
Кришна Шрестха

Я знаю, что это старый пост, но мне нужен ответ на свой вопрос. Я создаю такое же приложение, как показано выше. Я использую MultiAutoCompleteTextView для предложений, а затем создаю пузыри при нажатии на элемент .. пузыри создаются успешно, но моя проблема в том, что я не хочу, чтобы курсор появлялся между двумя пузырями ... Я использую пространственный токенизатор для MultiAutoCompleteTextView .. любой ключ, как этого добиться ??
VijayRaj

@chrish Спасибо за этот код, но у меня есть один вопрос. У меня есть ситуация, когда у меня уже есть некоторые значения, и я вставлю их прямо в текст редактирования как составные тексты. однако теперь я просто задаюсь вопросом, можно ли объединить ваш код из проекта spannable с такой функциональностью. Я хочу иметь возможность добавлять имена для удаления во время выполнения, добавление может происходить группами, однако удаление выполняется как обычно (одно за другим) .. спасибо
kuldeep

5

У меня есть библиотека, которая делает то, что вы ищете:

  • По умолчанию или полностью настраиваемый (вы даже можете использовать свой собственный макет)
  • Многострочная поддержка
  • Слушатель кликов

Посмотри сюда

Вот краткое руководство:

Добавьте ChipView в свой макет или создайте его программно:

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

Запустите его со списком данных, которые расширяют абстрактный Chip, и прослушивателем кликов (если хотите):

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 по умолчанию отображается так:

ChipView по умолчанию

Но вы можете настроить по своему усмотрению от общего до уровня чипа:

Общий ChipView Пользовательский ChipView

Это не MultiAutocomplete, но вы можете имитировать его (на самом деле я использую его именно так)

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.