這次我們來介紹一下ListView控件以及常用資料擴充卡Adapter的使用,并通過一個商品展示案例來說明。
一.ListView控件
在Android開發中ListView是一個比較常用的控件。它以清單的形式展示具體資料内容,并且能夠根據資料的長度自适應螢幕顯示。接下來介紹一下ListView的常見屬性。
ListView常見屬性:
1.android:cacheColorHint——設定拖動的背景色
2.android:divider——設定分隔線
3.android:dividerHeight——設定分隔線的高度
4.android:listSelector——設定ListView item選中時的顔色
5.android:scrollbars——設定ListView的滾動條
6.android:dadeScrollbars——設定為true就可以實作滾動條的自動隐藏和顯示
ListView是一個清單視圖,由很多Item(條目)組成,每個Item的布局都是一樣的。需要注意的是,在布局檔案中需要指定ListView的id。同時,如果不對ListView進行資料适配,那麼就無法在界面上看到布局檔案中建立的ListView。
二.Adapter
上面提到在使用ListView時需要對其進行資料适配。為了實作這個功能,Android系統提供一系列的擴充卡(Adapter)對ListView進行資料适配。可以将擴充卡了解為界面資料綁定。接下來介紹幾種常用的Adapter。
1.BaseAdapter
BaseApdater顧名思義即基本的擴充卡。它實際上就是一個抽象類。在Android開發中,就是根據這幾個抽象方法來對ListView進行資料适配的。BaseAdapter的四個抽象方法的功能如下所示:
public int getCount()--------得到Item的總數
public Object getItem(int position)--------根據position得到某個Item的對象
public long getItemId(int position)--------根據position得到某個Item的id
public View getView(int position,View convertView,ViewGroup parent)--------得到相應的Item視圖,position目前Item的位置,convertView複用的View對象
這四個抽象方法分别用于設定Item的總數、擷取Item對象、擷取Item id、得到Item視圖。開發者在适配資料到ListView時,需要建立一個類內建BaseAdapter并重寫這四個抽象方法。
2.SimpleAdapter
SimpleAdapter繼承自BaseAdapter,實作了BaseAdapter的四個抽象方法。分别是getCount()、getItem()、getItemId()、getView()方法。是以,開發者隻需要在建立SimpleAdapter執行個體時,在構造方法裡傳入相應的參數即可。SimpleAdapter的構造方法如下:
public SimpleAdapter(Context context,List<? extends Map<String,?>>data,int resource,String[] from,int[] to);
上述構造方法中有多個參數:
a. Context context:Context對象,getView()方法中更需要用到Context将布局轉換成View對象。
b. int resource:Item布局的資源id。
c. String[] from:Map集合裡面的key。
d.int[] to:Item布局對應的控件id。
需要注意的是,SimpleAdapter隻能适配Checkable、TextView、ImageView,其中Checkable是一個接口,CheckBox控件就實作了該接口。TextView适用于顯示文本的控件,ImageView是用來顯示圖檔的控件。int[] to所代表的控件不是這三中類型則會報IllegalStateException。
3.ArrayAdapter
ArrayAdapter也是BaseAdapter的子類,與SimpleAdapter相同,ArrayAdapter也不是抽象類,并且用法與SimpleAdapter類似,開發者隻需要在構造方法裡傳入相應參數即可适配資料。ArrayAdapter通常用于适配TextView控件,例如Android系統中的Setting(設定菜單)。
ArrayAdapter的構造方法如下:
public ArrayAdapter(Context context,int resourse,inttextViewResourceId,T[]objects);
上述構造方法同樣有多個參數:
a. Context context:Context對象。
b. int resource:Item布局的資源id。
c. int textViewResourceId:Item布局相應的控件TextView的id。
d. T[] objects:需要适配的資料數組。
OK,接下來我們通過一個案例來了解ListView控件以及Adapter的使用。
下面為詳細步驟及代碼:
1.建立一個程式,設計使用者互動界面。
代碼:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/activity_main"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:layout_margin="8dp"
tools:context="com.example.productshow.MainActivity">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/addLL"
android:orientation="horizontal">
<EditText
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:id="@+id/nameET"
android:hint="商品名稱"
android:inputType="textPersonName"/>
<EditText
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:id="@+id/balanceET"
android:hint="金額"
android:inputType="number"/>
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/addIV"
android:onClick="add"
android:src="@android:drawable/ic_input_add"
/>
</LinearLayout>
<ListView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/accountLV"
android:layout_below="@id/addLL">
</ListView>
</LinearLayout>
上述代碼中用ImageView顯示圖檔。其中使用到了ImageView的屬性Android:src來指定ImageView要顯示的圖檔,但是隻會顯示圖檔原圖大小。如果使用Android:background屬性,圖檔的大小會根據ImageView的大小進行拉伸。
2.建立ListView Item布局
由于本案例用到了ListView布局,是以需要編寫一個ListView Item的布局。在res/layout目錄下建立一個item.xml檔案,效果如下:
代碼:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="10dp">
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:id="@+id/idTv"
android:text="13"
android:textColor="#000000"
android:textSize="20sp"/>
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="2"
android:id="@+id/nameTv"
android:singleLine="true"
android:text="PQ"
/>
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="2"
android:id="@+id/balanceTV"
android:singleLine="true"
android:text="12345"
android:textColor="#000000"
android:textSize="20sp"/>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical">
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/upTv"
android:src="@android:drawable/arrow_up_float"/>
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/downTv"
android:src="@android:drawable/arrow_down_float"/>
</LinearLayout>
<ImageView
android:layout_width="25dp"
android:layout_height="25dp"
android:id="@+id/deleteTV"
android:src="@android:drawable/ic_menu_delete"/>
</LinearLayout>
上面代碼添加了三個TextView,分别用于顯示資料庫中的某條資料的id、商品名稱、金額,三個ImageView用于增加金額、減少金額、删除資料。
3.建立資料庫
建立資料庫屬于資料操作,在包下建立一個名為dao的 包,并在該包下定義一個MyHelper類繼承自SQLiteOpenHelper,代碼如下:
package com.example.productshow.dao;
import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.provider.Settings;
public class MyHelper extends SQLiteOpenHelper {
public MyHelper(Context context){
super(context,"itcase.db",null,);
}
public void onCreate(SQLiteDatabase db){
System.out.println("onCreate");
db.execSQL("CREATE TABLE account(_id INTEGER PRIMARY KEY AUTOINCREMENT,name VARCHAR(20),balance INTEGER)");
}
public void onUpgrade(SQLiteDatabase db,int oldVersion,int newVersion){
System.out.println("onUpgrade");
}
}
4.建立Account類
在操作資料庫時将資料存放至一個JavaBean對象中操作起來會比較友善。是以,需要在包下建立一個名為bean的包用于存放Javabean類,然後再包下定義一個類Account,代碼如下:
package com.example.productshow.bean;
public class Account {
private Long id;
private String name;
private Integer balance;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getBalance() {
return balance;
}
public void setBalance(Integer balance) {
this.balance = balance;
}
public Account(Long id,String name,Integer balance){
super();
this.id=id;
this.name=name;
this.balance=balance;
}
public Account(String name, Integer balance) {
super();
this.name = name;
this.balance = balance;
}
public Account() {
super();
}
public String toString() {
return "[序号:" + id + ",商品名稱:" + name + ",餘額:" + balance + "]";
}
}
5.建立資料操作邏輯類
前面建立了資料庫和JavaBean,接下來需要編寫資料邏輯操作類,在包下建立一個AccountDao類用于操作資料,代碼如下:
package com.example.productshow;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import com.example.productshow.bean.Account;
import com.example.productshow.dao.MyHelper;
import java.util.ArrayList;
import java.util.List;
public class AccountDao {
private MyHelper helper;
public AccountDao(Context context){
helper=new MyHelper(context);
}
public void insert(Account account){
SQLiteDatabase db=helper.getWritableDatabase();
ContentValues values=new ContentValues();
values.put("name",account.getName());
values.put("balance",account.getBalance());
long id=db.insert("account",null,values);
account.setId(id);
db.close();
}
public int delete(long id){
SQLiteDatabase db=helper.getWritableDatabase();
int count=db.delete("account","_id=?",new String[] {id+""});
db.close();
return count;
}
public int update(Account account){
SQLiteDatabase db=helper.getWritableDatabase();
ContentValues values=new ContentValues();
values.put("name",account.getName());
values.put("balance",account.getBalance());
int count=db.update("account",values,"_id=?",new String[] {account.getId()+""});
db.close();
return count;
}
public List<Account> queryAll(){
SQLiteDatabase db=helper.getReadableDatabase();
Cursor c=db.query("account",null,null,null,null,null,"balance DESC");
List<Account> list=new ArrayList<Account>();
while(c.moveToNext()){
long id=c.getLong(c.getColumnIndex("_id"));
String name=c.getString();
int balance=c.getInt();
list.add(new Account(id,name,balance));
}
c.close();
db.close();
return list;
}
}
上述代碼是操作資料庫的,該類建立了對資料進行增删改查的方法。
6.編寫界面互動代碼
資料庫的操作完成之後需要界面與資料庫進行互動用于實作将資料庫中的資料以ListView的形式展示在界面上,代碼如下:
package com.example.productshow;
import android.content.DialogInterface;
import android.support.v7.app.AlertDialog;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.BaseAdapter;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;
import com.example.productshow.bean.Account;
import java.util.List;
import java.util.Objects;
public class MainActivity extends AppCompatActivity {
//需要适配的資料集合
private List<Account> list;
//資料庫增删改查操作類
private AccountDao dao;
//輸入姓名的EditText
private EditText nameET;
//輸入金額的EditText
private EditText balanceET;
//擴充卡
private MyAdapter adapter;
private ListView accountLV;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//初始化控件
initView();
dao=new AccountDao(this);
//從資料庫查詢出所有資料
list=dao.queryAll();
adapter=new MyAdapter();
accountLV.setAdapter(adapter);
}
//初始化控件
private void initView(){
accountLV=(ListView)findViewById(R.id.accountLV);
nameET=(EditText) findViewById(R.id.nameET);
balanceET=(EditText) findViewById(R.id.balanceET);
//添加監聽器,監聽條目點選事件
accountLV.setOnItemClickListener(new MyOnItemClickListener());
}
//activity_main.xml對應ImageView的點選事件觸發的方法
public void add(View v){
String name=nameET.getText().toString().trim();
String balance=balanceET.getText().toString().trim();
//三目運算balance.equals("")則等于0
//如果balance不是空字元串則進行類型轉換
Account a=new Account(name,balance.equals("")?:Integer.parseInt(balance));
dao.insert(a); //插入資料庫
list.add(a); //插入集合
adapter.notifyDataSetChanged(); //重新整理界面
//選中最後一個
accountLV.setSelection(accountLV.getCount()-);
nameET.setText("");
balanceET.setText("");
}
private class MyAdapter extends BaseAdapter{
public int getCount(){
return list.size(); //擷取條目總數
}
public Object getItem(int position){
return list.get(position); //根據位置擷取對象
}
public long getItemId(int position){
return position; //根據位置擷取id
}
//擷取一個條目視圖
public View getView(int position, View convertView, ViewGroup parent){
//重用convertView
View item=convertView!=null?convertView:View.inflate(getApplicationContext(),R.layout.item,null);
//擷取視圖中的TextView
TextView idTV=(TextView) item.findViewById(R.id.idTv);
TextView nameTV=(TextView) item.findViewById(R.id.nameTv);
TextView balanceTV=(TextView) item.findViewById(R.id.balanceTV);
//根據目前位置擷取Account對象
final Account a=list.get(position);
//把Account對象中的Account資料放到TextView中
idTV.setText(a.getId()+"");
nameTV.setText(a.getName());
balanceTV.setText(a.getBalance()+"");
ImageView upIV=(ImageView) item.findViewById(R.id.upTv);
ImageView downIV=(ImageView) item.findViewById(R.id.downTv);
ImageView deleteIV=(ImageView) item.findViewById(R.id.deleteTV);
//向上箭頭的點選事件觸發的方法
upIV.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
a.setBalance(a.getBalance()+); //修改值
notifyDataSetChanged(); //重新整理界面
dao.update(a); //更新資料庫
}
});
//向下箭頭的點選事件觸發的方法
downIV.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
a.setBalance(a.getBalance()-);
notifyDataSetChanged();
dao.update(a);
}
});
//删除圖檔的點選事件觸發的方法
deleteIV.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//删除資料之前首先彈出一個對話框
android.content.DialogInterface.OnClickListener listener=new android.content.DialogInterface.OnClickListener(){
public void onClick(DialogInterface dialog,int which){
list.remove(a); //從集合中删除
dao.delete(a.getId()); //從資料庫中删除
notifyDataSetChanged(); //重新整理界面
}
};
AlertDialog.Builder builder=new AlertDialog.Builder(MainActivity.this);
builder.setTitle("确定要删除嗎?");
//設定确定按鈕的文本以及監聽器
builder.setPositiveButton("确定",listener);
builder.setNegativeButton("取消",null);
builder.show();
}
});
return item;
}
}
//ListView的Item點選事件
private class MyOnItemClickListener implements AdapterView.OnItemClickListener{
public void onItemClick(AdapterView<?> parent,View view,int position,long id){
//擷取點選位置上的資料
Account a=(Account) parent.getItemAtPosition(position);
Toast.makeText(getApplicationContext(),a.toString(),Toast.LENGTH_SHORT).show();
}
}
}
因為這個地方比較麻煩,是以我加了一些必要的注釋,并且總結了上述代碼裡的知識點:
a. ListView的setOnItemClickListener()方法:該方法用于監聽Item的點選事件,在使用該方法時需要傳入一個OnItemClickListener的實作類對象,并且需要實作onItemClick方法。當點選ListView的Item時就會觸發Item的點選事件然後會回調onItemClick()方法。
b. ListView的setSelection()方法:該方法的作用是設定目前選中的條目。假設目前螢幕一屏隻能顯示10條資料,當添加第11條資料時,調用次方法就會将第11條資料顯示咋螢幕上,将第1條資料畫出螢幕外。
c. Adapter的notifyDataSetChange()方法:該方法是用于重新資料,當資料擴充卡中的内容發生變化時,會調用次方法,重新執行BaseAdapter中的getView()方法。
7.運作程式展示商品
運作之後界面如下:
然後輸入名稱和金額點選那個小加号,效果如下:
然後多加幾條資料,并進行删除操作,如下: