Loading

Android控件开发——ListView

上篇博客解决了Android客户端通过WebService与服务器端程序进行交互的问题,这篇博客重点关注两个问题,一个是Android应用程序如何与本机文件型数据库SQLite进行交互,另一问题则是如何在ListView中按照我们想要的界面效果进行展示。限于篇幅这篇重点讲ListView,下篇博客重点阐述SQLite。

ListView是一个常用的数据显示控件,假设我们要做一个简单的界面,如图所示。

这张图是我直接从Android平板电脑(Android 4.2.2)上面截图下来的,就是一个普通的列表,能够点击报名按钮获取到对应行的信息。

这里面显示的数据是我从SQLite数据库中查询出来的,封装的类的代码如下:

public class MyDatabaseHelper extends SQLiteOpenHelper {
 
    private static final String name = "mydb.db";// SQLite数据库文件名
    private static final int version = 1;// SQLite数据库版本号
 
    public MyDatabaseHelper(Context context) {
        super(context, name, null, version);
    }
 
    @SuppressLint("SimpleDateFormat")
    @Override
    public void onCreate(SQLiteDatabase db) {
        try {
            // 开启事务
            db.beginTransaction();
            String sql = "create table jobInfo (name varchar(20),"
                    + "num integer," + "date varchar(10),"
                    + "description text)";
            db.execSQL(sql);
 
            //测试插入10条数据
            for (int i = 0; i < 10; i++) {
                db.execSQL(
                        "insert into jobInfo(name,num,date,description)values(?,?,?,?)",
                        new Object[] {
                                "name" + i,
                                i,
                                new SimpleDateFormat("yyyy-MM-dd")
                                        .format(new Date()), "description" + i });
            }
 
            // 标识事务成功
            db.setTransactionSuccessful();
        } finally {
            // 结束事务
            db.endTransaction();
        }
    }
 
    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
        //数据库升级操作
    }
}

在需要创建数据库、插入数据的地方都可以实例化MyDatabaseHelper这个类,关于更多的SQLite的细节下篇博客将会进行详细的说明。

 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"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin" >
 
    <LinearLayout
        android:id="@+id/head"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal" >
 
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="岗位名称"
            android:textSize="24sp"
            android:width="150dip" />
 
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="岗位数量"
            android:textSize="24sp"
            android:width="150dip" />
 
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="发布日期"
            android:textSize="24sp"
            android:width="150dip" />
 
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="岗位描述"
            android:textSize="24sp"
            android:width="550dip" />
    </LinearLayout>
 
    <ListView
        android:id="@id/android:list"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_below="@+id/head" >
    </ListView>
 
</RelativeLayout>

可以看到这是一个相对布局,里面有一个线性布局,线性布局里面又放置了4个TextView作为ListView数据的标题。下面直接是一个ListView控件,由于这是相对布局,为了让ListView显示在“表头”下面,我们设置了layout_below属性。此外要注意ListView的id的写法。

 

接着按照界面的要求,我们准备一下ListView加载布局文件的内容,我们起名为:list_item.xml。

list_item.xml:

 

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="horizontal" >
 
    <TextView
        android:id="@+id/name"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textSize="24sp"
        android:width="150dip" />
 
    <TextView
        android:id="@+id/num"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textSize="24sp"
        android:width="150dip" />
 
    <TextView
        android:id="@+id/date"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textSize="24sp"
        android:width="150dip" />
 
    <TextView
        android:id="@+id/description"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textSize="24sp"
        android:width="550dip" />
 
    <Button
        android:id="@+id/btn"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:focusable="false"
        android:focusableInTouchMode="false"
        android:text="报名"
        android:width="150dip"
        android:textSize="24sp" />
 
</LinearLayout>

这也是一个普通的线性布局,设置orientation为horizontal(水平)。

 

布局文件准备好,下面我们准备写代码了。

我们让MainActivity这个类继承自ListActivity,完整的代码如下:

