ListView详解

android.widget.ListView,译为"列表视图"


设置项目间的分割线:

android:devider="@android:color/daker"

android:deviderHeight="10dp"

android:devider="@null"分割线为透明

android:scrollBar="none"隐藏滚动条

android:listSelector="#00000000"取消点击效果

listview.setSelection(N); 设置ListView需要显示在第几页


平滑移动:

 

mListView.smoothScrollBy(distance,duration);
mListView.smoothScrollByOffset(offset);
mListView.smoothScrollToPosition(index);

遍历Listview中的所有item:

for (int i = 0; i < list.getChildCount(); i++) {
			View view=list.getChildAt(i);
		}

处理空的ListView:

<FrameLayout 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:id="@+id/listView1"
        android:layout_width="match_parent"
        android:layout_height="match_parent" >
    </ListView>

    <ImageView
        android:id="@+id/img"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:src="@drawable/ic_launcher" />

</FrameLayout>

	ListView list=(ListView) findViewById(R.id.listView1);
		list.setEmptyView(findViewById(R.id.img));

滑动监听:

ontouchlistener

	ListView list=(ListView) findViewById(R.id.listView1);
		list.setOnTouchListener(new View.OnTouchListener() {
			
			@Override
			public boolean onTouch(View arg0, MotionEvent arg1) {
				// TODO Auto-generated method stub
				switch (arg1.getAction()) {
				case MotionEvent.ACTION_DOWN:
					//触摸时操作
					break;
				case MotionEvent.ACTION_MOVE:
					//移动时操作
					break;
				case MotionEvent.ACTION_UP:
					//离开时操作
					break;
				}
				return false;
			}
		});
	}


onscrollListener:

	list.setOnScrollListener(new OnScrollListener() {
			
			@Override
			public void onScrollStateChanged(AbsListView arg0, int arg1) {
				// TODO Auto-generated method stub
				switch (arg1) {
				case OnScrollListener.SCROLL_STATE_IDLE:
					//滑动停止时
					break;
				case OnScrollListener.SCROLL_STATE_TOUCH_SCROLL:
					//正在滚动
				    break;
				case OnScrollListener.SCROLL_STATE_FLING:
					//手指抛动时,即手指用力滑动
					//在离开后listview由于惯性继续滑动
					break;

				}
			}
			
			@Override
			public void onScroll(AbsListView arg0, int arg1, int arg2, int arg3) {
				// TODO Auto-generated method stub
				//滑动时一直调用
				//arg0-firstVisibleItem 当前能看见的第一个item id(从0开始)
				//arg2-visibleitemcount 当前能看见的item总数
				//arg3-toallitemcount 整个list的item总数
				if (arg1+arg2==arg3&&arg3-count>0) {
					//滚到最后一行
				}
				if (arg1>lastVisibleitemposition) {
					//上滑
				}else if (arg1<lastVisibleitemposition) {
				//下滑
				}
				lastVisibleitemposition=arg1;
			}
		});
	}

获取可视区域最后一个id:

list.getLastVisiblePosition();
获取可视区域第一个item的id

list.getFirstVisiblePosition();







列表视图的显示需要三个元素:

1.ListVeiw 用来展示列表的View。

2.适配器 用来把数据映射到ListView上的中介。

3.数据 具体的将被映射的字符串,图片,或者基本组件。

适配器类型通常用ArrayAdapter,SimpleAdapter,SimpleCursorAdapter和BaseAdapter。

ArrayAdapter:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              android:layout_width="match_parent"
              android:layout_height="match_parent" >
       <ListView
              android:id="@+id/list_view"
              android:layout_width="match_parent"
              android:layout_height="match_parent" >
       </ListView>
</LinearLayout>

public class MainActivity extends Activity {
           
  private String[] data = { "A", "B", "C", "D","E", "F", "G", "H", "I", "J" };
          
       @Override
            protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            ArrayAdapter<String> adapter = new ArrayAdapter<String>(
            MainActivity.this, android.R.layout.simple_list_item_1, data);
            ListView listView = (ListView) findViewById(R.id.list_view);
            listView.setAdapter(adapter);
      }
}




只能显示一段文本的 ListView 实在是太单调了, 我们现在就来对 ListView 的界面进行定制,让它可以显示更加丰富的内容

public class Hero {

	private String name;
	
	private int image;
	
	public Hero(String name,int image){
		this.name=name;
		this.image=image;
		
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public int getImage() {
		return image;
	}

	public void setImage(int image) {
		this.image = image;
	}
}

Hero 类中只有两个字段,name 表示英雄的名字,image 表示英雄的肖像id。然后需要为 ListView 的子项指定一个我们自定义的布局,在 layout 目录下新建hero_item.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"
     >

