關於Fragment的動態添加的相關疑問及解答

今天在網上看到了一個開源庫:Spruce Android Animation Library (and iOS)javascript

也就是
html

你們會說這個關Fragment的什麼事,別急,聽我慢慢來講。java


咱們來能夠下載它的Demo文件:android

上面Gif的圖片裏面的界面,是RecyclerActivity.java,而他引用的佈局是recycler_fragment.xmlgit

咱們先來看佈局文件recycler_fragment.xmlgithub

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              android:id="@+id/recycler_fragment"
              android:orientation="vertical"
              android:layout_width="match_parent"
              android:layout_height="match_parent">

    <android.support.v7.widget.Toolbar android:id="@+id/recycler_tool_bar" android:layout_width="match_parent" android:layout_height="wrap_content" android:theme="@style/LightToolbarTheme" android:background="@color/colorPrimary"/> <android.support.v7.widget.RecyclerView android:id="@+id/recycler" android:layout_width="match_parent" android:layout_height="match_parent" /> </LinearLayout>複製代碼

沒錯,你們一看就知道,和上面的Gif圖顯示的同樣,一個ToolBar,而後下面一個RecycleView,外面的ViewGroup是LinearLayout。app

原本是沒什麼問題的,可是我發現,他在這個界面加了一個Fragment。ide

在activity裏面的onCreate方法中:佈局

@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    setContentView(R.layout.recycler_fragment);

    FragmentManager fm = getSupportFragmentManager();
    Fragment recyclerFragment = fm.findFragmentById(R.id.recycler_fragment);
    if (recyclerFragment == null) {
        recyclerFragment = RecyclerFragment.newInstance();
        fm.beginTransaction()
                .replace(R.id.recycler_fragment, recyclerFragment)
                .commit();
    }

  ......
  ......
  ......
}複製代碼

沒錯,他把這個Fragment,經過replace(R.id.recycler_fragment, recyclerFragment).commit(),添加到了id 爲R.id.recycler_fragmnt處,而這個R.id.recycler_fragmnt就是咱們上面的activity佈局中的最外面的LinearLayout。WHAT!!!不是通常都是加到FrameLayout中的嗎???spa


因此咱們的問題1:若是動態添加Fragment加到LinearLayout,RelayoutLayout中會怎麼樣。


而後咱們繼續看咱們加的RecyclerFragment.java中的代碼:

@Nullable
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, @Nullable Bundle savedInstanceState) {

    recyclerView = (RecyclerView) container.findViewById(R.id.recycler);
    recyclerView.setHasFixedSize(true);

    RelativeLayout placeholder = (RelativeLayout) container.findViewById(R.id.placeholder_view);

   ....
   ....
   ....

    List<RelativeLayout> placeHolderList = new ArrayList<>();
    for (int i = 0; i < 10; i++) {
        placeHolderList.add(placeholder);
    }

    recyclerView.setAdapter(new RecyclerAdapter(placeHolderList));
    recyclerView.setLayoutManager(linearLayoutManager);

    return inflater.inflate(R.layout.recycler_fragment, container, false);
}複製代碼

咱們發現了,這個fragment是對onCreate中的ViewGroup參數進行了操做,把他裏面的RecycleView作了處理,而後最後在return 了一個View,並且這個View的引用的佈局與咱們上面的Activity是同一個佈局文件!!!!都是recycle_fragment.xml

這時候你是否是又有疑問了,通常在fragment中你們都是

View view = inflater.inflate(R.layout.recycler_fragment, container, false);
recycleView = (RecyclerView) view.findViewById(R.id.recycler);
...
...

return view;複製代碼

你有想過這個onCreate方法中的ViewGroup參數究竟是什麼,爲何這裏它能夠直接使用findViewById等。而後去對RecycleView作處理。那最後執行return inflater.inflate(R.layout.recycler_fragment, container, false);這句話,並 沒有對其中的RecycleView作處理,豈不是這個這時候界面上顯示的RecycleView 顯示的是空的???