public class MainActivity extends ListActivity {
 
    List<Map<String, Object>> list;
 
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
 
        list = new ArrayList<Map<String, Object>>();
        //初始化SQLite数据库操作类对象
        MyDatabaseHelper dbHelper = new MyDatabaseHelper(MainActivity.this);
        
        //查询数据库返回Cursor(游标)对象
        Cursor cursor = dbHelper.getReadableDatabase().query("jobInfo",
                new String[] { "name", "num", "date", "description" }, null,
                null, null, null, "name");
        
        //将结果集封装到List<Map<String,Object>>数据结构当中
        while (cursor.moveToNext()) {
            Map<String, Object> map = new HashMap<String, Object>();
            map.put("name", cursor.getString(0));
            map.put("num", cursor.getInt(1));
            map.put("date", cursor.getString(2));
            map.put("description", cursor.getString(3));
            map.put("btn", R.drawable.ic_launcher);
            list.add(map);
        }
        //查询完毕,记得及时关闭数据库链接
        cursor.close();
        MyButtonAdapter adapter = new MyButtonAdapter(MainActivity.this, list,
                R.layout.list_item, new String[] { "name", "num", "date",
                        "description", "btn" }, new int[] { R.id.name,
                        R.id.num, R.id.date, R.id.description, R.id.btn });
 
