Contact Bubble EditText


89

Estou tentando criar bolhas de contato no MultiAutoCompleteTextViewsimilar a como ele é implementado no aplicativo Google+. Abaixo está uma captura de tela:

Captura de tela do Google+ Compor postagem .

Tentei estender a DynamicDrawableSpanclasse para obter um drawable spannable no fundo de uma extensão de texto

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

Onde meu drawable oval.xml é definido assim:

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

Na minha classe de atividade que tem o MulitAutoCompleteTextView, eu defino a amplitude da bolha assim:

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

No entanto, em vez da forma oval exibida atrás dos primeiros 6 caracteres na string, os caracteres não são visíveis e não há drawable oval no fundo.

Se eu alterar o método getDrawable () do BubbleSpan para usar um .png em vez de um drawable de forma:

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

Em seguida, o .png aparecerá, mas os caracteres na string que fazem parte do período não serão exibidos. Como posso fazer com que os caracteres no intervalo sejam exibidos em primeiro plano, enquanto um drawable de forma personalizada é exibido em segundo plano?

Também tentei usar um em ImageSpanvez de uma subclasse, DynamicDrawableSpanmas não tive êxito.



Como você está recebendo os números de contato selecionados
Srihari

Respostas:


55

Obrigado @chrish por toda a ajuda. Então, aqui está como eu fiz:

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
Descobri que isso não funcionava em todos os dispositivos devido a problemas de dimensionamento. A melhor maneira de fazer isso é retornar o bitmap de convertView e, em seguida, usar as dimensões reais do bitmap ao definir as bordas drawable. Por exemplo, BitmapDrawable bd = new BitmapDrawable(bitmap); bd.setBounds(0,0,bitmap.getWidth(), bitmap.getHeight()); isso funciona em todos os dispositivos.
dmon

Olá, talvez seja necessário postar isso em uma nova pergunta, mas queria saber se você encontrou problemas com TextViews de várias linhas. Estou executando isso no Android 3.2 e, "às vezes", parece que a largura da bolha não está bem calculada. Como no texto, não continuará para a próxima linha, mas em vez disso, continuará fora de TextView. Se você já viu isso, alguma dica?
Johann Hilbold

1
Se o texto com bolha for mais largo que o preenchimento automático, a bolha será criada duas vezes em duas linhas. Você deve definir isso para textView: textView.setMaxWidth (this.getWidth () - SOME_PADDING); `E também estou usando isso (se o texto for muito grande, está em duas linhas no balão e com ... no final): textView.setEllipsize (TruncateAt.END); textView.setSingleLine (false); textView.setMaxLines (2);
SocialError

isso funciona bem quando você seleciona na lista suspensa. No caso, se vc quiser definir alguns valores predefinidos para editar o texto, como posso quebrar esse texto com o botão de cruz de borda n?
Braj,

5
como você adiciona o clicklistener a um item diferente na textview para excluir o texto.
Nambi

21

Aqui está uma solução completa para você

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

}

Aqui está o arquivo do projeto completo, se algum de vocês quiser usar o Spannble


1
obrigado ... sua solução funciona bem, mas meus problemas são quando eu pressionei o botão ADICIONAR. O texto da bolha é adicionado no texto de edição, mas quando eu Limpo o texto de edição e tento entrar novamente (pressione o botão Adicionar), a bolha adicionada anteriormente permanece e um novo também é anexado. e também removo a bolha ao pressionar o sinal de cruz do lado direito.
Govind Rathod

Resolvendo o primeiro problema. Acho que você armazenou texto na lista e não apagou ao limpar Editar texto. posso não estar certo, foi apenas um palpite, pois não sei como você codifica.
Krishna Shrestha

Eu sei que é um post antigo, mas preciso responder à minha pergunta .. Estou construindo o mesmo aplicativo mostrado acima .. estou usando MultiAutoCompleteTextView para as sugestões e, em seguida, crie as bolhas quando o item for clicado .. as bolhas são criadas com sucesso, mas meu problema é que não quero que o cursor apareça entre as duas bolhas ... Estou usando o tokenizer de espaço para MultiAutoCompleteTextView ... alguma pista de como fazer isso ??
VijayRaj

@chrish Obrigado por este código, tenho uma pergunta, no entanto. Tenho uma situação em que já tenho alguns valores comigo e irei colá-los diretamente no texto de edição como textos expansíveis. no entanto, agora eu só me pergunto se é possível combinar seu código de projeto spannable com esse tipo de funcionalidade. Eu quero ter a capacidade de adicionar nomes de exclusão em tempo de execução, adicionando pode acontecer em grupo, no entanto, a exclusão é como de costume (um por um) .. obrigado
kuldeep

5

Eu tenho uma biblioteca que faz o que você procura:

  • Padrão ou totalmente personalizável (você pode até usar seu próprio layout)
  • Suporte multilinha
  • Click listener

Dê uma olhada aqui

Aqui está um início rápido:

Adicione ChipView ao seu layout ou crie-o programaticamente:

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

Inicie com uma lista de dados que se estendem ao Chip abstrato e um ouvinte de clique (se desejar):

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 padrão é renderizado assim:

ChipView padrão

Mas você pode personalizar como quiser do nível geral para o nível de Chip:

ChipView geral ChipView personalizado

Este não é um MultiAutocomplete, mas você pode conseguir imitá-lo (na verdade, estou usando-o assim)

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.