Jaki jest główny cel setTag () getTag () metod View?

421

Jaki jest główny cel takich metod jak setTag() i getTag()na Viewobiektach typu?

Czy mam rację, myśląc, że mogę powiązać dowolną liczbę obiektów z jednym widokiem?

Eugene
źródło

Odpowiedzi:

636

Załóżmy, że generujesz kilka podobnych widoków. Możesz ustawić OnClickListenerosobno dla każdego widoku:

button1.setOnClickListener(new OnClickListener ... );
button2.setOnClickListener(new OnClickListener ... );
 ...

Następnie musisz utworzyć unikalną onClickmetodę dla każdego widoku, nawet jeśli robią podobne rzeczy, takie jak:

public void onClick(View v) {
    doAction(1); // 1 for button1, 2 for button2, etc.
}

Jest tak, ponieważ onClickma tylko jeden parametr, a View, i musi uzyskać inne informacje ze zmiennych instancji lub końcowych zmiennych lokalnych w obejmujących zakresach. Tak naprawdę chcemy uzyskać informacje z samych widoków .

Wpisz getTag/ setTag:

button1.setTag(1);
button2.setTag(2);

Teraz możemy użyć tego samego OnClickListener dla każdego przycisku:

listener = new OnClickListener() {
    @Override
    public void onClick(View v) {
        doAction(v.getTag());
    }
};

Jest to w zasadzie sposób, by widoki miały wspomnienia .

Matthew Willis
źródło
8
@Matthew Willis, ale możemy to zrobić również za pomocą view.getId (). Czyż nie ?
Android Killer
50
@AndroidKiller mógłbyś, ale dzięki setTag () możesz umieścić dowolny obiekt, nawet niestandardowe klasy - dzięki czemu możesz użyć ich do zachowania odniesienia do danych, które wyświetla widok
Daniel
Co powinienem zrobić, jeśli chcę tylko zmienić kolor tła klikniętego przycisku? Otrzymuję pozycję przez getTag ().
Sagar Devanga
2
@Sagar: public void ui_click(View view){ if(20==((int)view.getTag())) view.setBackgroundColor(colorInt); }powinien załatwić sprawę z częścią kolorową. 20 jest tylko symbolem zastępczym dla pozycji sprawdzającej poprawność Twojego Widoku.
RiA
Myślę, że to stary sposób. nowy sposób polega na użyciu ogólnych argumentów zapewniających bezpieczeństwo typu. ale to i tak jest dobre.
M.kazem Akhgary,
124

Chciałbym dodać kilka słów.

Chociaż używanie get/setTag(Object)wydaje się być bardzo przydatne w szczególnym przypadku wzorca ViewHolder, zalecam zastanowić się dwa razy przed użyciem go w innych przypadkach. Prawie zawsze istnieje inne rozwiązanie o lepszym designie.

Głównym powodem jest to, że taki kod dość szybko staje się nieobsługiwany.

  • Dla innych programistów nie jest oczywiste, co zaprojektowałeś do przechowywania jako znacznik w widoku. Metody setTag/getTagw ogóle nie mają charakteru opisowego.

  • Po prostu przechowuje plik Object, który trzeba rzucić, kiedy chcesz getTag. Nieoczekiwane awarie mogą wystąpić później, gdy zdecydujesz się zmienić typ przechowywanego obiektu w znaczniku.

  • Oto prawdziwa historia: mieliśmy całkiem duży projekt z dużą ilością adapterów, operacji asynchronicznych z widokami i tak dalej. Jeden programista postanowił set/getTagw swojej części kodu, ale inny już ustawił tag w tym widoku. W końcu ktoś nie mógł znaleźć własnej metki i był bardzo zdezorientowany. Znalezienie błędu kosztowało nas kilka godzin.

setTag(int key, Object tag)wygląda o wiele lepiej, ponieważ możesz wygenerować unikalne klucze dla każdego tagu (używając zasobów identyfikatora ), ale jest znaczące ograniczenie dla Androida <4.0. Z dokumentów Lint:

W wersjach wcześniejszych niż Android 4.0 implementacja View.setTag (int, Object) przechowywałaby obiekty w mapie statycznej, gdzie wartości były silnie przywoływane. Oznacza to, że jeśli obiekt zawiera odniesienia do kontekstu, kontekst (który wskazuje na prawie wszystko inne) wycieknie. Jeśli przejdziesz widok, widok zawiera odniesienie do kontekstu, który go utworzył. Podobnie, uchwyty widoków zazwyczaj zawierają widok, a kursory czasami są również powiązane z widokami.

Andrei Buneyeu
źródło
2
Dzięki, bardzo pomocna! ... Czy zdarza ci się wiedzieć, czy to, co jest w tagu, zostanie przywrócone między odtworzeniami działań?
gunar
25

Możemy używać setTag()i getTag()ustawiać i uzyskiwać niestandardowe obiekty zgodnie z naszymi wymaganiami. setTag()Metoda wymaga argumentu typu Objecti getTag()zwraca Object.

Na przykład,

Person p = new Person();
p.setName("Ramkailash");
p.setId(2000001);
button1.setTag(p);
Ramkailash
źródło
20

Dla twórców stron internetowych wydaje się, że jest to odpowiednik danych…

Oren
źródło
14

Jest to bardzo przydatne do niestandardowego ArrayAdapterkorzystania. To jest jakaś optymalizacja. Jest setTagużywany jako odniesienie do obiektu odniesienia na niektórych częściach układu (czyli wyświetlanie w ListView) zamiast findViewById.

static class ViewHolder {
    TextView tvPost;
    TextView tvDate;
    ImageView thumb;
}

public View getView(int position, View convertView, ViewGroup parent) {

    if (convertView == null) {
        LayoutInflater inflater = myContext.getLayoutInflater();
        convertView = inflater.inflate(R.layout.postitem, null);

        ViewHolder vh = new ViewHolder();
        vh.tvPost = (TextView)convertView.findViewById(R.id.postTitleLabel);
        vh.tvDate = (TextView)convertView.findViewById(R.id.postDateLabel);
        vh.thumb = (ImageView)convertView.findViewById(R.id.postThumb);
        convertView.setTag(vh);
    }
            ....................
}
shubniggurath
źródło
13

W przeciwieństwie do identyfikatorów tagi nie są używane do identyfikowania widoków. Tagi są w zasadzie dodatkową informacją, którą można powiązać z widokiem. Są one najczęściej używane jako wygoda do przechowywania danych związanych z widokami w samych widokach, zamiast umieszczania ich w osobnej strukturze.

Odniesienie: http://developer.android.com/reference/android/view/View.html

Saad Bilal
źródło
11

Ustawienie TAG jest bardzo przydatne, gdy masz ListView i chcesz odtworzyć / ponownie wykorzystać widoki. W ten sposób ListView staje się bardzo podobny do nowszego RecyclerView.

@Override
public View getView(int position, View convertView, ViewGroup parent)
  {
ViewHolder holder = null;

if ( convertView == null )
{
    /* There is no view at this position, we create a new one. 
       In this case by inflating an xml layout */
    convertView = mInflater.inflate(R.layout.listview_item, null);  
    holder = new ViewHolder();
    holder.toggleOk = (ToggleButton) convertView.findViewById( R.id.togOk );
    convertView.setTag (holder);
}
else
{
    /* We recycle a View that already exists */
    holder = (ViewHolder) convertView.getTag ();
}

// Once we have a reference to the View we are returning, we set its values.

// Here is where you should set the ToggleButton value for this item!!!

holder.toggleOk.setChecked( mToggles.get( position ) );

return convertView;
}

źródło