        //给ListView设置数据填充适配器
        ListView listView = (ListView) findViewById(android.R.id.list);
        listView.setAdapter(adapter);
    }
 
    @Override
    protected void onListItemClick(ListView l, View v, int position, long id) {
        //ListView的
        @SuppressWarnings("unchecked")
        Map<String, Object> map = (HashMap<String, Object>) l
                .getItemAtPosition(position);
        Toast.makeText(MainActivity.this,
                "您点击了:" + map.get("name").toString() + "岗位!",
                Toast.LENGTH_SHORT).show();
    }
    
    public class MyButtonAdapter extends BaseAdapter {
 
        private class ButtonViewHolder {
            TextView name;
            TextView num;
            TextView date;
            TextView description;
            Button btn;
        }
 
        private Context mContext;
        private List<Map<String, Object>> mList;
        private ButtonViewHolder holder;
        private LayoutInflater mInflater;
        private String[] keyString;
        private int[] valueViewID;
 
        // 构造函数初始化变量
        public MyButtonAdapter(Context context, List<Map<String, Object>> list,
                int resource, String[] from, int[] to) {
            this.mContext = context;
            this.mList = list;
 
            // 获得布局文件对象
            mInflater = (LayoutInflater) context
                    .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            keyString = new String[from.length];
            valueViewID = new int[to.length];
 
            // 复制数组
            System.arraycopy(from, 0, keyString, 0, from.length);
            System.arraycopy(to, 0, valueViewID, 0, to.length);
        }
 
        @Override
        public int getCount() {
            return list.size();
        }
 
        @Override
        public Object getItem(int position) {
            return list.get(position);
        }
 
        /**
         * 从list中移除某一项
         * 
         * @param position
         */
        public void removeItem(int position) {
            list.remove(position);
            // 通知数据集已改变,请求自刷新
            this.notifyDataSetChanged();
        }
 
        @Override
        public long getItemId(int position) {
            return position;
        }
 
        @Override
        public View getView(int position, View convertView, ViewGroup parent) {
            if (convertView != null) {
                holder = (ButtonViewHolder) convertView.getTag();
            } else {
                convertView = mInflater.inflate(R.layout.list_item, null);
                holder = new ButtonViewHolder();
                holder.name = (TextView) convertView
                        .findViewById(valueViewID[0]);// 岗位名称
                holder.num = (TextView) convertView
                        .findViewById(valueViewID[1]);// 岗位数量
                holder.date = (TextView) convertView
                        .findViewById(valueViewID[2]);// 发布日期
                holder.description = (TextView) convertView
                        .findViewById(valueViewID[3]);// 岗位描述
                holder.btn = (Button) convertView.findViewById(valueViewID[4]);// 报名按钮
                convertView.setTag(holder);
            }
            Map<String, Object> appInfo = mList.get(position);
            if (appInfo != null) {
                String aname = (String) appInfo.get(keyString[0]);
                Integer anum = (Integer) appInfo.get(keyString[1]);
                String adate = (String) appInfo.get(keyString[2]);
                String adescription = (String) appInfo.get(keyString[3]);
                holder.name.setText(aname);
                holder.num.setText(anum + "");
                holder.date.setText(adate);
                holder.description.setText(adescription);
 
                // 报名按钮事件
                holder.btn.setOnClickListener(new lvButtonListener(position));
            }
            return convertView;
        }
 
        class lvButtonListener implements OnClickListener {
            private int position;
 
            lvButtonListener(int pos) {
                position = pos;
            }
 
            @Override
            public void onClick(View v) {
                int vid = v.getId();
                if (vid == holder.btn.getId()) {
                    String result = "" + "岗位名称:"
                            + list.get(position).get("name") + "\r\n" + "岗位人数:"
                            + list.get(position).get("num") + "\r\n" + "发布日期:"
                            + list.get(position).get("date") + "\r\n" + "岗位描述:"
                            + list.get(position).get("description") + "\r\n";
 
                    new AlertDialog.Builder(MainActivity.this)
                            .setTitle("提示")
                            .setIcon(R.drawable.ic_launcher)
                            .setMessage(result + "\r\n" + "您确定要申请该岗位吗?")
                            .setPositiveButton(R.string.positive,
                                    new DialogInterface.OnClickListener() {
                                        @Override
                                        public void onClick(
                                                DialogInterface dialog,
                                                int which) {
                                            Toast toast = Toast
                                                    .makeText(
                                                            MainActivity.this,
                                                            "您点击了"
                                                                    + getResources()
                                                                            .getString(
                                                                                    R.string.positive)
                                                                    + "按钮,申请了"
                                                                    + list.get(
                                                                            position)
                                                                            .get("name")
                                                                    + "的岗位!",
                                                            Toast.LENGTH_SHORT);
                                            toast.setGravity(Gravity.CENTER, 0,
                                                    0);
                                            toast.show();
                                        }
                                    })
                            .setNegativeButton(R.string.negative,
                                    new DialogInterface.OnClickListener() {
                                        @Override
                                        public void onClick(
                                                DialogInterface dialog,
                                                int which) {
                                            Toast toast = Toast
                                                    .makeText(
                                                            MainActivity.this,
                                                            "您点击了"
                                                                    + getResources()
                                                                            .getString(
                                                                                    R.string.negative)
                                                                    + "按钮",
                                                            Toast.LENGTH_SHORT);
                                            toast.setGravity(Gravity.CENTER, 0,
                                                    0);
                                            toast.show();
                                        }
                                    }).create().show();
                    // 如果要删除行,可以调用此方法
                    // removeItem(position);
                }
            }
        }
    }
}

上面的代码有几个知识点需要注意:

 1、SQLite数据库的查询操作

我们通过getReadableDatabase().query方法执行了查询操作,返回Cursor(游标,与JDBC中的ResultSet类似)对象。

2、ListView控件使用(重点)

我们参考了SimpleAdapter默认的构造函数的方法,创建了自定义的MyButtonAdapter类,在显示数据的同时,能够给每一行的按钮绑定点击事件。

3、弹出提示框

弹出提示框的代码很长,完全可以封装到一个方法中,简化代码。这里完整的列出来,目的就是体验一下设计思路。经过观察我们发现,这就是所谓的“链式编程”,可以通过连续的".",设置参数(控制显示效果)。

strings.xml:

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <string name="positive">确定</string>
    <string name="negative">取消</string>
</resources>

 

最终在pad上面的执行效果如下:

posted @ 2016-06-14 09:48  guwei4037  阅读(449)  评论(0编辑  收藏  举报