Fragment

 阅读过程中有疑惑的地方:

  • inflate方法的第三个参数,为true和false时,到底有何区别;
  • FragmentTransaction的replace方法,到底是怎么个替换法?是把当前view中所有fragment都替换掉,还是只替换id相同的fragment;
  • FragmentTransaction的addToBackStack()方法,是返回上一次状态,但是为何平板上面实际操作的时候是直接退出了activity;
  • padding的单位,按我的理解,只能是像素吧;
  •  

  发现了一个自适应计算的方法:TypedValue.applyDimension,方法源码如下:

 

 1 public static float applyDimension(int unit, float value,
 2                                        DisplayMetrics metrics)
 3     {
 4         switch (unit) {
 5         case COMPLEX_UNIT_PX:
 6             return value;
 7         case COMPLEX_UNIT_DIP:
 8             return value * metrics.density;
 9         case COMPLEX_UNIT_SP:
10             return value * metrics.scaledDensity;
11         case COMPLEX_UNIT_PT:
12             return value * metrics.xdpi * (1.0f/72);
13         case COMPLEX_UNIT_IN:
14             return value * metrics.xdpi;
15         case COMPLEX_UNIT_MM:
16             return value * metrics.xdpi * (1.0f/25.4f);
17         }
18         return 0;
19     }

 

  根据当前value以及单位、屏幕密度来动态计算,返回的值是计算过后的实际像素。

  实例:

 

1  int padding = (int)TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
2                     4, getActivity().getResources().getDisplayMetrics());
3  text.setPadding(padding, padding, padding, padding);

 

  dp实际上可以理解成一个相对的比例,比如若在mdpi、分辨率是480x800的屏幕上面,一个宽240dp的按钮,实际像素是240px,占了屏幕的1/2;那么在ldpi、分辨率是320x480的屏幕上面,它也要占屏幕的1/2,但是button的像素只有160px了。

  阅读完以后的总结:

  • 设计原则,为什么要用fragment
  • 创建方式,包括两种,一种是通过xml文件夹,另外一种是在代码中添加
  • 如何管理
  • 与activity如何交互

 

一、设计原则
  fragment是为了使大屏幕的界面更加灵活而产生,将UI抽象成可重用的组件,然后在界面上灵活使用。最常见的用法是在横竖屏切换、或者平板与手机共用同一个apk的时候,如下图:

Fragment - 笨小孩 - 我要当地主

 

 

 

应用场景1

  个人理解:平板横屏的时候,可以将左侧的列表和右侧的详细信息同时展现出来;竖屏的时候宽度不够,那么只是单独展示列表或者详细信息。常规的做法是需要针对这种方式分别写上3个activity.那么使用fragment后,将列表抽象成一个共用的fragment,详细信息也抽象成一个公用的fragment,横屏的布局文件中包含两个fragment,竖屏的只包含一个fragment,但是共用同一个activity A的代码。需要做的判断是在点左侧列表中一个选项的时候,是在右侧更新内容还是另起一个activity来展示。另起的activity B 只要将fragment B包含进去即可,并不需要新增很多再处理的代码,这样就达到了一个重用的效果。

 

二、创建

 

  fragment的生命周期是受其依附的activity影响,当activity暂停或者停止时,fragment也会同时达到相应的状态。当activity出于运行状态时,fragment才会进入自由的一个生命周期。

 

  其中,比较重要的生命周期方法包括:

  • onCreateView:在onCreate之后,用于返回fragment的根视图对象,一般使用InflateLayout.inflate方法,从xml资源文件转换成View对象。
  • onActivityCreated:在其依附的activity的onCreate方法成功返回后触发,用于做进一步操作,比如创建一个接口用于回调给activity,这时候可以检验activity是否实现了该接口。
  1. 创建方式

 

  包括两种,一种是直接在xml文件中做配置:  

 1 <?xml version="1.0" encoding="utf-8"?>
 2 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
 3     android:orientation="horizontal"
 4     android:layout_width="match_parent"
 5     android:layout_height="match_parent">
 6     <fragment android:name="com.example.news.ArticleListFragment"
 7             android:id="@+id/list"
 8             android:layout_weight="1"
 9             android:layout_width="0dp"
