Fragment 和 ViewPager 基础

您所在的位置:网站首页 viewpager重新加载 Fragment 和 ViewPager 基础

Fragment 和 ViewPager 基础

2023-03-22 02:27| 来源: 网络整理| 查看: 265

Fragment

Fragment 可以有自己独立的事件处理和生命周期 , fragment最初是为了大屏幕显示而设计, 有了fragment后手机和平板兼容就容易了, 比如平板上 Activity A 包含 FragmentA 和 FragmentB , 手机上就可以ActivityA 包含FragmentA ; ActivityB包含FragmentB ; 就不用重新在手机上大改布局文件, 只需要小改… fragment 可以包含到多个Activity中

使用fragment需要先定义一个类, 继承Fragment 并实现其onCreateView()方法 , Fragment第一次绘制其用户界面的时候,系统会调用该方法, 为了绘制fragment的UI该方法必须返回一个View, 如果不显示UI, 返回null即可

静态和动态加载

Fragment静态加载: 就是在layout的xml文件中有定义 标签

在Activity的layout文件中声明Fragment , fragment的name属性, 指定了layout实例化的Fragment类 必须有标示, id属性唯一id 或 tag属性唯一字符串

Fragment动态加载: Activity的layout布局文件中没有定义fragment控件, 而是在Activity中用代码加载

但无论是静态还是动态 , 都需要有自定义的fragment类和这个fragment对应的layout文件 并且这个fragment类里面需要重写onCreateView方法, 返回view , 一般是把layout转换为view返回

@Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view = inflater.inflate(R.layout.fragment1, container); TextView tv = (TextView) view.findViewById(R.id.id_fragment1_tv); tv.setText("fragment 1 text"); Button btn = (Button) view.findViewById(R.id.id_fragment1_btn); btn.setText("btnOfFragment1"); return view; }

有了fragment类后, 动态加载需要fragment事务来加载到Activity 对fragment进行添加移除替换和其他动作, 提交给Activity的每一套变化称为事务

另外, 动态加载fragment最终还是把fragment加载到某个指定ID的layout

//动态加载fragment到ID为id_fram的LinearLayout中 Fragment fragment = new MyFragment2(); FragmentManager manager = getFragmentManager(); FragmentTransaction beginTransaction = manager.beginTransaction();//开启事务 beginTransaction.add(R.id.id_frame, fragment); //把fragment加载到指定ID的layout中 beginTransaction.addToBackStack(null);//fragment添加到返回栈 beginTransaction.commit();

每个事务都是一套变化 , 包括add() remove() replace() 然后提交给Activity, 必须调用commit() 方法 如果允许用户通过按下back返回到前一个fragment状态, 调用commit之前可以加入addToBackStack()方法

Fragment和Activity通信

1 fragment可以调用getActivity方法获取它所在的Activity 2 Activity可以调用FragmentManager的findFragmentById() 或findFragmentByTag()方法获取Fragment

Activity –> Fragment :

在Activity中创建Bundle数据包, 并调用Fragment的setArguments(Bundle bundle) 方法

Fragment –> Activity : 需要在 Fragment中定义一个内部回调接口, 再让包含该Fragment的Activity实现该回调接口. 这样在Fragment类中可以调用该回调方法将数据传递给Activity

Activity 传值给 Fragment : //Activity端 @Override public void onClick(View v) { String data = tv_data.getText().toString(); //Activity中准备bundle数据 MyFragment4 myFragment4 = new MyFragment4(); Bundle bundle = new Bundle(); bundle.putString("data", data); //加载fragment前, 调用fragment对象的setArguments方法传递数据 myFragment4.setArguments(bundle); //和往常一样动态加载fragment到某个控件 FragmentManager manager = getFragmentManager(); FragmentTransaction beginTransaction = manager.beginTransaction(); beginTransaction.replace(R.id.id_activity4_layout,myFragment4); beginTransaction.addToBackStack(null); beginTransaction.commit(); Toast.makeText(Activity4.this, "Activity 发送数据给Fragment4:" + data, Toast.LENGTH_SHORT).show(); } });