    <TextView
        android:id="@+id/textView1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentTop="true"
        android:layout_marginLeft="17dp"
        android:layout_marginTop="14dp"
        android:layout_toRightOf="@+id/imageView1"
        android:text="TextView" />

    <ImageView
        android:id="@+id/imageView1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentLeft="true"
        android:layout_alignParentTop="true"
        android:layout_marginLeft="24dp"
        android:src="@drawable/ic_launcher" />

</RelativeLayout>


在这个布局中,我们定义了一个 ImageView 用于显示英雄的图片,又定义了一个TextView 用于显示英雄的名字。接下来需要创建一个自定义的适配器,这个适配器继承自 ArrayAdapter,并将泛型指定为 Hero 类。新建类 HeroAdapter,代码如下所示:

public class HeroAdapter extends ArrayAdapter<Hero> {
	
	public int resourceId;

	public HeroAdapter(Context context, int resource, List<Hero> objects) {
		super(context, resource, objects);
		// TODO Auto-generated constructor stub
		resourceId=resource;
	}

	@Override
	public View getView(int position, View convertView, ViewGroup parent) {
		// TODO Auto-generated method stub
		Hero hero=getItem(position);
		View view=LayoutInflater.from(getContext()).inflate(resourceId, null);
		ImageView img=(ImageView)view.findViewById(R.id.imageView1);
		TextView txt=(TextView)view.findViewById(R.id.textView1);
		img.setImageResource(hero.getImage());
		txt.setText(hero.getName());
		return view;
	}
}
HeroAdapter 重写了父类的一组构造函数,用于将上下文、ListView 子项布局的 id和数据都传递进来。另外又重写了 getView()方法,这个方法在每个子项被滚动到屏幕内的
时候会被调用。在 getView 方法中,首先通过 getItem()方法得到当前项的 Hero实例,然后 使 用 LayoutInflater 来 为 这 个 子 项 加 载 我 们 传 入 的 布 局 , 接 着 调 用 View 的findViewById()方法分别获取到 ImageView 和 TextView 的实例,并分别调用它们的setImageResource()和 setText()方法来设置显示的图片和文字,最后将布局返回,这样
我们自定义的适配器就完成了。
下面修改 MainActivity 中的代码,如下所示:

public class MainActivity extends Activity {

	
	private List<Hero> heroList=new ArrayList<Hero>();
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        initHero();
        HeroAdapter adapter=new HeroAdapter(MainActivity.this, R.layout.hero_item, heroList);
        ListView listView = (ListView) findViewById(R.id.listView1);
        listView.setAdapter(adapter);
    }


    private void initHero() {
		// TODO Auto-generated method stub
    	Hero ez = new Hero("EZ", R.drawable.a);
    	heroList.add(ez);
    	Hero mangseng = new Hero("盲僧", R.drawable.b);
    	heroList.add(mangseng);
    	Hero manwang = new Hero("蛮王", R.drawable.c);
    	heroList.add(manwang);
    	Hero kapai = new Hero("卡牌", R.drawable.d);
    	heroList.add(ez);
    	Hero debang = new Hero("德邦", R.drawable.e);
    	heroList.add(debang);
    	Hero yasuo = new Hero("亚索", R.drawable.g);
    	heroList.add(ez);
    	}
<span style="font-family: Arial, Helvetica, sans-serif;">}</span>
<span style="font-family: Arial, Helvetica, sans-serif;">
</span>

可以看到,这里添加了一个initHero()方法,用于初始化所有的水果数据。在 Hero类的构造函数中将水果的名字和对应的图片 id 传入,然后把创建好的对象添加到水果列表中。 接着我们在 onCreate()方法中创建了 HeroAdapter对象, 并将 HeroAdapter作为适配器传递给了 ListView。这样定制 ListView 界面的任务就完成了。


之所以说 ListView 这个控件很难用,就是因为它有很多的细节可以优化,其中运行效率就是很重要的一点。目前我们 ListView 的运行效率是很低的,因为在 HeroAdapter的
getView()方法中每次都将布局重新加载了一遍,当 ListView 快速滚动的时候这就会成为性能的瓶颈。仔细观察,getView()方法中还有一个 convertView 参数,这个参数用于将之前加载好的布局进行缓存,以便之后可以进行重用。修改 HeroAdapter中的代码,


public class HeroAdapter extends ArrayAdapter<Hero> {
	
	public int resourceId;

	public HeroAdapter(Context context, int resource, List<Hero> objects) {
		super(context, resource, objects);
		// TODO Auto-generated constructor stub
		resourceId=resource;
	}

	@Override
	public View getView(int position, View convertView, ViewGroup parent) {
		// TODO Auto-generated method stub
		Hero hero=getItem(position);
		View view;
		if (convertView==null) {
			view=LayoutInflater.from(getContext()).inflate(resourceId, null);
		}else{
			view=convertView;
		}
		
		ImageView img=(ImageView)view.findViewById(R.id.imageView1);
		TextView txt=(TextView)view.findViewById(R.id.textView1);
		img.setImageResource(hero.getImage());
		txt.setText(hero.getName());
		return view;
	}
}




