Antworten:
Angenommen, Sie generieren eine Reihe ähnlicher Ansichten. Sie können OnClickListener
für jede Ansicht einzeln eine festlegen :
button1.setOnClickListener(new OnClickListener ... );
button2.setOnClickListener(new OnClickListener ... );
...
Dann müssen Sie onClick
für jede Ansicht eine eindeutige Methode erstellen, auch wenn sie ähnliche Aktionen ausführen, z.
public void onClick(View v) {
doAction(1); // 1 for button1, 2 for button2, etc.
}
Dies liegt daran, dass onClick
nur ein Parameter a vorhanden View
ist und andere Informationen von Instanzvariablen oder endgültigen lokalen Variablen in umschließenden Bereichen abgerufen werden müssen. Was wir wirklich wollen, ist, Informationen aus den Ansichten selbst zu erhalten .
Geben Sie getTag
/ setTag
:
button1.setTag(1);
button2.setTag(2);
Jetzt können wir für jede Schaltfläche denselben OnClickListener verwenden:
listener = new OnClickListener() {
@Override
public void onClick(View v) {
doAction(v.getTag());
}
};
Es ist im Grunde eine Möglichkeit für Ansichten, Erinnerungen zu haben .
public void ui_click(View view){ if(20==((int)view.getTag())) view.setBackgroundColor(colorInt); }
sollte den Trick für den Farbteil machen. 20 ist nur ein Platzhalter für die Validierungsposition Ihrer Ansicht.
Ich möchte ein paar Worte hinzufügen.
Obwohl die Verwendung get/setTag(Object)
im speziellen Fall eines ViewHolder-Musters sehr nützlich zu sein scheint, würde ich empfehlen, zweimal darüber nachzudenken, bevor Sie es in anderen Fällen verwenden. Es gibt fast immer eine andere Lösung mit besserem Design.
Der Hauptgrund ist, dass solcher Code ziemlich schnell nicht mehr unterstützt werden kann.
Für andere Entwickler ist es nicht offensichtlich, was Sie als Tag in der Ansicht speichern möchten. Die Methoden setTag/getTag
sind überhaupt nicht beschreibend.
Es speichert nur eine Object
, die gegossen werden muss, wenn Sie möchten getTag
. Sie können später zu unerwarteten Abstürzen kommen, wenn Sie den Typ des im Tag gespeicherten Objekts ändern.
Hier ist eine reale Geschichte: Wir hatten ein ziemlich großes Projekt mit vielen Adaptern, asynchronen Operationen mit Ansichten und so weiter. Ein Entwickler entschied sich für set/getTag
seinen Teil des Codes, aber ein anderer hatte das Tag bereits auf diese Ansicht gesetzt. Am Ende konnte jemand sein eigenes Etikett nicht finden und war sehr verwirrt. Es hat uns mehrere Stunden gekostet, den Fehler zu finden.
setTag(int key, Object tag)
sieht viel besser aus, da Sie für jedes Tag eindeutige Schlüssel generieren können (mithilfe von ID-Ressourcen ), aber für Android <4.0 gibt es eine erhebliche Einschränkung. Aus Lint-Dokumenten:
Vor Android 4.0 wurden bei der Implementierung von View.setTag (int, Object) die Objekte in einer statischen Karte gespeichert, auf die stark verwiesen wurde. Dies bedeutet, dass, wenn das Objekt Verweise enthält, die auf den Kontext verweisen, der Kontext (der auf so ziemlich alles andere verweist) ausläuft. Wenn Sie eine Ansicht übergeben, enthält die Ansicht einen Verweis auf den Kontext, in dem sie erstellt wurde. In ähnlicher Weise enthalten Ansichtsinhaber normalerweise eine Ansicht, und Cursor werden manchmal auch Ansichten zugeordnet.
Wir können benutzerdefinierte Objekte gemäß unseren Anforderungen verwenden setTag()
und getTag()
festlegen und abrufen. Die setTag()
Methode verwendet ein Argument vom Typ Object
und getTag()
gibt ein zurück Object
.
Zum Beispiel,
Person p = new Person();
p.setName("Ramkailash");
p.setId(2000001);
button1.setTag(p);
Dies ist sehr nützlich für die benutzerdefinierte ArrayAdapter
Verwendung. Es ist eine Art Optimierung. Es setTag
wird als Referenz auf ein Objekt verwendet, das auf einige Teile des Layouts (die in angezeigt werden ListView
) verweist, anstatt 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);
}
....................
}
Im Gegensatz zu IDs werden Tags nicht zum Identifizieren von Ansichten verwendet. Tags sind im Wesentlichen zusätzliche Informationen, die einer Ansicht zugeordnet werden können. Sie werden am häufigsten verwendet, um Daten zu Ansichten in den Ansichten selbst zu speichern, anstatt sie in einer separaten Struktur abzulegen.
Referenz: http://developer.android.com/reference/android/view/View.html
Das Festlegen von TAGs ist sehr nützlich, wenn Sie eine ListView haben und die Ansichten recyceln / wiederverwenden möchten. Auf diese Weise wird die ListView der neueren RecyclerView sehr ähnlich.
@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;
}