ListView总结(一)

ListView总结(一)

listview是比较常用的组件,可以方便的把内容以列表的形式展现.

步骤

三要素:listview(展示列表的view),数据(字符串,图片等),适配器(将数据映射到listview上)

步骤:
1.在布局文件上添加listview控件
2.通过id找到listview控件
3.准备数据
4.使用数据适配器填充数据

代码

<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" >

<!-- 1.在布局文件上添加listview控件 -->

<ListView
    android:id="@+id/lv"
    android:layout_width="match_parent"
    android:layout_height="match_parent" />

</RelativeLayout>
布局文件view
<?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="100dip"
android:padding="10dip" >

<ImageView
    android:id="@+id/iv"
    android:layout_width="80dip"
    android:layout_height="80dip"
    android:src="@drawable/ic_launcher" />

<TextView
    android:id="@+id/tv_title"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_toRightOf="@id/iv"

    <!-- 设置单行显示 -->

    android:singleLine="true"
    android:text="新闻标题"
    android:textSize="16sp" />

<TextView
    android:id="@+id/tv_desc"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_below="@id/tv_title"
    android:layout_toRightOf="@id/iv"

    <!-- 设置最多显示的行数 -->

    android:maxLines="3"
    android:text="新闻描述"
    android:textColor="#66000000"
    android:textSize="13sp" />

<TextView
    android:id="@+id/tv_type"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_alignParentBottom="true"
    android:layout_alignParentRight="true"
    android:text="专题"
    android:textSize="10sp" />

</RelativeLayout>
activity文件
import java.io.FileInputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.xmlpull.v1.XmlPullParser;

import android.app.Activity;
import android.graphics.Color;
import android.os.Bundle;
import android.os.Environment;
import android.util.Xml;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.TextView;

public class MainActivity extends Activity {

private ListView lv;
private List<Map<String, String>> list = new ArrayList<Map<String, String>>();

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    // 2.通过id找到listview控件
    lv = (ListView) findViewById(R.id.lv);

    // 3.准备数据:解析sd卡中的xml文件,把数据放到list集合中
    parsernews();

    // 4.使用数据适配器填充数据:自定义数据适配器填充数据

    lv.setAdapter(new MyAdapter());
}

private void parsernews() {

    try {
        // 1.创建解析器
        XmlPullParser parser = Xml.newPullParser();

        // 2.初始化解析器
        FileInputStream fis = new FileInputStream(
                Environment.getExternalStorageDirectory() + "/news.xml");
        parser.setInput(fis, "UTF-8");

        // 3.得到当前解析的事件类型
        int type = parser.getEventType();
        Map<String, String> map = null;
        // 4.如果没有解析到文档结尾,就循环解析每个子标签
        while (type != XmlPullParser.END_DOCUMENT) {
            switch (type) {
            case XmlPullParser.START_TAG: // 解析到开始标签

                // 得到当前解析到的开始标签
                String name = parser.getName();
                if ("item".equals(name)) {
                    map = new HashMap<String, String>();
                } else if ("title".equals(name)) {
                    // 得到标签体
                    String title = parser.nextText();
                    map.put("title", title);
                } else if ("description".equals(name)) {
                    // 得到标签体
                    String description = parser.nextText();
                    map.put("description", description);
                } else if ("image".equals(name)) {
                    // 得到标签体
                    String image = parser.nextText();
                    map.put("image", image);
                } else if ("type".equals(name)) {
                    // 得到标签体
                    String newsType = parser.nextText();
                    map.put("type", newsType);
                } else if ("comment".equals(name)) {
                    // 得到标签体
                    String comment = parser.nextText();
                    map.put("comment", comment);
                }
                break;

            case XmlPullParser.END_TAG:

                // 得到当前解析到的开始标签
                String endName = parser.getName();
                if ("item".equals(endName)) {
                    list.add(map);
                    map = null;
                }
                break;
            }
            // 解析到下一个事件类型
            type = parser.next();
        }

        fis.close();
    } catch (Exception e) {
        e.printStackTrace();
    }

}

private class MyAdapter extends BaseAdapter {

