Skontaktuj się z dymkiem EditText


89

Staram się tworzyć bąbelki kontaktów w sposób MultiAutoCompleteTextViewpodobny do tego, jak jest to zaimplementowane w aplikacji Google+. Poniżej zrzut ekranu:

Zrzut ekranu tworzenia posta w Google+ .

Próbowałem rozszerzyć DynamicDrawableSpanklasę, aby uzyskać spanable do rysowania w tle zakresu tekstu

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

Gdzie mój plik do rysowania oval.xml jest zdefiniowany w następujący sposób:

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

W mojej klasie Activity, która ma MulitAutoCompleteTextView, ustawiam zakres bąbelków w następujący sposób:

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

Jednak zamiast owalnego kształtu wyświetlanego za pierwszymi 6 znakami w ciągu, znaki nie są widoczne i nie ma owalu, który można narysować w tle.

Jeśli zmienię metodę getDrawable () metody BubbleSpan, aby używała pliku .png zamiast kształtu możliwego do rysowania:

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

Następnie pojawi się .png, ale znaki w ciągu, które są częścią zakresu, nie pojawią się. Jak mogę to zrobić, aby znaki w zakresie były wyświetlane na pierwszym planie, podczas gdy niestandardowy kształt do rysowania jest wyświetlany w tle?

Próbowałem również użyć ImageSpanzamiast podklasy, DynamicDrawableSpanale nie powiodło się.



Jak
zdobywasz

github.com/splitwise/TokenAutoComplete może być pomocny dla niektórych
john-salib

Odpowiedzi:


55

Dzięki @chrish za wszelką pomoc. Oto jak to zrobiłem:

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
Odkryłem, że to nie działa na wszystkich urządzeniach z powodu problemów ze skalowaniem. Lepszym sposobem na zrobienie tego jest zwrócenie mapy bitowej z convertView, a następnie użycie rzeczywistych wymiarów mapy bitowej podczas ustawiania krawędzi rysowanych. Np. BitmapDrawable bd = new BitmapDrawable(bitmap); bd.setBounds(0,0,bitmap.getWidth(), bitmap.getHeight()); To działa we wszystkich urządzeniach.
dmon

Cześć, być może będę musiał opublikować to w nowym pytaniu, ale chciałem wiedzieć, czy napotkasz problemy z wielowierszowymi TextViews. Używam tego na Androidzie 3.2 i "czasami" wygląda na to, że szerokość bąbelka nie jest dobrze obliczona. Tak jak w tekście, nie będzie kontynuowane do następnej linii, ale zamiast tego będzie kontynuowane poza TextView. Jeśli widziałeś to, jakieś wskazówki?
Johann Hilbold

1
Jeśli tekst z bąbelkiem jest szerszy, to autouzupełnianie jest tworzone dwukrotnie w dwóch wierszach. Powinieneś ustawić to na textView: textView.setMaxWidth (this.getWidth () - SOME_PADDING); `I używam również tego (jeśli tekst jest zbyt duży, znajduje się w dwóch wierszach w bąbelku i ... na końcu): textView.setEllipsize (TruncateAt.END); textView.setSingleLine (false); textView.setMaxLines (2);
SocialError

to działa dobrze, aby wybrać z listy rozwijanej. W przypadku, gdy chcesz ustawić wstępnie zdefiniowane wartości w edittext, w jaki sposób mogę zawinąć ten tekst przyciskiem obramowanie i skrzyżowanie?
Braj

5
jak dodać moduł nasłuchiwania kliknięć do innego elementu w widoku tekstu, aby usunąć tekst.
Nambi

21

Oto kompletne rozwiązanie dla Ciebie

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

}

Oto pełny plik projektu, jeśli ktoś z was chce używać Spannble


1
dzięki ... Twoje rozwiązanie działa dobrze, ale moje problemy są po naciśnięciu przycisku DODAJ tekst bąbelkowy jest dodawany w tekście edycji, ale kiedy usuwam tekst edycji i próbuję ponownie wprowadzić (naciśnij przycisk Dodaj), poprzednio dodany bąbelek pozostaje i dołączony jest również nowy. a także usuwam bańkę po naciśnięciu prawego krzyża.
Govind Rathod,

Rozwiązanie pierwszego problemu. Domyślam się, że zapisałeś tekst na liście i nie wyczyściłeś go podczas czyszczenia Edytuj tekst. może nie mam racji, to było tylko przypuszczenie, ponieważ nie wiem, jak kodujesz.
Krishna Shrestha,

Wiem, że to stary post, ale potrzebuję odpowiedzi na moje pytanie ... buduję tę samą aplikację, co pokazano powyżej ... używam MultiAutoCompleteTextView do sugestii, a następnie tworzę bąbelki po kliknięciu elementu ... bąbelki są tworzone pomyślnie, ale moim problemem jest to, że nie chcę, aby kursor pojawiał się między dwoma bąbelkami ... Używam tokenizera spacji dla MultiAutoCompleteTextView ... jakaś wskazówka, jak to osiągnąć?
VijayRaj

@chrish Dzięki za ten kod, niemniej mam jedno pytanie. Mam sytuację, w której mam już przy sobie pewne wartości i wkleię je bezpośrednio do tekstu edycji jako teksty z możliwością rozszerzania. jednak teraz zastanawiam się tylko, czy możliwe jest połączenie kodu z projektu, który można dowolnie rozbudowywać, z tego rodzaju funkcjonalnością. Chcę mieć możliwość dodawania usuwania nazw w czasie wykonywania, dodawanie może się odbywać w paczkach, jednak usuwanie jest jak zwykle (jeden po drugim) .. dzięki
kuldeep

5

Mam bibliotekę, która robi to, czego szukasz:

  • Domyślny lub w pełni konfigurowalny (możesz nawet użyć własnego układu)
  • Obsługa wielu linii
  • Odbiornik kliknięć

Zajrzyj tutaj

Tutaj szybki start:

Dodaj ChipView do swojego układu lub utwórz go programowo:

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

Zainicjuj go z listą danych, które rozszerzają abstrakcyjny układ i odbiornikiem kliknięć (jeśli chcesz):

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

Domyślny ChipView jest renderowany w następujący sposób:

Domyślny ChipView

Ale możesz dostosować, jak chcesz, od ogólnego do poziomu Chip:

Ogólny ChipView Niestandardowy ChipView

To nie jest MultiAutocomplete, ale możesz go naśladować (właściwie używam go w ten sposób)

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.