//Fragment类中onCreateView方法中获取数据

@Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { // inflater将布局文件转换为view View view = inflater.inflate(R.layout.fragment4, container, false); ... .... //获取Activity传递的数据; Bundle bundle = getArguments(); String txt = bundle.get("data").toString() ; Toast.makeText(getActivity(), "fragment 接收到数据:"+txt, Toast.LENGTH_SHORT).show(); return view; } Fragment传值给Activity

fragment中定义接口, 然后activity实现接口方法, fragment中onAttach 重写的时候, 把activity转换为接口实现对象, fragment中在合适的地方调用activity强转接口对象中的方法 , 并传值, 于是实现fragment传递数据给activity

Fragment 类中:

public class MyFragment4 extends Fragment { //定义接口 public interface MyListener { public void thankyou (String str); } //定义接口对象 MyListener mListener; ... //复写onAttach方法时将实现了接口方法的activity强转并赋值给接口对象 @Override public void onAttach(Activity activity) { mListener = (MyListener) activity; super.onAttach(activity); } //在需要调用接口方法, 传值的时候调用接口方法 @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { // TODO Auto-generated method stub View view = inflater.inflate(R.layout.fragment4, container, false); ... Bundle bundle = getArguments(); String txt = bundle.get("data").toString() ; Toast.makeText(getActivity(), "fragment 接收到数据:"+txt, Toast.LENGTH_SHORT).show(); //比如收到数据后, 返回一条确认字符串 mListener.thankyou(code); return view; }

//Activity中:

public class Activity4 extends Activity implements MyListener{ ... ... ... //通过实现接口方法, 让fragment调用接口方法来实现fragment向Activity传值 @Override public void thankyou(String str) { Toast.makeText(Activity4.this, "Activity 接收到数据" + str, Toast.LENGTH_SHORT).show(); } } activity传值给静态加载的fragment

Activity 的layout文件中有fragment字段, 静态加载MyFragment这个类的话

Fragment类中:

我们在MyFragment类中, 对需要传值的字段设置好getter , setter

public class MyFragment1 extends Fragment { private String testField; public String getTestField() { return testField; } public void setTestField(String testField) { this.testField = testField; } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view = inflater.inflate(R.layout.fragment1, container); TextView tv = (TextView) view.findViewById(R.id.id_fragment1_tv); tv.setText("fragment 1 text 静态加载"); Button btn = (Button) view.findViewById(R.id.id_fragment1_btn); btn.setText("btnOfFragment1"); btn.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { String data = getTestField(); Toast.makeText(getActivity(), "testField 现在的值为:" + data, Toast.LENGTH_SHORT).show(); } }); return view; } }

Activity中:

FragmentManager fragmentManager = getFragmentManager(); Fragment fragment = fragmentManager.findFragmentById(R.id.id_activity4_staticFrag); MyFragment1 myfragment1 = (MyFragment1) fragment; myfragment1.setTestField("测试传值给fragment");

Fragment类中 调用 getXxx() 方法即可得到Activity传递过来的数据

ViewPager

类: android.support.v4.view.ViewPager

加载显示的页卡, 页卡可以使view对象也可以使fragment对象

将layout布局文件转换为view对象的方法: 1 LayoutInflater LayoutInflater lf = getLayoutInflater().from(this); lf.inflate(resource,root);

2 View.inflate View.inflate(context,resource,root);

配置Adapter 数据源可以使view也可以使fragment 1. PagerAdapter 数据源List 2. FragmentPagerAdapter 数据源 List 3. FragmentStatePagerAdapter 数据源 List

view 作为页卡 , 最简单的viewPager

//main.xml

Activity