    @Override
    public int getCount() {
        return list.size();
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {

        // 1.加载布局文件为view
        View view = View.inflate(MainActivity.this, R.layout.item, null);

        // 2.得到布局文件中的控件
        ImageView iv = (ImageView) view.findViewById(R.id.iv);
        TextView tv_title = (TextView) view.findViewById(R.id.tv_title);
        TextView tv_desc = (TextView) view.findViewById(R.id.tv_desc);
        TextView tv_type = (TextView) view.findViewById(R.id.tv_type);

        // 3.给控件填充数据
        Map<String, String> map = list.get(position);
        tv_title.setText(map.get("title"));
        tv_desc.setText(map.get("description"));
        String type = map.get("type");
        if ("1".equals(type)) {
            tv_type.setText("专题");
            tv_type.setTextColor(Color.RED);
        }
        if ("2".equals(type)) {
            tv_type.setText("评论");
            tv_type.setTextColor(Color.BLACK);
        }
        if ("3".equals(type)) {
            tv_type.setTextColor(Color.BLUE);
            tv_type.setText("视频");
        }

        // 4.返回view
        return view;
    }

    @Override
    public Object getItem(int position) {
        return null;
    }

    @Override
    public long getItemId(int position) {
        return 0;
    }

  }

}
程序运行得到的结果如图1,

这里写图片描述
上面将xml文件解析后的数据存放在map集合中,但是这种单纯键值对的形式有局限性,如果用Javabean类保存解析得到的数据,扩展性会更好.

下面的几段代码用Javabean类保存解析得到的数据,并用tomcat模拟服务器存放xml文件(需要加权限).
     <uses-permission android:name="android.permission.INTERNET"/>
javabean类
package so.easy.newsclient.domain;

public class NewsInfo {

    private String title;
    private String description;
    private String image;
    private String type;
    private String comment;


    public String getTitle() {
        return title;
    }
    public void setTitle(String title) {
        this.title = title;
    }
    public String getDescription() {
        return description;
    }
    public void setDescription(String description) {
        this.description = description;
    }
    public String getImage() {
        return image;
    }
    public void setImage(String image) {
        this.image = image;
    }
    public String getType() {
        return type;
    }
    public void setType(String type) {
        this.type = type;
    }
    public String getComment() {
        return comment;
    }
    public void setComment(String comment) {
        this.comment = comment;
    }
    @Override
    public String toString() {
        return "NewsInfo [title=" + title + ", description=" + description
                + ", image=" + image + ", type=" + type + ", comment="
                + comment + "]";
    }
}
解析xml文件的util类
package so.easy.newsclient.service;

import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;

import org.xmlpull.v1.XmlPullParser;

import android.util.Xml;

import so.easy.newsclient.domain.NewsInfo;

public class ParseNewsService {

