2012-07-03 11 views
23

He estado buscando pero no he podido encontrar ninguna respuesta. Lo que intento implementar es un EditText similar al campo 'To' que se encuentra en la pantalla de composición de la aplicación ICS gmail.Creando un editText personalizado con función de etiqueta

Aquí está la descripción de una imagen lo que quiero: enter image description here

Estoy pensando en extender EditText e implementar mi propia clase personalizada EditText pero no estoy muy seguro de cómo hacerlo o incluso si esa es la mejor solución . ¿Alguna idea?

+1

Fuera de la manga, supongo que está viendo un 'EditText' regular, en un' Spannable' que contiene elementos 'ImageSpan' para las" etiquetas ". Sin embargo, si esas porciones "x" significan que tocar la etiqueta lo quita, entonces no creo que sea posible con 'ImageSpan'. – CommonsWare

+1

Mmm, eso suena razonable, pero sí, Google lo hizo funcionar (con la pequeña "x" para eliminarlo) en su aplicación de Gmail, así que estoy bastante seguro de que hay una solución completa en alguna parte. Con suerte, no es demasiado hackeo –

+0

@BillX: ¿Puedo saber qué solución ha decidido utilizar? ¡Gracias! – Loc

Respuesta

4

Hm, tomó un tiempo para encontrar una pregunta similar, pero no obstante, aquí está el closest answer I found. ¡Sabía que otras personas tenían este tipo de problema antes! Gracias a CommonsWare por señalarme en la dirección correcta.

4

No pude encontrar una buena solución, así que me gustaría construir mi propia biblioteca para manejar esto: TokenAutoComplete. Aquí hay un ejemplo básico: Código

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.getName()); 

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

Disposición para contact_token (que tendrá que encontrar su propio x estirable)

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 
    android:layout_height="wrap_content" 
    android:layout_width="wrap_content" 
    android:background="@drawable/token_background"> 
    <TextView android:id="@+id/name" 
     android:layout_width="wrap_content" 
     android:layout_height="wrap_content" 
     android:textColor="@android:color/white" 
     android:textSize="14sp" 
     android:text="Test Me" 
     android:padding="2dp" /> 

    <ImageView 
     android:layout_height="10dp" 
     android:layout_width="10dp" 
     android:src="@drawable/x" 
     android:layout_gravity="center_vertical" 
     android:layout_marginLeft="3dp" 
     android:layout_marginRight="5dp" /> 
</LinearLayout> 

backgound simbólico dibujable

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

Persona código objeto

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

Muestra acti vidad

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", "[email protected]"), 
       new Person("Margaret Smith", "[email protected]"), 
       new Person("Max Jordan", "[email protected]"), 
       new Person("Meg Peterson", "[email protected]"), 
       new Person("Amanda Johnson", "[email protected]"), 
       new Person("Terry Anderson", "[email protected]") 
     }; 

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

     completionView = (ContactsCompletionView)findViewById(R.id.searchView); 
     completionView.setAdapter(adapter); 
     completionView.setTokenClickStyle(TokenCompleteTextView.TokenClickStyle.Delete); 
    } 
} 

código Layout

<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> 
+0

Estoy en la misma situación de BillX. ¿Puedo saber que su solución funciona con el botón x-close? Gracias. – Loc

+0

@LocHa ¿Encontró alguna solución para la funcionalidad del botón x-close? –

+0

@SwapnilSonar: No encontré ninguna solución completa. Creé mi propia forma de editar etiquetas (no como BillX quiere). Puedes aprender algo de kpbird.com/2013/02/android-chips-edittext-token-edittext.html – Loc

5

Adaptado la solución de this answer. Separa la entrada automáticamente al insertar una coma (se puede ajustar el separador). Crea un ImageSpan y un ClickableSpan (las entradas se pueden eliminar haciendo clic en la parte derecha).

public class TagEditText extends EditText { 

    TextWatcher textWatcher; 

    String lastString; 

    String separator = ","; 

    public TagEditText(Context context, AttributeSet attrs) { 
     super(context, attrs); 
     init(); 
    } 