//MainActivity.java public class MainActivity extends Activity { private List viewList; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); viewList = new ArrayList(); /*** - view 对象作为数据源 */ View view1 = View.inflate(this, R.layout.view1, null); View view2 = View.inflate(this, R.layout.view2, null); View view3 = View.inflate(this, R.layout.view3, null); View view4 = View.inflate(this, R.layout.view4, null); viewList.add(view1); viewList.add(view2); viewList.add(view3); viewList.add(view4); //创建pager对象 ViewPager pager = (ViewPager) findViewById(R.id.id_pager); //加载适配器 MyPagerAdapter adapter = new MyPagerAdapter(viewList); pager.setAdapter(adapter); } }

//MyPagerAdapter

package com.example.imooc_viewpager; import java.util.List; import android.support.v4.view.PagerAdapter; import android.view.View; import android.view.ViewGroup; public class MyPagerAdapter extends PagerAdapter { List mViewList ; public MyPagerAdapter(List viewList) { mViewList = viewList; } /** - 返回页卡数量 */ @Override public int getCount() { // TODO Auto-generated method stub return mViewList.size(); } /*** - 判断view 是否来自对象 */ @Override public boolean isViewFromObject(View arg0, Object arg1) { // TODO Auto-generated method stub return arg0 == arg1; } /** - 实例化一个页卡 , viewpager一般是前, 后, 当前页卡, 一共3个页卡为单位的去操作 */ @Override public Object instantiateItem(ViewGroup container, int position) { // return super.instantiateItem(container, position); container.addView(mViewList.get(position)); return mViewList.get(position); } /*** - 销毁一个页卡 , 需要从viewGroup中移除一个view */ @Override public void destroyItem(ViewGroup container, int position, Object object) { container.removeView(mViewList.get(position)); } } 加入页卡标题

1 XML文件中 , 加入PagerTabStrip 控件

//设置tabStrip在顶端显示

2 Activity中准备标题数据

private List titleList; titleList = new ArrayList (); titleList.add("第一页"); titleList.add("第二页"); titleList.add("第三页"); titleList.add("第四页");

3 自定义的MyPagerAdapter 类中实现getPageTitle 方法

//构造函数中传递titleList List mViewList ; List mTitleList; public MyPagerAdapter(List viewList , List titleList) { mViewList = viewList; mTitleList = titleList; } ...... /** * 设置页卡标题 */ @Override public CharSequence getPageTitle(int position) { return mTitleList.get(position); }

4 设置属性

//为tabStrip 设置属性 tabStrip = (PagerTabStrip) findViewById(R.id.id_pager_tabStrip); tabStrip.setBackgroundColor(Color.YELLOW); //背景色 tabStrip.setTextColor(Color.RED); //文字颜色 tabStrip.setDrawFullUnderline(false); //去掉长的下划线 tabStrip.setTabIndicatorColor(Color.GREEN); //设置当前单项粗点的线的颜色

类似PagerTabStrip的还有PagerTitleStrip

使用Fragment作为Pager数据源

1 XML文件中 , 加入PagerTabStrip 控件

//设置tabStrip在顶端显示

2 创建Fragment类 , 注意使用的包 android.support.v4.app.Fragment; 兼容3.0以下版本

public class Fragment1 extends Fragment { @Override @Nullable public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { return inflater.inflate(R.layout.view1, container, false); } }

定义4个这样的fragment分别加载4个不同的layout文件

3 自定义FragmentPagerAdapter类

import java.util.List; import android.support.v4.app.Fragment; import android.support.v4.app.FragmentManager; import android.support.v4.app.FragmentPagerAdapter; /*** * FragmentPagerAdapter 和 PagerAdapter加载的时候不同的是, * FragmentPagerAdapter 会一次把所有的fragment都加载进来, 而不是三个三个地加载 * @author hendry-code * */ public class MyFragmentPagerAdapter extends FragmentPagerAdapter { private List mFragList; private List mTitleList; public MyFragmentPagerAdapter(FragmentManager fm, List fragList, List titleList) { super(fm); mFragList = fragList; mTitleList = titleList; } @Override public Fragment getItem(int arg0) { // TODO Auto-generated method stub return mFragList.get(arg0); } @Override public int getCount() { // TODO Auto-generated method stub return mFragList.size(); } @Override public CharSequence getPageTitle(int position) { return mTitleList.get(position); } }

4 修改Activity文件, 使用fragmentAdapter

private List fragList; ... /** * Fragment 作为数据源 */ fragList = new ArrayList(); fragList.add(new Fragment1()); fragList.add(new Fragment2()); fragList.add(new Fragment3()); fragList.add(new Fragment4()); titleList = new ArrayList (); titleList.add("第一页"); titleList.add("第二页"); titleList.add("第三页"); titleList.add("第四页"); //创建pager对象 pager = (ViewPager) findViewById(R.id.id_pager); //为tabStrip 设置属性 tabStrip = (PagerTabStrip) findViewById(R.id.id_pager_tabStrip); tabStrip.setBackgroundColor(Color.YELLOW); tabStrip.setTextColor(Color.RED); tabStrip.setDrawFullUnderline(false); //去掉长的下划线 tabStrip.setTabIndicatorColor(Color.GREEN); //设置当前单项粗点的线的颜色 MyFragmentPagerAdapter fragmentAdapter = new MyFragmentPagerAdapter(getSupportFragmentManager(), fragList, titleList); pager.setAdapter(fragmentAdapter);

由于使用Fragment 是v4兼容包的Fragment, 所以 , FragmentPagerAdapter 的构造函数中需要一个fragmentManager 不能通过 getFragmentManager()来获得, 我们需要getSupportFragmentManager() ; 为了使用这个兼容包, 我们还需要把Activity改为继承自FragmentActivity.

使用FragmentStatePagerAdapter

FragmentPagerAdapter 是一次性加载所有的页卡, 没有动态添加销毁的功能 , 验证方法 , 在第四个fragment 销毁的时候打印LOG, 然后测试切换, 发现LOG没有打印

public class Fragment4 extends Fragment { @Override @Nullable public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { return inflater.inflate(R.layout.view4, container, false); } @Override public void onDestroy() { // TODO Auto-generated method stub super.onDestroy(); Log.i("main","Fragment4 destoryed...."); } }

所以如果页卡很多的话FragmentPagerAdapter就不适合了, 我们需要另外一个有动态添加销毁功能的 FragmentStatePagerAdapter 把adapter的定义头部改一下, 并复写创建和销毁方法 , 但这两个方法不用去改什么, 原样就可以了

public class MyFragmentPagerAdapter2 extends FragmentStatePagerAdapter { ... ... @Override public Object instantiateItem(ViewGroup arg0, int arg1) { // TODO Auto-generated method stub return super.instantiateItem(arg0, arg1); } @Override public void destroyItem(ViewGroup container, int position, Object object) { // TODO Auto-generated method stub super.destroyItem(container, position, object); } ... } Activity文件中: MyFragmentPagerAdapter2 fragmentAdapter2 = new MyFragmentPagerAdapter2(getSupportFragmentManager(), fragList, titleList); pager.setAdapter(fragmentAdapter2);

然后再模拟器上测试, 就发现从第三页切换到第二页的时候, 第四页的销毁LOG就被打印出来了, 说明FragmentStatePagerAdapter适配器是会动态维护创建销毁的

ViewPager 监听器 OnPageChangeListener

1 类定义的头文件 public class MainActivity extends FragmentActivity implements OnPageChangeListener {

2 完成接口方法, 主要是onPageSelected

@Override public void onPageScrollStateChanged(int arg0) { // TODO Auto-generated method stub } @Override public void onPageScrolled(int arg0, float arg1, int arg2) { // TODO Auto-generated method stub } @Override public void onPageSelected(int arg0) { // TODO Auto-generated method stub Toast.makeText(this, "当前是第" + (arg0 + 1) + "页面",Toast.LENGTH_SHORT).show(); }

3 OnCreate方法中 绑定Listener , pager.setOnPageChangeListener(this);

因为Fragment有完整的生命周期, 更好控制, 一般使用fragment + viewPager组合比较多…..



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3