    public static List<NewsInfo> parserNews(InputStream is) {

        List<NewsInfo> list = new ArrayList<NewsInfo>();
        try {
            XmlPullParser parser = Xml.newPullParser();

            parser.setInput(is, "UTF-8");

            int type = parser.getEventType();

            NewsInfo info = null;

            while (type != XmlPullParser.END_DOCUMENT) {
                switch (type) {
                case XmlPullParser.START_TAG: 
                    String name = parser.getName();
                    if ("item".equals(name)) {
                        info = new NewsInfo();
                    } else if ("title".equals(name)) {
                        String title = parser.nextText();
                        info.setTitle(title);
                    } else if ("description".equals(name)) {
                        String description = parser.nextText();
                        info.setDescription(description);
                    } else if ("image".equals(name)) {
                        String image = parser.nextText();
                        info.setImage(image);
                    } else if ("type".equals(name)) {
                        String newsType = parser.nextText();
                        info.setType(newsType);
                    } else if ("comment".equals(name)) {
                        String comment = parser.nextText();
                        info.setComment(comment);
                    }   
                    break;

                case XmlPullParser.END_TAG: 
                    String endName = parser.getName();
                    if ("item".equals(endName)) {
                        list.add(info);
                        info = null;
                    }
                    break;
                }
                type = parser.next();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return list;
    }

}
activity
package so.easy.newsclient;

import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import com.jit.lib.SmartImageView;
import so.easy.newsclient.domain.NewsInfo;
import so.easy.newsclient.service.ParseNewsService;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.app.Activity;
import android.graphics.Color;
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 {
    private ListView lv;
    public static final String path = "http://192.168.20.87:8080/news.xml";
    private List<NewsInfo> list = new ArrayList<NewsInfo>();
    private Handler handler = new Handler() {
        public void handleMessage(Message msg) {
            // List<NewsInfo> list = (List<NewsInfo>) msg.obj;
            // 新闻数据填充在listview上;
            lv.setAdapter(new MyAdapter());
        };
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        lv = (ListView) findViewById(R.id.lv);
        // 访问网络,获取服务器返回的数据,放到list集合中
        // 不能在主线程中访问网络
        getData();
    }

    private void getData() {
        // 访问网络
        new Thread() {
            public void run() {
                try {
                    // 创建url对象,打开http类型的连接
                    URL url = new URL(path);
                    HttpURLConnection connection = (HttpURLConnection) url
                            .openConnection();
                    // 设置连接的请求参数
                    connection.setRequestMethod("GET");
                    connection.setConnectTimeout(3000);
                    // 得到服务器返回的响应码,判断是否是200
                    int code = connection.getResponseCode();
                    if (code == 200) {
                        // 得到服务器返回的二进制输入流
                        InputStream is = connection.getInputStream();
                        // 获取服务器返回的新闻数据,解析xml数据,放到list集合中
                        list = ParseNewsService.parserNews(is);
                        // 关流
                        is.close();
                        // 子线程不能修改ui界面,所以使用handle完成修改工作
                        // 新闻数据填充到listview上
                        Message msg = Message.obtain();
                        msg.obj = list;
                        handler.sendMessage(msg);
                    }

                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }.start();
    }

    private class MyAdapter extends BaseAdapter {

        @Override
        public int getCount() {
            return list.size();
        }

        @Override
        public View getView(int position, View convertView, ViewGroup parent) {
            // 1.把布局文件加载为一个view对象
            View view = View.inflate(MainActivity.this, R.layout.item, null);

            // 2.得到布局文件中的控件
            SmartImageView siv = (SmartImageView) view.findViewById(R.id.siv);
            TextView tv_title = (TextView) view.findViewById(R.id.tv_title);
            TextView tv_desc = (TextView) view.findViewById(R.id.tv_desc);
            TextView tv_type = (TextView) view.findViewById(R.id.tv_type);

            // 3.给控件填充数据
            NewsInfo info = list.get(position);
            // 使用SmartImageview加载网络上的图片
            siv.setImageUrl(info.getImage());

            tv_title.setText(info.getTitle());
            tv_desc.setText(info.getDescription());

            if ("1".equals(info.getType())) {
                // 评论
                tv_type.setText("评论:" + info.getComment());
                tv_type.setTextColor(Color.RED);
            }
            if ("2".equals(info.getType())) {
                // 视频
                tv_type.setText("视频");
                tv_type.setTextColor(Color.BLUE);
            }

            if ("3".equals(info.getType())) {
                // 专题
                tv_type.setText("专题");
                tv_type.setTextColor(Color.BLACK);
            }
            // 4.返回view显示在界面上
            return view;
        }

        @Override
        public Object getItem(int position) {
            return null;
        }

        @Override
        public long getItemId(int position) {
            return 0;
        }
    }
}

这里写图片描述

关于adapter

上面用到的适配器都是自定义的适配器,Android也提供了很多adapter,ArrayAdapter,simpleAdapter,SimpleCursorAdapter,BaseAdapter等.
#
使用arrayAdapter适配数据
    MainActivity.this   上下文
    android.R.layout.simple_list_item_1     
        系统定义好的条目的布局文件,这里也可以使用自定义的布局view
    names   需要填充的数据

lv.setAdapter(new ArrayAdapter<String>(MainActivity.this, android.R.layout.simple_list_item_1, names));

使用系统提供的布局还可以实现带选择框的ListView;
    android.R.layout.simple_list_item_checked
    android.R.layout.simple_list_item_multiple_choice
    android.R.layout.simple_list_item_single_choice
上面三种布局只是提供了选择框的风格,单选多选的实现还需添加以下代码;
    lv.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);    //多选
    lv.setChoiceMode(ListView.CHOICE_MODE_SINGLE);  //单选

还可以为listview添加点击监听事件;
lv.setOnItemClickListener(new OnItemClickListener() {

        @Override
        public void onItemClick(AdapterView<?> parent, View view, int position,
                long id) {
            int x = position%3;
            if (x==0) {
                view.setBackgroundColor(Color.BLUE);
            } else if(x==1){
                view.setBackgroundColor(Color.GREEN);
            }else if (x==2) {
                view.setBackgroundColor(Color.RED);
            }
        }
    }); 

这里写图片描述

#
使用SimpleAdapter适配数据
除了可以在listview列表中添加文字,还能添加图片,Button,CheckBox等
    MainActivity.this    上下文
    data    要显示的数据,必须是list,里面的元素必须是map类型的
    new String[]{"name"}    map中要显示的字段名称的数组
    new int[]{R.id.tv_name}     字段显示的控件的id的数组

    lv.setAdapter(new SimpleAdapter(MainActivity.this, data, R.layout.item, new String[]{"name","sex"}, new int[]{R.id.tv_name,R.id.tv_sex}));
#
如果在listview列表中加入Button,Button会抢夺ListView的焦点,只需在button的xml文件中将focusable参数(默认为true)设置为false,
    android:focusable=“false”

    lv.setAdapter(new SimpleAdapter(MainActivity.this, data, R.layout.item,
            new String[] { "name", "sex", "btn" }, new int[] {
                    R.id.tv_name, R.id.tv_sex, R.id.btn }));

    lv.setOnItemClickListener(new OnItemClickListener() {

        @Override
        public void onItemClick(AdapterView<?> arg0, View arg1, int arg2,
                long arg3) {
            Toast.makeText(getApplicationContext(), "Listview条目", 0).show();
            System.out.println("ListView 条目");

            Button btn = (Button) arg1.findViewById(R.id.btn);
            btn.setOnClickListener(new OnClickListener() {

                @Override
                public void onClick(View v) {
                    Toast.makeText(getApplicationContext(), "btn", 0)
                            .show();
                    System.out.println("Button");
                }
            });
        }
    }); 

点击后的Logcat打印日志:

这里写图片描述

#
使用ListView时,可以继承listActivity(和Activity区别不大),它对ListView做了优化,设置适配器时调用setListAdapter()方法.

ListView 优化

优化的两种方式:
    conventView
    ViewHolder
下面是三段Google实例代码;

这里写图片描述

the slow way

public View getView(int position, View convertView, ViewGroup parent) {

    View item = mInflater.inflat(R.layout.list_item_icon_text, null);
    ((TextView) item.findViewById(R.id.text)).setText(DATA[position]);
    ((ImageView) item.findViewById(R.id.icon)).setImageBitmap((position & 1) == 1 ? mIcon1 : mIcon2);

    return item;
}

the right way

conventView的特点:
    – Supplied by ListView
    – Matches item types
    – Reuse it
可以看出conventView的重用省去了findviewbyid()的时间,提高了效率;   
#
public View getView(int position, View convertView, ViewGroup parent) {

    if (convertView == null) {
        // 缓存为空的时候 创建一个新的view
        convertView = mInflater.inflate(R.layout.item, parent, false);
    }

    ((TextView) convertView.findViewById(R.id.text)).setText(DATA[position]);
    ((ImageView) convertView.findViewById(R.id.icon)).setImageBitmap(
    (position & 1) == 1 ? mIcon1 : mIcon2);

    return convertView;
 }

the fast way

 public View getView(int position, View convertView, ViewGroup parent) {
    ViewHolder holder;
    // 1.判断缓存view是否为空
    if (convertView == null) {
        convertView = mInflater.inflate(R.layout.list_item_icon_text,parent, false);
        // 2创建新的对象 并创建viewHolder对象
        holder = new ViewHolder();
        // 3.取出控件放到viewHolder里
        holder.text = (TextView) convertView.findViewById(R.id.text);
        holder.icon = (ImageView) convertView.findViewById(R.id.icon);
        // 4.把viewHolder作为一个标记 放到convertView上
        convertView.setTag(holder);
    } else {
        // 5.取出缓存view里的viewHolder对象 因为viewHolder里面有控件 减少了findViewById的过程
        holder = (ViewHolder) convertView.getTag();
    }
    // 6.给控件赋值
    holder.text.setText(DATA[position]);
    holder.icon.setImageBitmap((position & 1) == 1 ? mIcon1 : mIcon2);

    return convertView;
 }
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值