    private void init() { 
     setMovementMethod(LinkMovementMethod.getInstance()); 

     textWatcher = new TextWatcher() { 
      @Override 
      public void beforeTextChanged(CharSequence s, int start, int count, int after) { 

      } 

      @Override 
      public void onTextChanged(CharSequence s, int start, int before, int count) { 

      } 

      @Override 
      public void afterTextChanged(Editable s) { 
       String thisString = s.toString(); 
       if (thisString.length() > 0 && !thisString.equals(lastString)) { 
        format(); 

       } 
      } 
     }; 

     addTextChangedListener(textWatcher); 
    } 


    private void format() { 

     SpannableStringBuilder sb = new SpannableStringBuilder(); 
     String fullString = getText().toString(); 

     String[] strings = fullString.split(separator); 


     for (int i = 0; i < strings.length; i++) { 

      String string = strings[i]; 
      sb.append(string); 

      if (fullString.charAt(fullString.length() - 1) != separator.charAt(0) && i == strings.length - 1) { 
       break; 
      } 

      BitmapDrawable bd = (BitmapDrawable) convertViewToDrawable(createTokenView(string)); 
      bd.setBounds(0, 0, bd.getIntrinsicWidth(), bd.getIntrinsicHeight()); 

      int startIdx = sb.length() - (string.length()); 
      int endIdx = sb.length(); 

      sb.setSpan(new ImageSpan(bd), startIdx, endIdx, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); 

      MyClickableSpan myClickableSpan = new MyClickableSpan(startIdx, endIdx); 
      sb.setSpan(myClickableSpan, Math.max(endIdx-2, startIdx), endIdx, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); 

      if (i < strings.length - 1) { 
       sb.append(separator); 
      } else if (fullString.charAt(fullString.length() - 1) == separator.charAt(0)) { 
       sb.append(separator); 
      } 
     } 


     lastString = sb.toString(); 

     setText(sb); 
     setSelection(sb.length()); 

    } 

    public View createTokenView(String text) { 


     LinearLayout l = new LinearLayout(getContext()); 
     l.setOrientation(LinearLayout.HORIZONTAL); 
     l.setBackgroundResource(R.drawable.bordered_rectangle_rounded_corners); 

     TextView tv = new TextView(getContext()); 
     l.addView(tv); 
     tv.setText(text); 
     tv.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); 

     ImageView im = new ImageView(getContext()); 
     l.addView(im); 
     im.setImageResource(R.drawable.ic_cross_15dp); 
     im.setScaleType(ImageView.ScaleType.FIT_CENTER); 

     return l; 
    } 

    public Object convertViewToDrawable(View view) { 
     int spec = View.MeasureSpec.makeMeasureSpec(0, View.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(getContext().getResources(), viewBmp); 
    } 

    private class MyClickableSpan extends ClickableSpan{ 

     int startIdx; 
     int endIdx; 

     public MyClickableSpan(int startIdx, int endIdx) { 
      super(); 
      this.startIdx = startIdx; 
      this.endIdx = endIdx; 
     } 

     @Override 
     public void onClick(View widget) { 



      String s = getText().toString(); 

      String s1 = s.substring(0, startIdx); 
      String s2 = s.substring(Math.min(endIdx+1, s.length()-1), s.length()); 

      TagEditText.this.setText(s1 + s2); 
     } 

    } 
} 

R.drawable.bordered_rectangle_rounded_corners:

<shape xmlns:android="http://schemas.android.com/apk/res/android"> 
    <solid 
     android:color="@color/transparent"/> 
    <stroke android:width="1dp" android:color="#AAAAAA" /> 
    <corners 
     android:radius="100dp" /> 
    <padding 
     android:left="5dp" 
     android:top="5dp" 
     android:right="5dp" 
     android:bottom="5dp" /> 
</shape> 

último que hay que añadir es png para el "X-Button". Funciona bien hasta el momento, el único problema es que presionar largo en la tecla eliminar no funciona (si alguien tiene una idea de cómo hacerlo funcionar, no dude en comentar)

+0

Buen trabajo allí, me preguntaba por qué no puedo ver un cursor parpadeando inicialmente cuando agrego esto. – prateek31

1

Creé un library para resolver este problema, siéntete libre de usarlo y contribuir.

+0

mediante el uso de su biblioteca agradable, ¿puede por favor hágamelo saber, cómo eliminar la etiqueta de la parte posterior (borrar), presione en un teclado suave? – Dhiren

Cuestiones relacionadas