可以看到,现在我们在 getView()方法中进行了判断,如果 convertView 为空,则使用 LayoutInflater 去加载布局,如果不为空则直接对 convertView 进行重用。这样就大大
提高了 ListView 的运行效率,在快速滚动的时候也可以表现出更好的性能。不过, 目前我们的这份代码还是可以继续优化的, 虽然现在已经不会再重复去加载布局,
但是每次在getView()方法中还是会调用View的findViewById()方法来获取一次控件的实例。我们可以借助一个 ViewHolder 来对这部分性能进行优化,修改 HeroAdapter中的代
码,如下所示:

public class HeroAdapter extends ArrayAdapter<Hero> {
	
	public int resourceId;

	public HeroAdapter(Context context, int resource, List<Hero> objects) {
		super(context, resource, objects);
		// TODO Auto-generated constructor stub
		resourceId=resource;
	}

	@Override
	public View getView(int position, View convertView, ViewGroup parent) {
		// TODO Auto-generated method stub
		Hero hero=getItem(position);
		View view;
		ViewHolder viewHolder;
		if (convertView==null) {
			view=LayoutInflater.from(getContext()).inflate(resourceId, null);
		viewHolder=new ViewHolder();
		viewHolder.img=(ImageView)view.findViewById(R.id.imageView1);
		viewHolder.txt=(TextView)view.findViewById(R.id.textView1);
		view.setTag(viewHolder);
		}else{
			view=convertView;
			viewHolder=(ViewHolder) view.getTag();
		}
		
		viewHolder.img.setImageResource(hero.getImage());
		viewHolder.txt.setText(hero.getName());		
		return view;
	}
	class ViewHolder{
		ImageView img;
		
		TextView txt;
		
	}
}
我们新增了一个内部类 ViewHolder,用于对控件的实例进行缓存。当 convertView为空的时候,创建一个 ViewHolder 对象,并将控件的实例都存放在 ViewHolder 里,然
后调用 View 的 setTag()方法,将 ViewHolder 对象存储在 View 中。当 convertView 不为空的时候则调用 View 的 getTag()方法,把 ViewHolder 重新取出。这样所有控件的实例都缓存在了 ViewHolder 里,就没有必要每次都通过 findViewById()方法来获取控件实例了

ListView点击事件

public class MainActivity extends Activity {

	
	private List<Hero> heroList=new ArrayList<Hero>();
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        initHero();
        HeroAdapter adapter=new HeroAdapter(MainActivity.this, R.layout.hero_item, heroList);
        ListView listView = (ListView) findViewById(R.id.listView1);
        listView.setAdapter(adapter);
        listView.setOnItemClickListener(new OnItemClickListener() {

			@Override
			public void onItemClick(AdapterView<?> arg0, View arg1, int arg2,
					long arg3) {
				// TODO Auto-generated method stub
				Hero hero = heroList.get(arg2);
				Toast.makeText(MainActivity.this, hero.getName(),
				Toast.LENGTH_SHORT).show();
			}
		});
    }
........................
}

可以看到, 我们使用了 setOnItemClickListener()方法来为 ListView 注册了一个监听器,当用户点击了 ListView 中的任何一个子项时就会回调 onItemClick()方法,在这个方
法中可以通过 position 参数判断出用户点击的是哪一个子项,然后获取到相应的英雄,并通过 Toast 将英雄的名字显示出来。





动态修改ListView

public class MainActivity extends Activity implements OnClickListener{

	private List<String> mdata;
	private ArrayAdapter<String> adapter;

	private ListView list;

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

		Button btn=(Button) findViewById(R.id.btnAdd);
		btn.setOnClickListener(this);
		mdata = new ArrayList<String>();
		for (int i = 0; i < 20; i++) {
			mdata.add("" + i);
		}
		list = (ListView) findViewById(R.id.listView1);
		adapter = new ArrayAdapter<String>(MainActivity.this,
				android.R.layout.simple_list_item_1, mdata);
		list.setAdapter(adapter);
		for (int i = 0; i < list.getChildCount(); i++) {
			View view=list.getChildAt(i);
		}
	}

//	public void btnAdd(View view) {
//		mdata.add("new");
//		adapter.notifyDataSetChanged();
//		list.setSelection(mdata.size() - 1);
//	}

	@Override
	public void onClick(View arg0) {
		// TODO Auto-generated method stub
		switch (arg0.getId()) {
		case R.id.btnAdd:
			mdata.add("new");
			adapter.notifyDataSetChanged();
			list.setSelection(mdata.size()-1);
			break;

		default:
			break;
		}
	}

}




  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值