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" ...
随机推荐
- map赋值前要先初始化:assignment to entry in nil map
注意这种map的嵌套的形式,make只初始化了map[string]T部分(T为map[int]int),所以下面的赋值会出现错误: test := make(map[string]map[int]i ...
- 【BZOJ 1415】 1415: [Noi2005]聪聪和可可 (bfs+记忆化搜索+期望)
1415: [Noi2005]聪聪和可可 Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 1640 Solved: 962 Description I ...
- BZOJ.4316.小C的独立集(仙人掌 DP)
题目链接 \(Description\) 求一棵仙人掌的最大独立集. \(Solution\) 如果是树,那么 \(f[i][0/1]\) 表示当前点不取/取的最大独立集大小,直接DP即可,即 \(f ...
- python开发_thread_线程基础
说到线程,我们要知道啥是串行,啥是并行程序 举个例子: 串行程序,就是一个一个的执行程序 #python threading import time ''' 每一秒中,输出:this is a dem ...
- python开发_xml.dom_解析XML文档_完整版_博主推荐
在阅读之前,你需要了解一些xml.dom的一些理论知识,在这里你可以对xml.dom有一定的了解,如果你阅读完之后. 下面是我做的demo 运行效果: 解析的XML文件位置:c:\\test\\hon ...
- centos7安装kafka_2.11-1.0.0 新手入门
系统环境 1.操作系统:64位CentOS Linux release 7.2.1511 (Core) 2.jdk版本:1.8.0_121 3.zookeeper版本:zookeeper-3.4.9. ...
- 字符串转码【String.getBytes()和new String()】
在Java中,String.getBytes(String decode)方法会根据指定的decode编码返回某字符串在该编码下的byte数组表示,如 byte[] b_gbk = "中&q ...
- [Intervention] Unable to preventDefault inside passive event listener due to target being treated as passive. See https://www.chromestatus.com/features/5093566007214080
相信如果用谷歌浏览器做移动端页面的时候 用touch事件的时候应该遇到过这个东东吧 documet.addEventListener("touchstart",function() ...
- Apache Mina入门
Mina第一次听到这个名称的时候,我以为是个MM的名字米娜,后来才知道… Apache MINA(Multipurpose Infrastructure for Network Application ...
- C# 转换图形为PCX 格式
2010-5-27 PCX RLE压缩图形的行对齐比.NET多了一位.已经修正了. 2009 -7-25 C# 转换图形为PCX 格式 增加了对1位色的PCX的读取 2009-6 -12 RLE数据压 ...