10             android:layout_height="match_parent" />
11     <fragment android:name="com.example.news.ArticleReaderFragment"
12             android:id="@+id/viewer"
13             android:layout_weight="2"
14             android:layout_width="0dp"
15             android:layout_height="match_parent" />
16 </LinearLayout>

  其中的name属性实际就是具体指定fragment的实例,id和tag两个属性都可以用来标识fragment,但是一般用id;若是无界面的fragment,则用tag来标识。

  另外一种是在代码中动态的添加:  

1 FragmentManager fragmentManager = getFragmentManager()
2 FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
3 fragmentTransaction.add(R.id.replace);

   其中的R.id.fragment_container可以看作成是定义好的fragment容器,也即是xml中定义的fragment节点,但是没有指定过name或者class属性;是否也可以看作成一个任意的ViewGroup对应的资源Id?两者取其一还是都可以? 

 

  2. 管理fragment

  主要是通过FragmentManager对象来操作,主要负责:

  • 创建transaction,进行fragment的添加、删除、替换等事物操作;
  • 查找fragment,这个fragmentManager对象的引用是否依附于activity中的,通过getFragmentManager()方法可以直接获取该对象。通过findFragmentById获取findFragmentByTag来查找当前activity下存在的fragment;
  • 执行返回键的操作,出栈已存放的fragment事物;

  transaction提交之前的所有添加删除操作看成一个事物,当调用addToBackStack方法后,会将之前所有发生的改变看作一次改变,再返回回来的时候,是展示所有这改变之前的状态。

  3. 与activity进行交互

  fragment毕竟是独立出来的组件,那么fragment中发生的操作如何让activity也捕捉到呢?activity又如何向fragment传送值呢?

  让activity捕捉到,无非就是在fragment中触发某种操作后,比如点击按钮后,然后fragment通知activity,然后activity再做出相关的响应。那么fragment如何在恰当的时候通知activity呢?sdk中提供了一种做法,在fragment中定义了一个接口,里面定义了一个方法;然后在onAttach时,判断当前依附的activity有没有实现该接口,同时引用已经实现了该接口的activity对象,用来强制实现;在fragment的比如button事件中,直接调用该引用的注册方法,通知activity来做处理。如下:

public class Fragment_A extends Fragment{

  private OnChangedListener m_Listener;

   public interface OnChangedListener{
     public void onChanged(int index); 
  }  

  @Override
  public void onAttach(Activity activity){
      super.onAttach(activity);
      try{
          m_Listener=(OnChangedListener)activity;
      }catch(ClassCastException ex){
      throw new ClassCastException(activity.toString() + " 必须实现OnChangedListener!");
  }
  
}

  Activity实现了OnChangedListener就可以接收到对应的事件,这个是不是就是传说中的监听者模式。

  那么activity如何向fragment传递数据呢?

  Fragment类包括两个方法:setArguments和getArguments。setArguments方法必须在fragment attach到activity之前调用,参数是Bundle对象;然后在fragment中调用getArguments方法,获取该fragment实例化时传递进来的Bundle对象。

  4.保存状态

  fragment的生命很大程度上会受到其依附的activity的映像,因此为了保证数据完整性,也需要在适当的时候保存下当前状态:

1   @Override
2         public void onSaveInstanceState(Bundle outState) {
3             super.onSaveInstanceState(outState);
4             outState.putInt("curChoice", mCurCheckPosition);
5         }

   然后当该fragment再次被重新创建的时候,恢复之前保存的数据:

1  @Override
2         public void onActivityCreated(Bundle savedInstanceState) {
3             super.onActivityCreated(savedInstanceState);
4 
5              if (savedInstanceState != null) {
6                 // Restore last state
7             }
8         }

 总结:

  •   fragment的使用能够让UI更灵活
  •   感觉如何管理fragment是个关键

其中,图片引用自 android sdk官网,转载请说明出处~~

看不清未来,那就看脚下。
原文地址:https://www.cnblogs.com/caiwan/p/2875306.html