Eine ListView hat normalerweise zwei Verantwortlichkeiten.
(1) Geben Sie Daten in das Layout ein.
(2) Verarbeiten Sie die Auswahl- und Klickvorgänge des Benutzers.
Der erste Punkt ist leicht zu verstehen: ListView implementiert diese Funktion. Der zweite Punkt ist nicht schwer umzusetzen. Die Leser werden feststellen, dass er in den folgenden Studien sehr einfach ist.
Die Erstellung einer ListView erfordert 3 Elemente.
(1) Ansicht für jede Spalte in ListView.
(2) Geben Sie die Daten oder Bilder der Ansicht usw. ein.
(3) Adapter zur Verbindung von Daten und ListView.
Mit anderen Worten: Um ListView verwenden zu können, müssen Sie zunächst verstehen, was ein Adapter ist. Der Adapter ist eine Brücke, die Daten und AdapterView verbindet (ListView ist ein typischer AdapterView, und wir werden später mehr über andere erfahren). Er kann die Trennungseinstellung von Daten und AdapterView effektiv realisieren, wodurch die Bindung von AdapterView und Daten einfacher wird und Änderungen einfacher werden . Bequemlichkeit
Android bietet viele Adapter. Tabelle 4-5 listet einige häufig verwendete auf.
Tabelle 4-5 Häufig verwendete Adapter
Adapter
Bedeutung
ArrayAdapter
wird zum Binden eines Arrays verwendet und unterstützt generische Operationen
SimpleAdapter
wird verwendet, um Daten zu binden, die den in XML definierten Steuerelementen entsprechen
SimpleCursorAdapter
Wird zum Binden der vom Cursor erhaltenen Daten verwendet
BaseAdapter
Universeller Basisadapter
Eigentlich gibt es sie Viele Adapter Es ist zu beachten, dass verschiedene Adapter nur unterschiedliche Konvertierungsmethoden und -funktionen haben. Als nächstes werden wir verschiedene Adapter verwenden, um Daten an ListView zu binden (SimpleCursorAdapter wird vorerst nicht besprochen, wird aber später vorgestellt, wenn wir über SQLite sprechen).
4.12.1 ListView verwendet ArrayAdapter
ArrayAdapter kann verwendet werden, um eine einfache ListView-Datenbindung zu implementieren. Standardmäßig bindet ArrayAdapter den toString-Wert jedes Objekts an das vordefinierte TextView-Steuerelement im Layout. Die Verwendung von ArrayAdapter ist sehr einfach.
Beispiel:
Projektverzeichnis: EX_04_12
Fügen Sie der Layoutdatei ein ListView-Steuerelement hinzu.
android:layout_height="fill_parent"
publicclass MyListView erweitert Aktivität {
privatestaticfinal String[] strs = new String[] {
„first“, „second“, „dritte“, „vierte“, „fünfte“ };//Definieren Sie ein String-Array, um den Inhalt von ListView private ListView lv anzuzeigen;/**Wird aufgerufen, wenn die Aktivität zum ersten Mal erstellt wird.*/
@Override
publicvoid onCreate(Bundle savingInstanceState) {super.onCreate(savedInstanceState) ;
setContentView(R.layout.main);
lv = (ListView) findViewById(R.id.lv);//Eine Referenz auf das ListView-Objekt abrufen/*Einen Adapter für die ListView festlegen um Daten zu binden ***/ 🎜>
▲Abbildung 4-29 Der laufende Effekt von ListView mit ArrayAdapter
Der Code ist sehr einfach und der laufende Effekt ist in Abbildung dargestellt 4-29.
Analysieren Sie die verwendeten Schritte.
(2) Erstellen Sie ein ArrayAdapter-Objekt, indem Sie den Konstruktor von ArrayAdapter implementieren.
(3) Binden Sie ArrayAdapter über die setAdapter()-Methode von ListView.
Was im zweiten Schritt erwähnt werden muss, ist, dass ArrayAdapter über mehrere Konstruktoren verfügt und der im Beispiel implementierte der am häufigsten verwendete ist. Der erste Parameter ist der Kontext und der zweite Parameter ist eine Layout-Ressourcen-ID, die eine TextView enthält, die zum Füllen jeder Zeile der ListView verwendet wird. Der dritte Parameter ist der Inhalt von ListView. Mit dem zweiten Parameter kann ein Layout angepasst werden, dieses Layout muss jedoch über ein TextView-Steuerelement verfügen. Normalerweise verwenden wir die von Android bereitgestellten Ressourcen. Zusätzlich zu den in den Beispielen verwendeten Ressourcen werden häufig die folgenden zur Implementierung von ListView mit RadioButton und CheckBox verwendet.
(1) Implementieren Sie ListView mit Auswahlfeld, indem Sie die Ressource android.R.layout.simple_list_item_checked angeben. Sie müssen die Methode setChoiceMode () verwenden, um festzulegen, ob es sich um eine Mehrfachauswahl oder eine Einzelauswahl handelt. Andernfalls wird der Auswahleffekt nicht erzielt. Der Operationseffekt ist in Abbildung 4-30 dargestellt.
Der Implementierungscode lautet wie folgt:
lv.setAdapter(new ArrayAdapter
; ListView.CHOICE_MODE_MULTIPLE);
ListView.CHOICE_MODE_MULTIPLE);
(3 ) Implementieren Sie ListView mit RadioButton, indem Sie die Ressource android.R.layout.simple_list_item_single_choice angeben. Hierbei ist zu beachten, dass die Radioauswahl hier nicht spezifiziert ist. Ob es sich um eine Mehrfachauswahl oder eine Einzelauswahl handelt, muss über die Methode setChoiceMode() angegeben werden. Der Operationseffekt ist in Abbildung 4-32 dargestellt.
Der Implementierungscode lautet wie folgt:
lv.setAdapter(newArrayAdapter
android.R.layout.simple_list_item_single_choice, strs)) ;
lv.setChoiceMode(ListView.CHOICE_MODE_SINGLE);
▲ Abbildung 4-30 ListView mit Auswahlfeld ▲ Abbildung 4-31 ListView mit CheckBox ▲ Abbildung 4-32 ListView mit RadioButton
Wie bereits erwähnt, müssen die Aufgaben von ListView neben dem Ausfüllen von Daten auch die Benutzeroperationen abwickeln. . Mit dem folgenden Code können Sie einen Klick-Listener an ListView binden. Nach dem Klicken wird die Anzahl der angeklickten Zeilen in der Titelleiste angezeigt.
4.12.2 ListView verwendet SimpleAdapterlv.setOnItemClickListener(new OnItemClickListener() { @Override publicvoid onItemClick(AdapterView<?> arg0, View arg1, int arg2, long arg3) { //点击后在标题上显示点击了第几行 setTitle("你点击了第"+arg2+"行"); } });
Oft ist es notwendig, etwas anderes als Text in der Liste anzuzeigen, wie zum Beispiel Bilder usw. SimpleAdapter kann zu diesem Zeitpunkt verwendet werden. Auch die Verwendung von SimpleAdapter ist sehr einfach und seine Funktion ist ebenfalls sehr leistungsstark. Sie können damit den Inhalt von Elementen in ListView anpassen, z. B. Bilder, Mehrfachauswahlfelder usw. Sehen wir uns ein Beispiel für die Implementierung einer ListView mit einer ImageView und einer TextView für jede Zeile an. Schauen wir uns zunächst den Laufeffekt an, wie in Abbildung 4-34 dargestellt.
▲Abbildung 4-34 ListView mit Symbolen
Fügen Sie zunächst ein ListView-Steuerelement in der Layoutdatei hinzu.
Sie müssen außerdem ein Layout für jede Zeile in der ListView definieren und RelativeLayout verwenden, um ein Layout mit zwei Textzeilen und einem Bild zu implementieren.
item.xml:
publicclass MyListViewSimple erweitert Aktivität {
private ListView lv; /**Wird aufgerufen, wenn die Aktivität zum ersten Mal erstellt wird.*/ @Override
publicvoid onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);
setContentView(R.layout .main);
lv = (ListView) findViewById(R.id.lv);/*Dynamisches Array definieren*/
ArrayList
map.put("ItemImage", R.drawable.icon);//Bild hinzufügen map.put("ItemTitle", "row "+i+") ;
map.put("ItemText", "Dies ist die Zeile "+i+""
listItem.add(map) }
SimpleAdapter mSimpleAdapter = new er( This, listitem, // Die Daten, die gebunden werden müssen
r.Layout.item, // Das Layout jeder Zeile // Der Schlüssel der Datenquelle im dynamischen Array entspricht dem definierten Layout des spezifischen „
,"ItemTitle", "ItemText"},
newint[] {R.id.ItemImage,R.id.ItemTitle,R.id.ItemText}
);
Lv .setAdapter (msimpleadapter); // ist ein Listview-Bindungsadapter lv.SetonitemClicklistener (New
onItemClicklistener () {
@Override
PUBLICVOID Onitemclick (adapterview & lt;? & gt; arg0, view arg1, int arg2, lang arg3) {
settitle ("Sie haben auf die"+arg2+"Zeile") geklickt; // die Titelleiste festlegen, um die angeklickte Zeile 🎜>});
Die Daten, die simpleAdapter verwenden, sind im Allgemeinen eine Liste, die aus HashMap besteht, und jeder Abschnitt der Liste entspricht jeder Zeile von ListView. Über den Konstruktor von SimpleAdapter werden die Daten jedes Schlüssels der HashMap dem entsprechenden Steuerelement in der Layoutdatei zugeordnet. Diese Layoutdatei wird in der Regel von Ihnen selbst nach Ihren eigenen Bedürfnissen definiert. Lassen Sie uns die Schritte zur Verwendung von SimpleAdapter klären.
(1) Definieren Sie nach Bedarf das von jeder Zeile von ListView implementierte Layout.
(2) Definieren Sie eine aus HashMap bestehende Liste und speichern Sie darin Daten als Schlüssel-Wert-Paare.
(3) Konstruieren Sie ein SimpleAdapter-Objekt.
(4) LsitView an SimpleAdapter binden.
4.12.3 Optimierung von ListView mit BaseAdapter und ListView
Bei der Verwendung von ListView ist es manchmal notwendig, Schaltflächen und andere Steuerelemente hinzuzufügen, um separate Vorgänge zu erreichen. Mit anderen Worten: Diese ListView zeigt nicht mehr nur Daten an, und es ist auch nicht nur diese Zeile, die Benutzeroperationen verarbeitet, sondern die darin enthaltenen Steuerelemente müssen den Fokus des Benutzers erhalten. Leser können versuchen, mit SimpleAdapter eine Schaltfläche zum ListView-Element hinzuzufügen. Sie werden feststellen, dass sie hinzugefügt werden kann, aber nicht den Fokus erhalten kann und der Klickvorgang durch das ListView-Element abgedeckt wird. Die bequemste Möglichkeit ist derzeit die Verwendung des flexiblen Adapters BaseAdapter.
▲ Abbildung 4-35 Methoden in BaseAdapter Um BaseAdapter zu verwenden, müssen Sie eine Klasse schreiben, um sie zu erben. Gleichzeitig ist BaseAdapter ein abstrakte Klasse und muss implementiert werden, um ihre Methode zu erben. Die Flexibilität von BaseAdapter liegt darin, dass viele Methoden neu geschrieben werden müssen. Abbildung 4-35 zeigt die von SpeechListAdapter geerbten Methoden. Was bewirken diese Methoden? Wir geben den Lesern Antworten, indem wir die Prinzipien von ListView analysieren.当系统开始绘制ListView的时候,首先调用getCount()方法。得到它的返回值,即ListView的长度。然后系统调用getView()方法,根据这个长度逐一绘制ListView的每一行。也就是说,如果让getCount()返回1,那么只显示一行。而getItem()和getItemId()则在需要处理和取得Adapter中的数据时调用。那么getView如何使用呢?如果有10000行数据,就绘制10000次?这肯定会极大的消耗资源,导致ListView滑动非常的慢,那应该怎么做呢?通过一个例子来讲解如何在使用BaseAdapter的时候优化ListView的显示。例子中将上一节中的ImageView换成Button,并且处理Button的点击事件,其中对ListView的显示做了优化。
布局文件和上一例类同,读者可以在光盘的工程目录中查看,这里只给出Activity类。
publicclass MyListViewBase extends Activity { private ListView lv; /*定义一个动态数组*/ ArrayList<HashMap<String, Object>>listItem;/** Called when the activity is first created. */ @Override publicvoid onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState); setContentView(R.layout.main); lv = (ListView) findViewById(R.id.lv); MyAdapter mAdapter = new MyAdapter(this);//得到一个MyAdapter对象 lv.setAdapter(mAdapter);//为ListView绑定Adapter /*为ListView添加点击事件*/ lv.setOnItemClickListener(new OnItemClickListener() { @Override publicvoid onItemClick(AdapterView<?> arg0, View arg1, int arg2, long arg3) { Log.v("MyListViewBase", "你点击了ListView条目" + arg2);//在LogCat中输出信息 } }); }/*添加一个得到数据的方法,方便使用*/ private ArrayList<HashMap<String, Object>> getDate(){ ArrayList<HashMap<String, Object>> listItem = new ArrayList<HashMap<String, Object>>(); /*为动态数组添加数据*/ for(int i=0;i<30;i++) { HashMap<String, Object> map = new HashMap<String, Object>(); map.put("ItemTitle", "第"+i+"行"); map.put("ItemText", "这是第"+i+"行"); listItem.add(map); } return listItem; }/* * 新建一个类继承BaseAdapter,实现视图与数据的绑定 */ privateclass MyAdapter extends BaseAdapter { private LayoutInflater mInflater;//得到一个LayoutInfalter对象用来导入布局 /*构造函数*/ public MyAdapter(Context context) { this.mInflater = LayoutInflater.from(context); } @Override publicint getCount() { return getDate().size();//返回数组的长度 } @Override public Object getItem(int position) { returnnull; } @Override publiclong getItemId(int position) { return 0; } /*书中详细解释该方法*/ @Override public View getView(finalint position, View convertView, ViewGroup parent) { ViewHolder holder; //观察convertView随ListView滚动情况 Log.v("MyListViewBase", "getView " + position + " " + convertView); if (convertView == null) { convertView = mInflater.inflate(R.layout.item, null); holder = new ViewHolder(); /*得到各个控件的对象*/ holder.title = (TextView) convertView.findViewById(R.id.ItemTitle); holder.text = (TextView) convertView.findViewById(R.id.ItemText); holder.bt = (Button) convertView.findViewById(R.id.ItemButton); convertView.setTag(holder);//绑定ViewHolder对象 } else{ holder = (ViewHolder)convertView.getTag();//取出ViewHolder对象 } /*设置TextView显示的内容,即我们存放在动态数组中的数据*/ holder.title.setText(getDate().get(position).get("ItemTitle").toString()); holder.text.setText(getDate().get(position).get("ItemText").toString()); /*为Button添加点击事件*/ holder.bt.setOnClickListener(new OnClickListener() { @Override publicvoid onClick(View v) { Log.v("MyListViewBase", "你点击了按钮" + position); //打印Button的点击信息 } }); return convertView; } }/*存放控件*/ publicfinalclass ViewHolder{ public TextView title; public TextView text; public Button bt; } }
运行效果如图4-36所示。还需要注意的是,Button会抢夺ListView的焦点,需要将Button设置为没有焦点。设置非常简单,只需要在xml的Button标签下加入一行:android:focusable=“false”代码就可以了。在LogCat观察点击后输出的信息,如图4-37所示。
▲图4-36 Listenansicht und Adapternutzung
▲图4-37 Listenansicht und Adapternutzung
代码中getView()方法不容易理解。其实完全可以不用所谓的convertView和ViewHolder,直接导入布局并且设置控件显示的内容就可以了。但是这意味着有多少行数据就需要绘制多少行ListView,这显然是不可取的。这里采用了一种优化的方法。代码中,在getView()方法中加入了一行log输出convertView的内容。滚动ListView,输出信息如图4-38所示。
从图4-38中可以看出,当启动Activity呈现第一屏ListView的时候,convertView为零。当用户向下滚动ListView时,上面的条目变为不可见,下面出现新的条目。这时候convertView不再为空,而是创建了一系列的convertView的值。当又往下滚一屏的时候,发现第11行的容器用来容纳第22行,第12行的容器用来容纳第23行。也就是说convertView相当于一个缓存,开始为0,当有条目变为不可见,它缓存了它的数据,后面再出来的条目只需要更新数据就可以了,这样大大节省了系统资料的开销。
还可以继续优化。虽然重复利用了已经绘制的view,但是要得到其中的控件,需要在控件的容器中通过findViewById的方法来获得。如果这个容器非常复杂,这显然会增加系统资源的开销。在上面的例子中,引入了Tag的概念。或许不是最好的办法,但是它确实能使ListView变得更流畅。代码中,当convertView为空时,用setTag()方法为每个View绑定一个存放控件的ViewHolder对象。当convertView不为空,重复利用已经创建的view的时候,使用getTag()方法获取绑定的ViewHolder对象,这样就避免了findViewById对控件的层层查询,而是快速定位到控件。
▲图4-38 Listenansicht und Adapternutzung
总结一下,这节介绍了用BaseAdapter来绑定ListView的数据。因为BaseAdapter非常灵活,使用也相对较其他控件麻烦。同时ListView的优化问题也值得读者去研究,一个流畅的ListView会带来更好的用户体验。