类似于天气预报中用户添加一个城市的天气,就新生成一个天气信息展示页面;删除一个城市的天气,则相应的天气信息展示页被删除的效果。(一步一步的)总结一下该效果是如何通过ViewPager来实现的。
本例实现的功能:用户可以通过点击添加按钮来添加一个新的页面;点击删除按钮,删除当前页面。
1.准备工作
1.1 布局文件
ViewPager中页面的布局文件view.xml:
- <?xml version=“1.0” encoding=“utf-8”?>
- <LinearLayout xmlns:android=“http://schemas.android.com/apk/res/android”
- android:orientation=“vertical” android:layout_width=“match_parent”
- android:layout_height=“match_parent”>
- <TextView
- android:id=“@+id/text_view”
- android:gravity=“center”
- android:layout_width=“match_parent”
- android:layout_height=“wrap_content” />
- </LinearLayout>
MainActivity布局文件activity_main.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”>
- <android.support.v4.view.ViewPager
- android:id=“@+id/view_pager”
- android:layout_width=“match_parent”
- android:layout_height=“match_parent”></android.support.v4.view.ViewPager>
- </RelativeLayout>
1.2 适配器
新建一个类MyPagerAdapter继承自android.support.v4.view.PagerAdapter :
- package com.example.viewpagerdemo;
- import android.support.v4.view.PagerAdapter;
- import android.view.View;
- import android.view.ViewGroup;
- import java.util.List;
- public class MyPagerAdapter extends PagerAdapter{
- private List<View> viewList;
- public MyPagerAdapter(List<View> viewList){
- this.viewList = viewList;
- }
- @Override
- public void destroyItem(ViewGroup container, int position, Object object) {
- container.removeView((View)object);
- }
- @Override
- public int getCount() {
- return viewList.size();
- }
- @Override
- public Object instantiateItem(ViewGroup container, int position) {
- container.addView(viewList.get(position));
- return viewList.get(position);
- }
- @Override
- public boolean isViewFromObject(View view, Object object) {
- return view == object;
- }
- @Override
- public int getItemPosition(Object object) {
- return POSITION_NONE;
- }
- }
注意,destroyItem方法和getItemPosition方法,这里先请大家留意一下,下面会解释这两个方法和平常使用的ViewPager有何不同…
2. 具体实现
- import android.support.v4.view.ViewPager;
- import android.support.v7.app.AppCompatActivity;
- import android.os.Bundle;
- import android.view.LayoutInflater;
- import android.view.Menu;
- import android.view.MenuItem;
- import android.view.View;
- import android.widget.TextView;
- import java.util.ArrayList;
- import java.util.List;
- public class MainActivity extends AppCompatActivity {
- private List<View> viewList = new ArrayList<>();//ViewPager数据源
- private MyPagerAdapter myPagerAdapter;//适配器
- private ViewPager viewPager;
- private int count = 0; //页面展示的数据,无实际作用
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_main);
- myPagerAdapter = new MyPagerAdapter(viewList);//创建适配器实例
- viewPager = (ViewPager) findViewById(R.id.view_pager);
- viewPager.setAdapter(myPagerAdapter);//为ViewPager设置适配器
- }
- /**
- * 添加选项菜单
- * 为了不影响ViewPager每个页面的一致性,这里使用选项菜单来操作添加和删除页面的点击事件
- */
- @Override
- public boolean onCreateOptionsMenu(Menu menu) {
- menu.add(1,1,1,“添加页面”);
- menu.add(1,2,1,“删除页面”);
- return super.onCreateOptionsMenu(menu);
- }
- /**
- * 为选项菜单设置点击事件监听
- */
- @Override
- public boolean onOptionsItemSelected(MenuItem item) {
- switch (item.getItemId()){
- case 1://添加页面的点击事件
- String text = “页面” + count;
- count++;
- addPage(text);
- break;
- case 2://删除页面的点击事件
- delPage();
- break;
- }
- return super.onOptionsItemSelected(item);
- }
- /**
- *该方法封装了添加页面的代码逻辑实现,参数text为要展示的数据
- */
- public void addPage(String text){
- LayoutInflater inflater = LayoutInflater.from(this);//获取LayoutInflater的实例
- View view = inflater.inflate(R.layout.view, null);//调用LayoutInflater实例的inflate()方法来加载页面的布局
- TextView textView = (TextView) view.findViewById(R.id.text_view);//获取该View对象的TextView实例
- textView.setText(text);//展示数据
- viewList.add(view);//为数据源添加一项数据
- myPagerAdapter.notifyDataSetChanged();//通知UI更新
- }
- /**
- * 删除当前页面
- */
- public void delPage(){
- int position = viewPager.getCurrentItem();//获取当前页面位置
- viewList.remove(position);//删除一项数据源中的数据
- myPagerAdapter.notifyDataSetChanged();//通知UI更新
- }
- }
代码梳理:
1. 首先是一些初始化操作(ViewPager的使用): 定义一个空的数据源viewList; 创建数据适配器实例myPagerAdapter;为ViewPager设置数据适配器.(现在程序已经可以运行了,但是ViewPager里是空的,没有页面的)
2. 设置用户的添加和删除的点击事件;这里我用了一个选项菜单作为用户的点击按钮(不太了解选项菜单的看官,可以直接跳过onCreateOptionsMenu和onOptionsItemSelected这两个方法,只当他们是两个”按钮“即可)
3. 我们可以发现许多程序页面的布局结构都是相同的,不同的只是展示的内容信息(想象天气预报的天气信息展示页);所以我们最开始写了页面的布局view.xml,相当于一个模版,每一个不同的页面只是我们为其设置的展示数据不同。每当用户点击”添加页面时“,执行addPage()方法,该方法首先通过LayoutInflater的实例获取的View的实例(LayoutInflater的用法也请自行查询。其实findViewById也是返回的一个View的实例),然后拿到View实例里面的控件实例textView,设置展示信息,最后为ViewPager的数据源添加一项数据,添加了一个页面需要使用notifyDataSetChanged方法通知UI更新。(ViewPager中使notifyDataSetChanged方法起作用需要重写适配器中的getItemPosition方法)
4. 删除页面,当用户点击”删除页面“时,执行delPage()方法,该方法首先通过getCurrentItem方法获取当前页面滑动到了哪个位置,再通过移除数据源中的数据项,并且通知UI更新来实现页面的删除。
看到许多的ViewPager教程中适配器的destroyItem方法都是这样写的:
- <span style=“font-size:12px;”>public void destroyItem(ViewGroup container, int position, Object object) {
- container.removeView(viewList.get(position));
- }</span>
这样写在删除页面的时候会报下标越界异常,原因也很容易发现,当前页面的view项已经被我们从viewList中移除了,但是destroyItem方法中仍然在访问它。修改方法在上面的适配器的代码中已经给出了。
总结,添加和删除页面都是操作通过数据源的实现的。由于本例只是介绍ViewPager的动态添加、删除页面,所以有些问题,比如为什么ViewPager动态更新UI为什么要重写getItemPosition方法,并没有去深究,有兴趣的看官可以自行了解。另外发现本例一个bug,每次退出再进入的时候上次添加的页面没有了,这是由于我们并没有将数据源存储起来。
欢迎大家交流指正
源码下载:http://download.csdn.net/download/yunyis/10133529