- ScrollView:只能用于控件比较少的界面,如果数据有上千上万条,那么使用ScrollView就不好了,因为ScrollView就把所有的控件进行初始化,这是非常消耗性能的操作,所以android就设计了一个类ListView来专门处理列表数据条目的显示。
- ListView:处理条目比较多,并且每个条目都非常相似的场景。就是一个条目控件,会自动回收没有在屏幕上显示的控件,来优化性能。
对于ListView和BaseAdapter
1简单的用法
MainActivity.java
package com.example.listview; import android.os.Bundle; import android.app.Activity; import android.util.Log; import android.view.Menu; import android.view.View; import android.view.ViewGroup; import android.widget.BaseAdapter; import android.widget.ListView; import android.widget.TextView; public class MainActivity extends Activity { protected static final String TAG = "MainActivity"; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); //找到ListView ListView lv = (ListView) findViewById(R.id.lv); //给ListView设置数据(设置适配器 基本适配器) lv.setAdapter(new BaseAdapter() { //加工ListView需要的条目 int position 条目的下标 @Override public View getView(int position, View convertView, ViewGroup parent) { Log.i(TAG, "position:"+position); TextView tv = new TextView(MainActivity.this); tv.setText("人生自古谁没有年轻的时候"+position); tv.setTextSize(20); return tv; } @Override public long getItemId(int position) { return 0; } @Override public Object getItem(int position) { return null; } //控制条目的数量 @Override public int getCount() { return 100; } }); } }
activity_main.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" tools:context=".MainActivity" > <ListView android:id="@+id/lv" android:layout_width="match_parent" android:layout_height="match_parent"> </ListView> </LinearLayout>
上图就是ListView控件的基本图像
2复杂ListView的用法
首先要创建一个ListView和一个条目上的内容
activity_main.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".MainActivity" > <ListView android:layout_height="match_parent" android:layout_width="match_parent" android:id="@+id/lv"> </ListView> </RelativeLayout>
item.xml
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content" > <ImageView android:id="@+id/iv" android:layout_width="wrap_content" android:layout_height="wrap_content" android:src="@drawable/ic_launcher" android:layout_centerVertical="true" android:layout_marginRight="10dp"/> <TextView android:id="@+id/tv_name" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_toRightOf="@id/iv" android:layout_marginTop="10dp" android:textSize="22sp" android:text="姓名"/> <TextView android:id="@+id/tv_age" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_toRightOf="@id/iv" android:layout_below="@id/tv_name" android:textSize="16sp" android:text="年龄"/> </RelativeLayout>
布局填充器layoutinflate:可以把res/layout下面的资源加载到内存,即可以把xml布局变成Java对象。一般就是加载item.xml上的东西
MainActivity.java
package com.example.listiview; import java.util.ArrayList; import java.util.List; import android.app.Activity; import android.content.Context; import android.os.Bundle; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.BaseAdapter; import android.widget.ListView; import android.widget.TextView; import cn.itcast.wh08.lv.domain.Teacher; public class MainActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); ListView lv = (ListView) findViewById(R.id.lv); //模拟对象集合的数据 一般数据都是来自于网络,或者数据库 List<Teacher> data = new ArrayList<Teacher>(); for(int i = 0;i<100;i++){ data.add(new Teacher(i, "隔壁老王"+i, i+20)); } //适配器 MyAdapter adapter = new MyAdapter(data, this); //设置适配器 lv.setAdapter(adapter); } //适配器 private class MyAdapter extends BaseAdapter{ private List<Teacher> data; private Context context; private LayoutInflater mInflater; public MyAdapter(List<Teacher> data, Context context) { super(); this.data = data; this.context = context; //获取布局加载器 mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); } @Override public int getCount() { return data.size(); } //返回条目指定位置的数据 @Override public Object getItem(int position) { return data.get(position); } @Override public long getItemId(int position) { return 0; } //加工条目 @Override public View getView(int position, View convertView, ViewGroup parent) { //使用布局加载器加载布局 View view = mInflater.inflate(R.layout.item, null); //找到条目对应的控件 TextView tv_name = (TextView) view.findViewById(R.id.tv_name); TextView tv_age = (TextView) view.findViewById(R.id.tv_age); //获取条目对应的数据 Teacher info = data.get(position); //把数据绑定给控件 tv_name.setText(info.name); tv_age.setText(info.age+""); return view; } } }
Teacher.java
package com.example.listview.vo; public class Teacher { public int _id; public String _name; public int age; public Teacher(int _id, String _name, int age) { super(); this._id = _id; this._name = _name; this.age = age; } public Teacher() { super(); } }
3.与数据库结合来显示
- mode 数据模型(数据) :要被显示到ListView上的数据集合
- view 视图(展示数据) : ListView
- controller控制层(把数据展示到空间上) : 适配器Adapter
我们还是要先建立ListView控件和item控件
activity_main.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" tools:context=".MainActivity" > <TextView android:layout_width="fill_parent" android:layout_height="wrap_content" android:gravity="center" android:paddingBottom="5dp" android:paddingTop="5dp" android:text="闺蜜列表" android:textSize="22sp" /> <ListView android:id="@+id/lv" android:layout_width="fill_parent" android:layout_height="0dp" android:layout_weight="1" /> - <LinearLayout android:layout_width="fill_parent" android:layout_height="wrap_content" android:orientation="horizontal" > <Button android:id="@+id/bt_pre" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" android:enabled="false" android:text="上一页" /> <Button android:id="@+id/bt_next" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" android:text="下一页" /> </LinearLayout> </LinearLayout>
item.xml
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" > <ImageView android:id="@+id/iv_head" android:layout_width="wrap_content" android:layout_height="wrap_content" android:src="@drawable/ic_launcher" /> <TextView android:id="@+id/tv_name" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="10dp" android:layout_toRightOf="@id/iv_head" android:text="老师" /> <TextView android:id="@+id/tv_phone" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_below="@id/tv_name" android:layout_toRightOf="@id/iv_head" android:text="13787009878" /> </RelativeLayout>
先建立一个数据库,为了得到数据。
MySqliteOpenHelper.java
package com.example.lisview.db; import android.content.ContentValues; import android.content.Context; import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteDatabase.CursorFactory; import android.database.sqlite.SQLiteOpenHelper; public class MySqliteOpenHelper extends SQLiteOpenHelper { private static SQLiteOpenHelper mInstance; public static synchronized SQLiteOpenHelper getInstance(Context context) { if (mInstance == null) { mInstance = new MySqliteOpenHelper(context, "itcast.db", null, 1); } return mInstance; } public MySqliteOpenHelper(Context context, String name, CursorFactory factory, int version) { super(context, name, factory, version); // TODO Auto-generated constructor stub } @Override public void onCreate(SQLiteDatabase db) { // 设计一个表 db.execSQL("create table friends(_id integer primary key autoincrement," + "name text," + "phone text)"); // 初始化表数据 ContentValues values = new ContentValues(); for (int i = 0; i < 100; i++) { values.clear(); values.put("name", "老师" + i); values.put("phone", "13787990" + i); db.insert("friends", null, values); } } @Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { // TODO Auto-generated method stub } }
Friend.java
package com.example.lisview.vo; public class Friend { public int _id; public String name; public String phone; public Friend(int _id, String name, String phone) { super(); this._id = _id; this.name = name; this.phone = phone; } public Friend() { // TODO Auto-generated constructor stub } }
对数据库的增、删、查、改
FriendDao.java
package com.example.lisview.dao; import java.util.ArrayList; import java.util.List; import android.content.Context; import android.database.Cursor; import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteOpenHelper; import com.example.lisview.db.MySqliteOpenHelper; import com.example.lisview.vo.Friend; public class FriendDao { private Context context; private SQLiteOpenHelper helper; public FriendDao(Context context) { this.context = context; helper = MySqliteOpenHelper.getInstance(context); } /** * 获取数据的总条目 * @return */ public int queryAllSize(){ int size = 0; SQLiteDatabase db = helper.getReadableDatabase(); if(db.isOpen()){ Cursor cursor = db.query("friends", new String[]{"*"}, null, null, null, null, null); size = cursor.getCount();//获取Cursor的大小 cursor.close(); db.close(); } return size; } /** * 分页查询的 * * @param startIndex * 查询的开始下标 * @param block * 每次查询的数据量 * @return */ public List<Friend> queryFriendsLimit(int startIndex, int block) { List<Friend> infos = new ArrayList<Friend>(); SQLiteDatabase db = helper.getReadableDatabase(); if (db.isOpen()) { Cursor cursor = db.query("friends", new String[] { "*" }, null, null, null, null, null, startIndex + "," + block); while (cursor.moveToNext()) { int _id = cursor.getInt(0); String name = cursor.getString(1); String phone = cursor.getString(2); infos.add(new Friend(_id, name, phone)); } cursor.close(); db.close(); } return infos; } }
MyAdapter.java
package com.example.lisview.service; import java.util.List; import android.content.Context; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.BaseAdapter; import android.widget.TextView; import com.example.lisview.R; import com.example.lisview.vo.Friend; public class MyAdapter extends BaseAdapter { private List<Friend> infos; private LayoutInflater mInflater; public void setInfos(List<Friend> infos) { this.infos = infos; } public MyAdapter(List<Friend> infos, Context context) { super(); this.infos = infos; // 布局加载器 mInflater = LayoutInflater.from(context); } // 返回条目的总数 @Override public int getCount() { return infos.size(); } // 得到item.xml代表的对象 @Override public Object getItem(int position) { return infos.get(position); } // 得到Item的id,不过在这里貌似没有用 @Override public long getItemId(int position) { return position; } // 得到Item的视图 @Override public View getView(int position, View convertView, ViewGroup parent) { View view = mInflater.inflate(R.layout.item, null); TextView tv_name = (TextView) view.findViewById(R.id.tv_name); TextView tv_phone = (TextView) view.findViewById(R.id.tv_phone); Friend info = infos.get(position); tv_name.setText(info.name); tv_phone.setText(info.phone); return view; } }
MainActivity.java
package com.example.lisview; import java.util.List; import android.app.Activity; import android.app.AlertDialog; import android.content.DialogInterface; import android.content.Intent; import android.net.Uri; import android.os.Bundle; import android.view.View; import android.view.View.OnClickListener; import android.widget.AdapterView; import android.widget.AdapterView.OnItemClickListener; import android.widget.Button; import android.widget.ListView; import com.example.lisview.dao.FriendDao; import com.example.lisview.service.MyAdapter; import com.example.lisview.vo.Friend; public class MainActivity extends Activity { private ListView lv; private Button bt_pre; private Button bt_next; private FriendDao friendDao; private int block = 10;// 每一页获取10条数据 private int startIndex = 0;// 获取数据的下标 private MyAdapter adapter; private int size; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); initView(); } private void initView() { lv = (ListView) findViewById(R.id.lv); bt_pre = (Button) findViewById(R.id.bt_pre); bt_next = (Button) findViewById(R.id.bt_next); MyOnClickListener l = new MyOnClickListener(); bt_pre.setOnClickListener(l); bt_next.setOnClickListener(l); friendDao = new FriendDao(this); size = friendDao.queryAllSize(); // 查询第一页数据 List<Friend> infos = friendDao.queryFriendsLimit(0, block); adapter = new MyAdapter(infos, this); lv.setAdapter(adapter); // 设置条目点击事件 lv.setOnItemClickListener(new MyOnItemClickListener()); } private class MyOnItemClickListener implements OnItemClickListener { @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { //获取条目的数据 final Friend info = (Friend) adapter.getItem(position); //弹出对话框 new AlertDialog.Builder(MainActivity.this) .setTitle(info.name) .setMessage("请选择操作") .setPositiveButton("打电话", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { //打电话需要拨号权限 Intent intent = new Intent(); intent.setAction(Intent.ACTION_CALL); intent.setData(Uri.parse("tel:"+info.phone)); startActivity(intent); } }) .setNegativeButton("发短信", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { //TODO:学员自己处理 } }) .show(); } } private class MyOnClickListener implements OnClickListener { @Override public void onClick(View v) { List<Friend> infos = null; switch (v.getId()) { case R.id.bt_pre: startIndex = startIndex - block; if (startIndex == 0) { bt_pre.setEnabled(false); } else { bt_pre.setEnabled(true); } bt_next.setEnabled(true); infos = friendDao.queryFriendsLimit(startIndex, block); adapter.setInfos(infos);// 把查询的数据设置给适配器 // 刷新界面 adapter.notifyDataSetChanged(); break; case R.id.bt_next: startIndex = startIndex + block; // 判断是否是最后页面的数据 // 现在页面的数据 startIndex=startIndex+block if ((startIndex + block) >= size) { // 已经是最后一页数据 bt_next.setEnabled(false); } else { bt_next.setEnabled(true); } bt_pre.setEnabled(true); infos = friendDao.queryFriendsLimit(startIndex, block); adapter.setInfos(infos);// 把查询的数据设置给适配器 // 刷新界面 adapter.notifyDataSetChanged(); break; default: break; } } } }