zoukankan      html  css  js  c++  java
  • 【转】 Pro Android学习笔记(三九):Fragment(4):基础小例子-续

    目录(?)[-]

    1. Step 3实现简介显示类DetailFragment
      1. 创建实例
      2. 编写所需的生命周期代码
    2. Step 4实现showDetailint index如何管理fragment
      1. fragment的切换
      2. 回退堆栈back stack

    Step 3:实现简介显示类DetailFragment

    在Activity的布局xml中,对DetailFragment并没有指定class属性,故在setContentView()中不会自动调用该类,而是通过编写showDetail(int index)来调用,该函数的具体编码以后在描述,我们先来看看DetailFragment类的实现。

    创建实例

    在TitleFragment中,通过在xml中指定class属性来调用fragment。而对于右边部分,则是定义了FrameLayout容器,因此需要通过代码来创建实例。下面是通用的建议代码,通过静态函数来创建实例,并设置参数。当fragment被保存并重构时,系统回调用缺省的构造函数,并接着重新获取初始化参数。

    public class DetailFragment extends Fragment{  
        //以静态函数的方式,通过指定书名序号,来获取实例,并将书名序号通过setArguments()方式设为给fragment的参数  
        public static DetailFragment newInstance (int index)
    {  
            //1、创建fragment实例 
            DetailFragment df = new DetailFragment(); 
           //2、设置fragment的参数,在fragment中可以通过getArguments()来获取
            Bundle args = new Bundle(); 
            args.putInt("index", index); 
            df.setArguments(args);  
            return df; 
        } 
        //通过bundle方式携带书名序号,来获取实例 
        public static DetailFragment newInstance (Bundle bundle)
            int index = bundle.getInt("index"); 
            return newInstance(index); 
        }  
        … 略 … 
    }

    可以通过setArguments()来设置参数,对于fragment的生命周期而言,必须在fragment完成与activity关联之前设置参数。即必须在onAttach(之前进行,即在构造阶段或者onInflate。不是每个fragment都有onInflate状态,例如DetailFragment,不是通过xml的<fragment>进行构造,故没有onInflate状态。

    编写所需的生命周期代码

    实际上并不需要对每个生命周期都进行代码编写。由于在xml中没有指定class,不是activity中通过setContentView()来调用,因此没有经历onInflate()状态,而是从onAttach()开始。我们需要的是为fragment创建view布局,并具体填入信息,可以在onCreateView()和onActivityCreated()中实现。

    public class DetailFragment extends Fragment{ 
        private int mIndex = 0; 
         
       ... 略 … 

        @Override //在生命周期的早期onCreate(),获取参数(书名序号)
        public void onCreate(Bundle savedInstanceState) { 
            super.onCreate(savedInstanceState); 
            mIndex = getArguments().getInt("index",0); //在创建实例过程中将index设置为参数,可以在任何生命周期中获取,此处只为了使用方面进行提取。为何我们不直接newInstance()中将mIndex=index,而是设置成为参数,我们需要考虑到fragment recreate的情况,例如屏幕转向。此时,系统将调用缺省的构造函数,不会执行newInstance()代码,但在onCreate()我们仍可从参数中获取index。
        } 

        public int getShowIndex(){ 
            return mIndex; 
        }  
              
        @Override //在onCreateView中创建view层级,并返回。LayoutInflater可用于inflate布局。如果ViewGroup非空,则可以通过infalte()来获取布局,如果为null,说明没有viewGroup容器可以关联,在此所设置的,不会在UI中真正显示。
        public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
    {
            if(container == null)
                return null;

           //1、根据xml的布局文件创建view层级并将之返回。注意:第3个参数为false,不要将view和viewGroup进行关联,系统会自动进行,否则会出现异常。 
            View v = inflater.inflate(R.layout.details, container,false);
           //2、设置层级中的view 
            TextView tv = (TextView)v.findViewById(R.id.text1); 
            tv.setText(BooksInfo.DIALOGUE[mIndex]); 
            return v;  
        } 
    }

    在onCreateView中,返回的是View hierarchy,这和参数ViewGroup contianer是什么关系。其实这两者都是容器。一个表示fragment所占的空间的parent容器,就是XML文件中的FrameLayout;一个表示填充这个空间的child容器,图示如下:

    这个用于填充FrameLayout的子容器布局很简单,下面为details.xml文件。注意,我们并不需要在代码中将子容器放入FrameLayout中,系统会自动完成,如果我们将两者关联,反而会出现异常。

    <?xml version="1.0" encoding="utf-8"?> 
    <LinearLayout …. > 
        <ScrollView android:id="@+id/scroller" android:layout_width… > 
            <TextView android:id="@+id/text1"   android:layout_width… /> 
        </ScrollView> 
    </LinearLayout>

    Step 4:实现showDetail(int index),如何管理fragment

    fragment的切换

    右边的fragment在用户点击不同书目时进行切换。一个fragment必须在某个view容器中,即onCreateView中的ViewGroup。在XML中,我们设置了FrameLayout作为fragment的容器,因为FrameLayout比其他的简单。在容器中可以进行fragment的切换。通过FragmentTranscation可以替换当前UI。FragmentTransaction是Fragment操作的API接口集合。相关代码如下:

    public class FragmentBasicTest extends Activity{ 
        ... 略 …       
        public void showDetails(int index){  
           //【1】、获取当前与FrameLayout相关的fragment的对象。对fragment进行处理需要通过fragment管理器,FragmentManager可以通过 Activity的getFragmentManager()和Fragment的getFragmentManager()来获取,通过管理器,可以获得fragement transaction,根据id,tag获取fragment。
            DetailFragment detail = (DetailFragment)getFragmentManager().findFragmentById(R.id.details); 
            //【2】、如果fragment对象不存在(第一次创建)或者书目变更,将进行切换

            if(detail == null || detail.getShowIndex() != index ){  
                // 2.1)创建先的fragemnt对象 
                detail = DetailFragment.newInstance(index);  
                // 2.2)beginTransaction()有点词不达意,并不是说要获取第一个Transaction,Transaction没有分第几个,它是进行Fragment操作的API接口集合。beginTransaction()是说明要通过Fragment管理器对fragment进行编辑,编辑完后通过commit()进行确认。 
                FragmentTransaction ft = getFragmentManager().beginTransaction(); 
                // 编辑的内容是replace():在FrameLayout中替换现有的UI。具体为replace(int containerId, Fragment fragment<, String tag>); tag是fragment的可选属性,不设置即为null。
                ft.replace(R.id.details, detail);  
                ft.commit();
      
            }  
        } 

    }

    到此,我们已经完成了对fragment的基础小例子。

    回退堆栈back stack

    我们点击返回键,将退出activity。但是有时我们会希望,右边的fragment能退回到上一次点击的书目简介。在编写相关代码之前,我们跟踪一下小例子目前右边fragment的生命周期。

    利用FragmentTrasaction,将新的fragment对象加入back stack中,当用户按回退键时,从back stack中pop出fragment对象,实现回退效果。back stack由fragment管理器管理,代码如下:

        public void showDetails(int index){  
            DetailFragment detail = (DetailFragment)getFragmentManager().findFragmentById(R.id.details); 
            if(detail == null){  
                addFirstFragment(index);  
            }else if(detail.getShowIndex() != index ){  
                addFragmentToStack(index);  
            }  
        } 
        
        private void addFirstFragment(int index){ 
            DetailFragment detail = DetailFragment.newInstance(index);
            FragmentTransaction ft = getFragmentManager().beginTransaction(); 
            ft.replace(R.id.details, detail); 
            ft.commit();    
        } 
         
        private void addFragmentToStack(int index){ 
            DetailFragment detail = DetailFragment.newInstance(index); 
            FragmentTransaction ft = getFragmentManager().beginTransaction();  
            ft.replace(R.id.details, detail); 
            ft.addToBackStack(null);  //加入回退堆栈,将原有(准备被替换)的fragment加入堆栈。经过跟踪,貌似也将新的fragment进行保存,但是并不会进行回退显示,回退时进行Destroy,除非下一次,作为原有fragment加入堆栈。(这里的说法有些罗嗦和含混,如果我们考虑每次到加入回退堆栈可以处理,但是如果某次加入,某次不加入,跟踪状态,就很清楚)
            ft.commit(); 
        }

    我们同样跟踪一下现在小例子的运行情况。

    如果我们不区分是否第一次,均使用addFragmentToStack,即在第一次,也执行ft.addToBackStack(null)。将原有的(准备被替换)的fragment加入堆栈,即将null加入堆栈,在回退时,最后增加回退一步,回退到一个空白的fragment,非吾等所期。

    按返回键,fragment回退,仍然在同一个activity中,直至回退堆栈为空。

    本博文涉及的例子代码,可以在Pro Android学习:Fragment中下载。

    相关链接: 我的Android开发相关文章

  • 相关阅读:
    div布局的几点体会
    DIV高度的问题
    想修改CSS
    如何在EXCEL SHEET中 动态添加控件
    div的背景设置的问题
    CSS的资源
    远程调试
    Javascript跨域访问解决方案 Leone
    再谈PHP开发者常犯的10个MySQL错误 Leone
    开发人员需要熟知的常用Linux命令之八:Version、Kernel查看 Leone
  • 原文地址:https://www.cnblogs.com/blongfree/p/5047976.html
Copyright © 2011-2022 走看看