Android -- ViewPager、Fragment、状态保存、通信
工程架构
TabAFm到TabEFm都是Fragment,并且每个Fragment对应一个布局文件。
TabAFm.java
package com.yydcdut.viewpagerstudy; import android.app.Activity;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup; public class TabAFm extends Fragment { @Override
public void onAttach(Activity activity) {
super.onAttach(activity);
System.out.println("AAAAAAAAAA____onAttach");
} @Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
System.out.println("AAAAAAAAAA____onCreate");
} @Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
System.out.println("AAAAAAAAAA____onCreateView");
return inflater.inflate(R.layout.tab_a, container, false);
} @Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
System.out.println("AAAAAAAAAA____onActivityCreated");
} @Override
public void onStart() {
super.onStart();
System.out.println("AAAAAAAAAA____onStart");
} @Override
public void onResume() {
super.onResume();
System.out.println("AAAAAAAAAA____onResume");
} @Override
public void onPause() {
super.onPause();
System.out.println("AAAAAAAAAA____onPause");
} @Override
public void onStop() {
super.onStop();
System.out.println("AAAAAAAAAA____onStop");
} @Override
public void onDestroyView() {
super.onDestroyView();
System.out.println("AAAAAAAAAA____onDestroyView");
} @Override
public void onDestroy() {
super.onDestroy();
System.out.println("AAAAAAAAAA____onDestroy");
} @Override
public void onDetach() {
super.onDetach();
System.out.println("AAAAAAAAAA____onDetach");
} }
如上述代码所示,TabAFm是一个Fragment,对应的布局文件是tab_a.xml,并实现了他的所有的生命周期回调函数并打印,便于调试。tab_a.xml布局中有个EditText,其他的Fragment大同小异,这里就不贴出代码了
MainActivity
package com.yydcdut.viewpagerstudy; import java.util.ArrayList;
import java.util.List; import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentActivity;
import android.support.v4.view.ViewPager; public class MainActivity extends FragmentActivity { private ViewPager viewPager;
public List<Fragment> fragments = new ArrayList<Fragment>();
public String hello = "hello "; @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main); fragments.add(new TabAFm());
fragments.add(new TabBFm());
fragments.add(new TabCFm());
fragments.add(new TabDFm());
fragments.add(new TabEFm()); viewPager = (ViewPager) findViewById(R.id.viewPager); FragmentViewPagerAdapter2 adapter = new FragmentViewPagerAdapter2(this.getSupportFragmentManager(), viewPager,fragments); adapter.setOnExtraPageChangeListener(new FragmentViewPagerAdapter2.OnExtraPageChangeListener(){
@Override
public void onExtraPageSelected(int i) {
System.out.println("Extra...i: " + i);
}
@Override
public void onExtraPageScrolled(int i, float v, int i2) { super.onExtraPageScrolled(i, v, i2);
}
@Override
public void onExtraPageScrollStateChanged(int i) { super.onExtraPageScrollStateChanged(i);
}
});
}
}
MainActivity上述代码所示
MainActivity是包含Fragment的Activity(也就是这里的5个Fragment)
他继承了FragmentActivity(因为我这里用的是android-support-v4.jar)
用一个List<Fragment>去维护5个Fragment,也就是5个page。
activity_main.xml
<LinearLayout 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:orientation="vertical"
tools:context=".MainActivity" > <android.support.v4.view.ViewPager
android:id="@+id/viewPager"
android:layout_width="match_parent"
android:layout_height="match_parent" /> </LinearLayout>
现在回到MainActivity中,下面这个FragmentViewPagerAdapter类是关键,是我自己编写的用于绑定和处理fragments和ViewPager之间的逻辑关系
FragmentViewPagerAdapter2 adapter = new FragmentViewPagerAdapter2(this.getSupportFragmentManager(), viewPager,fragments);
FragmentViewPagerAdapter2
package com.yydcdut.viewpagerstudy; import java.util.List; import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentTransaction;
import android.support.v4.view.PagerAdapter;
import android.support.v4.view.ViewPager;
import android.support.v4.view.ViewPager.OnPageChangeListener;
import android.view.View;
import android.view.ViewGroup; public class FragmentViewPagerAdapter2 {
private List<Fragment> fragments; // 每个Fragment对应一个Page
private FragmentManager fragmentManager;
private ViewPager viewPager; // viewPager对象
private int currentPageIndex = 0; // 当前page索引(切换之前)
private OnExtraPageChangeListener onExtraPageChangeListener; // ViewPager切换页面时的额外功能添加接口 /**
* 构造函数
*
* @param fragmentManager
* @param viewPager
* @param fragments
*/
public FragmentViewPagerAdapter2(FragmentManager fragmentManager,
ViewPager viewPager, List<Fragment> fragments) {
this.fragments = fragments;
this.fragmentManager = fragmentManager;
this.viewPager = viewPager;
// PagerAdapter
MyPagerAdapter myPagerAdapter = new MyPagerAdapter();
this.viewPager.setAdapter(myPagerAdapter);
// PageChangeListener
MyPageChangeListener myPageChangeListener = new MyPageChangeListener();
this.viewPager.setOnPageChangeListener(myPageChangeListener);
} /**
* 当前page索引(切换之前)
*
* @return
*/
public int getCurrentPageIndex() {
return currentPageIndex;
} /**
* PagerAdapter 要使用PagerAdapter,首先要继承PagerAdapter类,然后至少覆盖以下方法
* instantiateItem(ViewGroup,
* int)【这个方法,return一个对象,这个对象表明了PagerAdapter适配器选择哪个对象放在当前的ViewPager中】
* destroyItem(ViewGroup, int, Object)【这个方法,是从ViewGroup中移出当前View】
* getCount()【这个方法,是获取当前窗体界面数】 isViewFromObject(View, Object)
* 【这个方法,在帮助文档中原文是could be implemented as return view ==
* object,也就是用于判断是否由对象生成界面】
*
* @author sansung
*
*/
class MyPagerAdapter extends PagerAdapter { @Override
public Object instantiateItem(ViewGroup container, int position) {
Fragment fragment = fragments.get(position);// 取得位置,获取出来Fragment
if (!fragment.isAdded()) { // 如果fragment还没有added
FragmentTransaction ft = fragmentManager.beginTransaction();
ft.add(fragment, fragment.getClass().getSimpleName());
ft.commit();
/**
* 在用FragmentTransaction.commit()方法提交FragmentTransaction对象后
* 会在进程的主线程中,用异步的方式来执行。 如果想要立即执行这个等待中的操作,就要调用这个方法(只能在主线程中调用)。
* 要注意的是,所有的回调和相关的行为都会在这个调用中被执行完成,因此要仔细确认这个方法的调用位置。
*/
fragmentManager.executePendingTransactions();
} if (fragment.getView().getParent() == null) {
container.addView(fragment.getView()); // 为viewpager增加布局
} return fragment.getView();
} @Override
public void destroyItem(ViewGroup container, int position, Object object) {
container.removeView(fragments.get(position).getView()); // 移出viewpager两边之外的page布局
} @Override
public int getCount() {
return fragments.size();
} @Override
public boolean isViewFromObject(View arg0, Object arg1) {
return arg0 == arg1;
} } /**
* OnPageChangeListener
*
* @author sansung
*
*/
class MyPageChangeListener implements OnPageChangeListener {
/**
* 此方法是在状态改变的时候调用,其中arg0这个参数有三种状态(0,1,2)。 arg0
* ==1的时辰默示正在滑动,arg0==2的时辰默示滑动完毕了,arg0==0的时辰默示什么都没做。
*/
@Override
public void onPageScrollStateChanged(int arg0) {
if (null != onExtraPageChangeListener) { // 如果设置了额外功能接口
onExtraPageChangeListener.onExtraPageScrollStateChanged(arg0);
}
} /**
* 当页面在滑动的时候会调用此方法,在滑动被停止之前,此方法回一直得到调用。 其中三个参数的含义分别为: arg0
* :当前页面,及你点击滑动的页面 arg1:当前页面偏移的百分比 arg2:当前页面偏移的像素位置
*/
@Override
public void onPageScrolled(int arg0, float arg1, int arg2) {
if (null != onExtraPageChangeListener) { // 如果设置了额外功能接口
onExtraPageChangeListener.onExtraPageScrolled(arg0, arg1, arg2);
}
} /**
* 此方法是页面跳转完后得到调用,arg0是你当前选中的页面的Position(位置编号)。
*/
@Override
public void onPageSelected(int arg0) {
fragments.get(currentPageIndex).onPause(); // 调用切换前Fargment的onPause()
// fragments.get(currentPageIndex).onStop(); //
// 调用切换前Fargment的onStop()
if (fragments.get(arg0).isAdded()) {
// fragments.get(i).onStart(); // 调用切换后Fargment的onStart()
fragments.get(arg0).onResume(); // 调用切换后Fargment的onResume()
} currentPageIndex = arg0; if (null != onExtraPageChangeListener) { // 如果设置了额外功能接口
onExtraPageChangeListener.onExtraPageSelected(arg0);
}
}
} /**
* page切换额外功能接口
*/
static class OnExtraPageChangeListener {
public void onExtraPageScrolled(int i, float v, int i2) {
} public void onExtraPageSelected(int i) {
} public void onExtraPageScrollStateChanged(int i) {
}
} /**
* 得到页面切换额外功能监听器
*
* @return onExtraPageChangeListener
*/
public OnExtraPageChangeListener getOnExtraPageChangeListener() {
return onExtraPageChangeListener;
} /**
* 设置页面切换额外功能监听器
*
* @param onExtraPageChangeListener
*/
public void setOnExtraPageChangeListener(
OnExtraPageChangeListener onExtraPageChangeListener) {
this.onExtraPageChangeListener = onExtraPageChangeListener;
} }
这里解决Fragment切换重新加载布局的办法,用的是把几个Fragment全部Add,然后根据要显示的哪个Fragment就把哪个Fragment的View给添加到“ViewGroup container”上去。
// 以下打开程序后,加载PageA和PageB 10-12 09:42:46.671: INFO/System.out(27248): AAAAAAAAAA____onAttach
10-12 09:42:46.671: INFO/System.out(27248): AAAAAAAAAA____onCreate
10-12 09:42:46.671: INFO/System.out(27248): AAAAAAAAAA____onCreateView
10-12 09:42:46.761: INFO/System.out(27248): AAAAAAAAAA____onActivityCreated
10-12 09:42:46.765: INFO/System.out(27248): AAAAAAAAAA____onStart
10-12 09:42:46.765: INFO/System.out(27248): AAAAAAAAAA____onResume
10-12 09:42:46.847: INFO/System.out(27248): BBBBBBBBBBB____onAttach
10-12 09:42:46.847: INFO/System.out(27248): BBBBBBBBBBB____onCreate
10-12 09:42:46.851: INFO/System.out(27248): BBBBBBBBBBB____onCreateView
10-12 09:42:46.867: INFO/System.out(27248): BBBBBBBBBBB____onActivityCreated
10-12 09:42:46.867: INFO/System.out(27248): BBBBBBBBBBB____onStart
10-12 09:42:46.867: INFO/System.out(27248): BBBBBBBBBBB____onResume // 以下切换到PageB 10-12 09:42:57.285: INFO/System.out(27248): AAAAAAAAAA____onPause // 切换到PageB前会调用PageA的onPause()方法
10-12 09:42:57.285: INFO/System.out(27248): BBBBBBBBBBB____onResume // 切换到PageB后会调用PageB的onResume()方法
10-12 09:42:57.285: INFO/System.out(27248): Extra...i: 1 // 切换页面时会调用切换额外功能接口(用户可以自己写需要的逻辑)
10-12 09:42:57.582: INFO/System.out(27248): CCCCCCCCCC____onAttach // 切换到PageB后会加载PageC
10-12 09:42:57.586: INFO/System.out(27248): CCCCCCCCCC____onCreate
10-12 09:42:57.586: INFO/System.out(27248): CCCCCCCCCC____onCreateView
10-12 09:42:57.675: INFO/System.out(27248): CCCCCCCCCC____onActivityCreated
10-12 09:42:57.675: INFO/System.out(27248): CCCCCCCCCC____onStart
10-12 09:42:57.675: INFO/System.out(27248): CCCCCCCCCC____onResume // 以下切换到PageC 10-12 09:43:18.261: INFO/System.out(27248): BBBBBBBBBBB____onPause // 切换到PageC前会调用PageB的onPause()方法
10-12 09:43:18.261: INFO/System.out(27248): CCCCCCCCCC____onResume // 切换到PageC后会调用PageC的onResume()方法
10-12 09:43:18.261: INFO/System.out(27248): Extra...i: 2 // 切换页面时会调用切换额外功能接口(用户可以自己写需要的逻辑)
10-12 09:43:18.726: INFO/System.out(27248): DDDDDDDDD____onAttach // 切换到PageC后会加载PageD
10-12 09:43:18.726: INFO/System.out(27248): DDDDDDDDD____onCreate
10-12 09:43:18.726: INFO/System.out(27248): DDDDDDDDD____onCreateView
10-12 09:43:18.738: INFO/System.out(27248): DDDDDDDDD____onActivityCreated
10-12 09:43:18.738: INFO/System.out(27248): DDDDDDDDD____onStart
10-12 09:43:18.742: INFO/System.out(27248): DDDDDDDDD____onResume // 以下切换到PageB
10-12 09:43:20.742: INFO/System.out(27248): CCCCCCCCCC____onPause // 切换到PageB前会调用PageC的onPause()方法
10-12 09:43:20.742: INFO/System.out(27248): BBBBBBBBBBB____onResume // 切换到PageB后会调用PageB的onResume()方法
10-12 09:43:20.746: INFO/System.out(27248): Extra...i: 1 // 切换页面时会调用切换额外功能接口(用户可以自己写需要的逻辑)
Fragment之间的通信
现在的情况是TabAFm中有个EditText,TabBFm中有个Button,MainActivity中有个变量“hello”
要做的是,切换到A,输入“I'm PageA”,切换到B,点击Button后,Toast显示“hello I'm PageA”
MainActivity中没什么好说的,就一个hello变量:
public String hello = "hello ";
TabBFm.java:
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
System.out.println("BBBBBBBBBB____onActivityCreated");
this.getView().findViewById(R.id.clickme).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
// 获得绑定的FragmentActivity
MainActivity activity = ((MainActivity)getActivity());
// 获得TabAFm的控件
EditText editText = (EditText) activity.fragments.get(0).getView().findViewById(R.id.edit); Toast.makeText(activity, activity.hello + editText.getText(), Toast.LENGTH_SHORT).show();
}
});
}
PagerAdapter
PageAdapter是一个抽象类,直接继承于Object,导入包android.support.v4.view.PagerAdapter即可使用。
关于PageAapter的描述,原文是这样的:Base class providing the adapter to populate pages inside of a ViewPager. You will most likely want to use a more specific implementation of this, such as FragmentPagerAdapter or FragmentStatePagerAdapter。
其实PagerAdapter就是ViewPager提供的一个适配器,方便我们对各个View进行控制。那ViewPager又是什么呢?它是实现左右两个屏幕平滑地切换的一个类,具体的自己百度google…关于ViewPager的用法好多。
要使用PagerAdapter,首先要继承PagerAdapter类,然后至少覆盖以下方法
/**这个方法,return一个对象,这个对象表明了PagerAdapter适配器选择哪个对象
*放在当前的ViewPager中
**/
instantiateItem(ViewGroup, int)
/**这个方法,是从ViewGroup中移出当前View**/
destroyItem(ViewGroup, int, Object)
/**这个方法,是获取当前窗体界面数**/
getCount()
/**这个方法,在帮助文档中原文是could be implemented as return view == object,
*也就是用于判断是否由对象生成界面
**/
isViewFromObject(View, Object)
ViewPager onPageChangeListener
OnPageChangeListener这个接口需要实现三个方法:(onPageScrollStateChanged,onPageScrolled ,onPageSelected)
onPageScrollStateChanged(int arg0)
此方法是在状态改变的时候调用,其中arg0这个参数有三种状态(0,1,2)。
arg0 ==1的时辰默示正在滑动,arg0==2的时辰默示滑动完毕了,arg0==0的时辰默示什么都没做。
onPageScrolled(int arg0,float arg1,int arg2)
当页面在滑动的时候会调用此方法,在滑动被停止之前,此方法回一直得到调用。其中三个参数的含义分别为:
arg0 :当前页面,及你点击滑动的页面
arg1:当前页面偏移的百分比
arg2:当前页面偏移的像素位置
onPageSelected(int arg0)
此方法是页面跳转完后得到调用,arg0是你当前选中的页面的Position(位置编号)。
我是天王盖地虎的分割线
源代码:http://pan.baidu.com/s/1dD1Qx01
viewpager学习.zip
参考:http://www.cnblogs.com/tiantianbyconan/p/3364728.html
Android -- ViewPager、Fragment、状态保存、通信的更多相关文章
- Android ViewPager Fragment使用懒加载提升性能
Android ViewPager Fragment使用懒加载提升性能 Fragment在如今的Android开发中越来越普遍,但是当ViewPager结合Fragment时候,由于Androi ...
- Android菜鸟的成长笔记(14)—— Android中的状态保存探究(上)
原文:[置顶] Android菜鸟的成长笔记(14)—— Android中的状态保存探究(上) 我们在用手机的时候可能会发现,即使应用被放到后台再返回到前台数据依然保留(比如说我们正在玩游戏,突然电话 ...
- Android菜鸟的成长笔记(15)—— Android中的状态保存探究(下)
原文:Android菜鸟的成长笔记(15)-- Android中的状态保存探究(下) 在上一篇中我们简单了解关于Android中状态保存的过程和原理,这一篇中我们来看一下在系统配置改变的情况下保存数据 ...
- Android - ViewPager+Fragment初始化问题
Android应用开发中,经常会用到ViewPager + Fragment,虽然效果不错,但随之而来的还有一些问题,下面就说说其中的初始化问题. ViewPager初始化时会预加载前后的2个页面,即 ...
- android ViewPager+Fragment之懒加载
说说写这篇博客的背景吧,前两天去面试,问到一个问题说的是:比如我们首页,是有3个fragment构成的,并且要是实现作用可以滑,那么这个最好的选择就是ViewPager+fragment了,但是我们知 ...
- Android ViewPager + Fragment的布局
ViewPager And Fragment 1.之前有篇博客是讲ViewPager的用法的:http://www.cnblogs.com/liangstudyhome/p/3773156.html ...
- Android ViewPager+Fragment 在Activity中获取Fragment的控件
如果ViewPager+Fragment实现Tab切换,在activity中利用adapter.getItem获取到fragment然后再根据fragment.的方法获取控件 //隐藏求租,以下代码用 ...
- Android学习——Fragment与Activity通信(一)
学会了在Activity中加载Fragment的方法之后,接下来便需要学习Activity和Fragment之间的通信.这一节先学习如何把Activity中的信息传递给Fragment. 基本过程 在 ...
- Android ViewPager + Fragment实现滑动页面
效果: PagerData类: package com.cloud.viewpagerdemo; import java.io.Serializable; class PagerData implem ...
- Android Viewpager+Fragment实现滑动标签页
ViewPager 结合Fragment实现一个Activity里包含多个可滑动的标签页,每个标签页可以有独立的布局及响应. 主页布局 <?xml version="1.0" ...
随机推荐
- 表单验证插件validate
http://www.runoob.com/jquery/jquery-plugin-validate.html <!DOCTYPE html> <html lang="e ...
- BZOJ.1032.[JSOI2007]祖码(区间DP)
题目链接 BZOJ 洛谷 AC代码: 区间DP,f[i][j]表示消掉i~j需要的最少珠子数. 先把相邻的相同颜色的珠子合并起来. 枚举方法一样,处理一下端点可以碰撞消除的情况就行. 当然合并会出现问 ...
- Linux怎么开启ssh
一.查看ssh开启状态 service ssh status 这是已经开启了的状态 二.如果没有开启 键入以下命令开启 service ssh start 三.开启后如果不能利用xshell远程访问 ...
- 函数栈溢出引起的段错误segmentation fault
遇到了一个奇怪的问题: 有一个回调函数中发生了段错误,但经检查也没有什么明显的错误,然后用排除法一点一点屏蔽,最后定位在一个函数里出错,但这个函数没什么明显错误.最后把入口参数改为引用传递就不报错误. ...
- UC浏览器 垂直水平居中
今天使用下述方式定义水平垂直居中不起作用 #box{ position: fixed; left:; right:; top:; bottom:; margin: auto; } 然后改用: #box ...
- ASP.NET MVC HttpVerbs.Delete/Put Routes not firing
原文地址: https://weblog.west-wind.com/posts/2015/Apr/09/ASPNET-MVC-HttpVerbsDeletePut-Routes-not-firing ...
- C#高级编程9-第2章 核心C#
C#基础 使用C#命名编译器csc.exe,编译C#程序 变量 变量一般初始化后才能使用 类型判断弱类型var,根据初始值判断类型, 变量作用域,可以访问该代码的区域 类中定义的成员变量和属性,作用在 ...
- Spring Batch 批处理框架介绍
前言 在大型的企业应用中,或多或少都会存在大量的任务需要处理,如邮件批量通知所有将要过期的会员,日终更新订单信息等.而在批量处理任务的过程中,又需要注意很多细节,如任务异常.性能瓶颈等等.那么,使用一 ...
- js面向对象编程-高级内容
JavaScript面向对象 一.为每个对象动态添加属性或方法 功能:返回对象类型原型的引用 prototype的使用 格式:class.prototype 场景: 比如说:A写了一个类,交给B,B在 ...
- [Node.js]Path模块
摘要 path模块提供了一些处理文件路径问题的工具. path模块 引入模块 var path=require("path"); 方法 1 path.normalize(p)规范化 ...