J'ai cherché autour mais je n'ai pas pu trouver de réponses à cela. Ce que j'essaye d'implémenter est un EditText similaire au champ 'To' trouvé dans l'écran de composition de l'application gmail ICS.
Voici une image décrivant ce que je veux:
J'envisage d'étendre EditText
et d'implémenter ma propre classe EditText
personnalisée, mais je ne sais pas vraiment comment le faire ou même si c'est la meilleure solution. Des pensées?
Hm, a mis du temps à trouver une question similaire mais néanmoins, voici la réponse la plus proche que j'ai trouvée . Je savais que d'autres personnes avaient ce genre de problème auparavant! Merci à CommonsWare de m'avoir indiqué dans la bonne direction.
Adapté la solution de cette réponse . Sépare l'entrée automatiquement lors de l'insertion d'une virgule (le séparateur peut être ajusté). Crée un ImageSpan et un ClickableSpan (les entrées peuvent être supprimées en cliquant sur la partie droite).
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>
La dernière chose à ajouter est le png pour le "x-Button". Fonctionne bien jusqu'à présent, le seul problème est que le fait d'appuyer longuement sur la touche de suppression ne fonctionne pas (si quelqu'un a une idée de comment le faire fonctionner, n'hésitez pas à commenter)
Je ne pouvais pas trouver une bonne solution, donc je construirais ma propre bibliothèque pour gérer cela: TokenAutoComplete . Voici un exemple de base:
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);
}
}
}
Code de mise en page pour contact_token (vous devrez trouver votre propre x dessinable)
<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>
Fond de jeton dessinable
<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>
Code objet personne
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; }
}
Exemple d'activité
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);
}
}
Code de mise en page
<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>