今天在这里和大家分享一下我对ListView和ViewPager的了解。简单索引如下:
- ListView
定义
一些常用属性
Adapter 常用的实现类
ArrayAdapter 的使用
SimpleAdapter 的使用
- ViewPager
定义
主要方法
OnPageChangeListener
三种适配器的简单说明:
PagerAdapter
FragmentPagerAdapter
FragmentStatePagerAdapter
说到ListView大家也许不会陌生,这个UI组件在我们手机里面的许多应用软件中都有使用,它常用来以垂直列表的形式显示所有列表项。
需要在对应的界面布局文件中定义,如:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ListView
android:id="@+id/list"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:divider="@android:color/darker_gray"
android:dividerHeight="2px"
android:headerDividersEnabled="false">
ListView>
LinearLayout>
值得注意的是,在布局文件中定义ListView时,需要为其定义id。此处的代码为:“android:id=”@+id/list””,该id在后面的操作中会经常使用,请不要忘记
android:divider //设置List列表项的分隔条(既可以用颜色分隔也可以用Drawable分隔)
android:dividerHeight //设置分隔条的高度
android:entries //指定一个数组资源,Android将根据该数组资源来生成ListView
android:footerDividersEnabled //如果设置为false,则不在footer View之前绘制分隔条
android:headerDividersEnabled //如果设置为false,则不在header View之后绘制分隔条
注意:如果此处使用了”android:entries”,则需要在values文件下创建对应的资源文件
事实上,通过以上方法已经可以创建ListView了。只不过这样创建出来的ListView十分简单,能够定制的内容很少,甚至连每个列表项的字号大小、颜色等属性都不能改变。
如果想对ListView的外观、行为进行定制,就需要把ListView作为AdapterView使用,进而通过Adapter控制每个列表项的外观和行为。
ArrayAdapter:简单、易用的Adapter,通常用于将数组或List集合的多个值包装成多个列表项
SimpleAdapter:功能强大、并不“简单”的Adapter,可用于将List集合的多个对象包装成多个列表项
SimpleCursorAdapter:与SimpleAdapter基本相同,只是用于包装Cursor提供的数据
BaseAdapter:通常用于被扩展。扩展BaseAdapter可以对各列表项进行最大限度的定制。
本文仅介绍ArrayAdapter与SimpleAdapter
private ListView listView;
private List stringList;
private ArrayAdapterarrayAdapter;
……
……
/**
* 初始化ListView
*/
listView = (ListView) findViewById(R.id.list);
/**
* 准备数据源
*/
stringList = new ArrayList<>();
stringList.add("新的朋友");
stringList.add("群聊");
stringList.add("标签");
stringList.add("公众号");
/**
* 建立ArrayAdapter适配器对象
*/
arrayAdapter = new ArrayAdapter(this,android.R.layout.simple_list_item_1,stringList);
/**
* ListView加载对应的适配器
*/
listView.setAdapter(arrayAdapter);
在创建ArrayAdapter时,必须指定如下三个参数:
效果如下:(真机版)
如果程序的窗口仅仅需要一个列表,那么可以直接让Activity继承ListActivity来快速实现。ListActivity无须布局文件——相当于它的布局文件只有一个ListView,因此只要为ListActivity设置Adapter即可
private ListView listView;
private List stringList;
private SimpleAdapter simpleAdapter;
private List
在创建SimpleAdapter时,必须指定如下五个参数:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:id="@+id/image" //此处需要定义id
android:layout_margin="15dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@mipmap/ic_launcher_round"/>
<TextView
android:id="@+id/text" //此处需要定义id
android:layout_width="wrap_content"
android:layout_height="30dp"
android:textSize="20sp"
android:textColor="#000000"
android:text="Demo"
android:layout_margin="25dp"/>
LinearLayout>
效果如下:(测试版)
现如今,ViewPager用于实现页面间的切换,我们在各大应用程序中均可看到它的影子。ViewPager使用前也需要在对应的布局文件中定义。
需要在对应的界面布局文件中定义,如:
.support.v4.view.ViewPager
android:id="@+id/pager"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center">
.support.v4.view.ViewPager>
同样地,这里也需要为ViewPager定义id
setAdapter(PagerAdapter adapter)
该方法为ViewPager设置适配器,ViewPager有三种适配器,它们分别有不同的特性
setCurrentItem(int item)
该方法设置显示item位置的界面
setOffscreenPageLimit(int limit)
该方法用来设置当前显示页面左右两边各缓存的页面数
addOnPageChangeListener(OnPageChangeListener listener)
该方法为ViewPager添加页面切换时的监听
setOnScrollChangeListener(OnScrollChangeListener l)
该方法为ViewPager增加滚动状态监听,但该方法需要minSdkVersion为23
onPageScrollStateChanged(int state)
该方法在手指操作屏幕的时候发生变化。有三个值:0(END),1(PRESS) ,2(UP) 。当用手指滑动翻页时,手指按下去的时候会触发这个方法,state值为1,手指抬起时,如果发生了滑动(即使很小),这个值会变为2,然后最后变为0 。总共执行这个方法三次。一种特殊情况是手指按下去以后一点滑动也没有发生,这个时候只会调用这个方法两次,state值分别是1,0 。当setCurrentItem翻页时,会执行这个方法两次,state值分别为2 ,0
onPageScrolled(int position, float positionOffset, int positionOffsetPixels)
- position:当用手指滑动时,如果手指按在页面上不动,position和当前页面index是一致的;如果手指向左拖动(相应页面向右翻动),这时候position大部分时间和当前页面是一致的,只有翻页成功的情况下最后一次调用才会变为目标页面;如果手指向右拖动(相应页面向左翻动),这时候position大部分时间和目标页面是一致的,只有翻页不成功的情况下最后一次调用才会变为原页面。当直接设置setCurrentItem翻页时,如果是相邻的情况(比如现在是第二个页面,跳到第一或者第三个页面),如果页面向右翻动,大部分时间是和当前页面是一致的,只有最后才变成目标页面;如果向左翻动,position和目标页面是一致的。这和用手指拖动页面翻动是基本一致的。如果不是相邻的情况,比如我从第一个页面跳到第三个页面,position先是0,然后逐步变成1,然后逐步变成2;我从第三个页面跳到第一个页面,position先是1,然后逐步变成0,并没有出现为2的情况。
- positionOffset:当前页面滑动比例,如果页面向右翻动,这个值不断变大,最后在趋近1的情况后突变为0。如果页面向左翻动,这个值不断变小,最后变为0
- positionOffsetPixels:当前页面滑动像素,变化情况和positionOffset一致
三个方法的执行顺序:用手指拖动翻页时,最先执行一遍 onPageScrollStateChanged(1),然后不断执行 onPageScrolled,放手指的时候,直接立即执行一次 onPageScrollStateChanged(2),然后立即执行一次 onPageSelected,然后再不断执行 onPageScrollStateChanged,最后执行一次 onPageScrollStateChanged(0)
先放一张图来大概了解一下其中的关系:
首先,让我们来看一下代码:
private ListviewList;
private ViewPager pager;
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
pager = (ViewPager) findViewById(R.id.pager);
/**
* 通过inflate方法将对应布局文件转化为View对象
* 使用View对象来作为ViewPager的数据源
*/
View view1 = View.inflate(this,R.layout.view_1,null);
View view2 = View.inflate(this,R.layout.view_2,null);
View view3 = View.inflate(this,R.layout.view_3,null);
View view4 = View.inflate(this,R.layout.view_4,null);
viewList.add(view1);
viewList.add(view2);
viewList.add(view3);
viewList.add(view4);
/**
* 创建PagerAdapter的适配器对象
*/
MyPagerAdapter adapter = new MyPagerAdapter(viewList);
/**
* ViewPager加载对应的适配器
*/
pager.setAdapter(adapter);
}
这里我就不给出view_1、2、3、4布局的代码啦,大家稍微脑补一下吧
此外,这里我是新建一个子类 MyPagerAdapter来创建对象的,下面给出这个子类的代码:
public class MyPagerAdapter extends PagerAdapter
{
private ListviewList;
public MyPagerAdapter(List viewList)
{
this.viewList = viewList;
}
@Override
public int getCount()
{
return viewList.size();//返回的是页面的数量
}
@Override
public boolean isViewFromObject(View view, Object object)
{
return view == object;//判断View是否来着于object对象
}
@Override
public Object instantiateItem(ViewGroup container, int position)
{
container.addView(viewList.get(position));
return viewList.get(position);//实例化一个页面
}
@Override
public void destroyItem(ViewGroup container, int position, Object object)
{
container.removeView(viewList.get(position));
//销毁一个网面。一般情况下,PagerAdapter只会三个三个地加载View对象,创建和销毁都是自动调用的
}
这种方法最好用于有限个静态fragment页面的管理。尽管不可见的视图有时会被销毁,但用户所有访问过的fragment都会被保存在内存中。因此fragment实例会保存大量的各种状态,这就造成了很大的内存开销。
下面我们来看一下代码:
private ViewPager pager;
private List fragmentList;
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
pager = (ViewPager) findViewById(R.id.pager);
/**
* 通过Fragment对象作为ViewPager的数据源
*/
fragmentList = new ArrayList<>();
fragmentList.add(new Fragment1());
fragmentList.add(new Fragment2());
fragmentList.add(new Fragment3());
fragmentList.add(new Fragment4());
/**
* 创建FragmentAdapter的适配器对象
*/
MyFragmentPagerAdapter adapter1 = new MyFragmentPagerAdapter(getSupportFragmentManager(),fragmentList);
/**
* ViewPager加载对应的适配器
*/
pager.setAdapter(adapter1);
}
这里也不给出 Fragment1、2、3、4这四个类的代码啦,其实里面因为只是演示所以也没有放什么东西进去
下面给出 MyFragmentPagerAdapter的代码:
public class MyFragmentPagerAdapter extends FragmentPagerAdapter
{
private ListfragmentList;
public MyFragmentPagerAdapter(FragmentManager fm,List fragmentList)
{
super(fm);
this.fragmentList = fragmentList;
}
@Override
public Fragment getItem(int position)
{
return fragmentList.get(position);//返回position位置关联的Fragment
}
@Override
public int getCount()
{
return fragmentList.size();//返回所有fragment的数量
}
}
在上面的FragmentPagerAdapter中我们了解到,这个适配器最好用于有限个静态fragment页面的管理。但如果要处理大量的页面切换时怎么办?这时建议使用FragmentStatePagerAdapter
该适配器适合处理大量的页面切换,其能能够保存和恢复Fragment状态的适配器,超出缓存的Fragment会调用onDestory()方法,彻底对销毁Fragment进行销毁
由于 FragmentPagerAdapter和我们上面所说的 FragmentPagerAdapter十分相似,故此处便不举例了