因此咱們的問題2:這個Demo中的ViewGrop究竟是什麼。並且最後在onCreate的最後直接return了一個新建的View,又沒對其中的RecycleView處理。手機運行後RecycleView仍是有數據的。


解惑:

問題一:

我新建一個Activity,他的佈局文件是:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent" android:id="@+id/activity_linearlayout" > <TextView android:id="@+id/text" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="我是Activity" /> </LinearLayout>複製代碼

再建一個Fragment,他的佈局文件是:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical" android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:id="@+id/fragment_linearlayout"
    >

    <TextView android:id="@+id/text" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="我是Fragment" /> </LinearLayout>複製代碼

而後咱們把這個Fragment添加到Activity的最外面的LinearLayout中。咱們看下效果,以下圖

咱們發現被加進來的Fragment就像是一個控件同樣,依照LinearLayout的特性,垂直向下排了下來。也就是說咱們的在Activity中動態添加Fragmenet,並非只能加到FrameLayout中,還能夠加到其餘ViewGrop中,可是爲何都是添加到FrameLayout中呢。

解答:
在stackoverflow上找到相關提問。
Why is a FrameLayout used for fragments?


問題二:

咱們在本身寫的這個Demo中的Fragment的oncreate方法中打印這個ViewGroup。會發現:

android.widget.LinearLayout{127e518 V.E...... ......I. 0,0-0,0 #7f0e0053 app:id/activity_linearlayout}複製代碼

能夠看到,這個ViewGroup就是咱們在把這個Fragment添加進Activity時候寫的id相對應的佈局。

爲何會這樣?

看下面的相關文章:
Android fragment源碼全解析
咱們就會知道containerViewId 最後就是咱們傳入的id值。
既然這個ViewGroup container就是咱們傳入的id對應的View ,即咱們的Activity佈局中的LinearLayout,咱們固然後直接對這個container經過findViewById來拿到裏面的相關控件。

總結:

最後咱們再回頭看上面那個開源項目的Demo。

在它的Fragment中的onCreate方法中的ViewGroup container其實就是他的Activity中最外面的LinearLayout的View。這個View裏面包括了ToolBar和RecycleView,因此能夠經過recyclerView = (RecyclerView) container.findViewById(R.id.recycler);而後對RecycleView進行相關處理。
並且這裏的RecycleView,是Activity中自己佈局中的那個RecycleView。而後咱們也知道了,這時候添加到Activity的LinearLayout中的Fragment是排在原來的控件的下面。

就是說應該是:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              android:id="@+id/recycler_fragment"
              android:orientation="vertical"
              android:layout_width="match_parent"
              android:layout_height="match_parent">

    <android.support.v7.widget.Toolbar android:id="@+id/recycler_tool_bar" android:layout_width="match_parent" android:layout_height="wrap_content" android:theme="@style/LightToolbarTheme" android:background="@color/colorPrimary"/> <android.support.v7.widget.RecyclerView android:id="@+id/recycler" android:layout_width="match_parent" android:layout_height="match_parent" /> <!--這下面就是Fragment返回的View的內容--> <....> ... ... </....> </LinearLayout>複製代碼

因此這時候,其實真正顯示列表的原來Activity中的RecycleView,因此就算咱們把Fragment中的onCreateView裏面最後return null。也不會影響界面顯示。
那爲何Demo中Fragment返回了一個同Activity同樣的佈局內容的View,卻沒有顯示呢,由於咱們Activity中的RecycleView的高度是match_parent,若是咱們把它改成200dp,咱們就能看到效果:

果真fragment的內容就呈現出來了。由於咱們就是單純的return inflater.inflate(R.layout.recycler_fragment, container, false);,而沒有作相關的處理,因此就是一個空的RecycleView,和一個沒內容的Toolbar。

固然這個開源軟件的Demo這麼寫,反而變得好複雜。可是也讓咱們對Fragment的瞭解更深一步了。

相關文章
相關標籤/搜索