2012-07-03 9 views
23

Szukałem w pobliżu, ale nie mogłem znaleźć odpowiedzi na to. Próbuję zaimplementować EditText podobny do pola "Do" znalezionego na ekranie tworzenia aplikacji Gmaila ICS.Tworzenie niestandardowego editText z funkcją podobną do znacznika

Oto obraz opisujący to, co chcę: enter image description here

myślę przedłużenia EditText i wdrażaniu własną zwyczaj EditText klasę, ale nie jestem pewien jak to zrobić, a nawet jeśli jest to najlepsze rozwiązanie . jakieś pomysły?

+1

Off mankietu, to myślę, że widzisz regularnego 'EditText', na' 'Spannable' który zawiera elementy ImageSpan' dla„tagów”. Jednakże jeśli te fragmenty "x" oznaczają, że kliknięcie na tagu usuwa to, to nie sądzę, że jest to możliwe w przypadku 'ImageSpan'. – CommonsWare

+1

Hmm, to brzmi rozsądnie, ale tak, Google go uruchomił (z małym "x", aby go usunąć) w swojej aplikacji Gmail, więc jestem pewien, że gdzieś jest pełne rozwiązanie. Mam nadzieję, że to nie jest za dużo hackowania –

+0

@BillX: Czy mogę wiedzieć, z którego rozwiązania zdecydowałeś się skorzystać? Dzięki! – Loc

Odpowiedz

4

Hm, zajęło to trochę czasu, aby znaleźć podobne pytanie, ale mimo to, oto closest answer I found. Wiedziałem, że inni ludzie mieli tego rodzaju problem wcześniej! Podziękowania dla Commons za wskazanie mnie we właściwym kierunku.

4

nie mogłem znaleźć dobre rozwiązanie, więc będę się buduje własną bibliotekę do obsługi to: TokenAutoComplete. Oto prosty przykład: Kod

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

Layout dla contact_token (musisz znaleźć własną x rozciągliwej)

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

Reklamowe backgound odkształcalne

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

Osoba kodu wynikowego

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

Sample Vity

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

Kod układu

<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

Jestem w tej samej sytuacji BillX. Czy mogę wiedzieć, że twoje rozwiązanie działa z przyciskiem x-close? Dzięki. – Loc

+0

@LocHa Czy znalazłeś jakieś rozwiązanie dla funkcji przycisku x-close? –

+0

@SwapnilSonar: Nie znalazłem żadnego kompletnego rozwiązania. Stworzyłem własny sposób edycji tagów (nie tak, jak chce BillX). Możesz się czegoś nauczyć na stronie kpbird.com/2013/02/android-chips-edittext-token-edittext.html – Loc

5

Dostosowany roztwór z this answer. Oddziela wejście automatycznie podczas wstawiania przecinka (można ustawić separator). Tworzy ImageSpan i ClickableSpan (wpisy można usunąć, klikając prawą część).

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> 

Ostatnią rzeczą, aby dodać, png dla "x-Buttona". Do tej pory działa dobrze, tylko problem polega na tym, że naciskanie długiego klawisza delete nie działa (jeśli ktoś ma pomysł, jak to działa, prosimy o komentarz)

+0

Dobra robota, zastanawiałem się, dlaczego nie widzę kursora migającego początkowo, kiedy dodam to. – prateek31

1

Stworzyłem library, aby rozwiązać ten problem, nie krępuj się go używać i przyczynić się.

+0

za pomocą swojej miłej biblioteki, czy możesz dać mi znać, jak usunąć tag z tyłu (usunąć) naciśnij SoftKeyboard? – Dhiren

Powiązane problemy