Android Fragment用法詳解(2)--動態添加Fragment


在上一篇文章《Android Fragment用法詳解(1)--靜態使用Fragment》我們講解了Fragment的最簡單的用法。這次我們來說一說Fragment復雜一丟丟的用法。在代碼中動態添加Fragment,讓其實現類似微信主頁面效果。也就是點擊底部的按鈕來動態改變中間內容頁面。我們先來看看效果圖吧。說明一下,為了方便大家復制粘貼,里面沒有任何圖片素材,都是用顏色和安卓自帶圖片來現實效果,所以有點難看哈~~畢竟我們是程序員不是美工嘛!

接下來就是源代碼啦

先看MainActivity的布局文件吧。因為布局文件是關鍵哦。

<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" >

    <!-- 把Fragment當作普通控件使用,這里沒啥作用,就是作為一個標題欄,不用Fragment,直接寫布局一樣的 -->
    <fragment
        android:id="@+id/fg_title"
        android:name="com.example.fragmentdemo.TitleFragment"
        android:layout_width="match_parent"
        android:layout_height="45dp" />

    <!-- 用一個幀布局來占一個位置,目的是給fragment用 -->
    <FrameLayout
        android:id="@+id/fl_content"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1" >
    </FrameLayout>

    <!-- 底部三個按鈕,我們用RadioGroup來實現 -->
    <include layout="@layout/bar" />

</LinearLayout>

 然后看看底部四個按鈕的布局吧

<?xml version="1.0" encoding="utf-8"?>
<RadioGroup xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="50dp"
    android:id="@+id/rg"
    android:orientation="horizontal" >

    <!-- android:paddingLeft="0dp"加這個是為了讓內容能夠劇中 -->
    <RadioButton
        android:id="@+id/rb_1"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        android:background="@drawable/bar_selector"
        android:button="@null"
        android:drawableTop="@android:drawable/star_on"
        android:gravity="center"
        android:paddingLeft="0dp"
        android:text="Frag_1" />

    <RadioButton
        android:id="@+id/rb_2"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        android:background="@drawable/bar_selector"
        android:button="@null"
        android:drawableTop="@android:drawable/star_on"
        android:gravity="center"
        android:paddingLeft="0dp"
        android:text="Frag_2" />

    <RadioButton
        android:id="@+id/rb_3"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        android:background="@drawable/bar_selector"
        android:button="@null"
        android:drawableTop="@android:drawable/star_on"
        android:gravity="center"
        android:paddingLeft="0dp"
        android:text="Frag_3" />

</RadioGroup>

然后就是三個按鈕的選擇器(就是控制點擊底部按鈕的時候,底部按鈕能夠變化背景顏色的選擇器)

<?xml version="1.0" encoding="utf-8"?>

<selector xmlns:android="http://schemas.android.com/apk/res/android" >  
    <item android:state_checked="true" android:drawable="@android:color/holo_red_light" ></item>  
    <item android:state_checked="false" android:drawable="@android:color/holo_blue_bright"></item>  
</selector>  

 接下來就是先上一些無關緊要的文件,哈哈。標題欄的類文件和布局文件

先看布局文件

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="45dp"
    android:gravity="center"
    android:background="#00ff00" >

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Fragment制作的標題欄"
        android:textColor="@android:color/black"
        android:textSize="18sp" />

</RelativeLayout>

然后是類文件

package com.example.fragmentdemo;

import android.app.Fragment;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

/**
 *************************************************************** 
 * 
 * @版權 LinFeng
 * 
 * @作者 LinFeng
 * 
 * @版本 1.0
 * 
 * @創建日期 2016-6-6
 * 
 * @功能描述 用Fragment制作標題欄
 ***************************************************************** 
 */
public class TitleFragment extends Fragment{
    
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
            Bundle savedInstanceState) {
        /**
         * 加載布局文件然后返回view,顯示在Activity
         */
        View view = inflater.inflate(R.layout.title, container,false);
        return view;
    }

}

然后就是重量級別的MainActivity類文件了

package com.example.fragmentdemo;

import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentTransaction;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.Window;
import android.widget.RadioButton;
import android.widget.RadioGroup;

public class MainActivity extends FragmentActivity implements OnClickListener {
    
    private RadioButton rb1;
    private RadioButton rb2;
    private RadioButton rb3;
    
    private RadioGroup rGroup;
    
    private Fragment f1,f2,f3;
    private FragmentManager manager;
    private FragmentTransaction transaction;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        requestWindowFeature(Window.FEATURE_NO_TITLE);
        setContentView(R.layout.activity_main);
        
        /**
         * 拿到事務管理器並開啟事務
         */
        manager = getSupportFragmentManager();
        transaction = manager.beginTransaction();
        
        /**
         * 初始化按鈕
         */
        rb1 = (RadioButton) findViewById(R.id.rb_1);
        rb2 = (RadioButton) findViewById(R.id.rb_2);
        rb3 = (RadioButton) findViewById(R.id.rb_3);
        
        rGroup = (RadioGroup) findViewById(R.id.rg);
        
        /**
         * 為三個按鈕添加監聽
         */
        rb1.setOnClickListener(this);
        rb2.setOnClickListener(this);
        rb3.setOnClickListener(this);
        
        /**
         * 啟動默認選中第一個
         */
        rGroup.check(R.id.rb_1);
        f1 = new Fragment1();
        transaction.replace(R.id.fl_content, f1);
        transaction.commit();
    }

    @Override
    public void onClick(View v) {
        
        manager = getSupportFragmentManager();
        transaction = manager.beginTransaction();

        switch (v.getId()) {
            case R.id.rb_1 :
                /**
                 * 為了防止重疊,需要點擊之前先移除其他Fragment
                 */
                hideFragment(transaction);
                f1 = new Fragment1();
                transaction.replace(R.id.fl_content, f1);
                transaction.commit();

                break;
            case R.id.rb_2 :
                hideFragment(transaction);
                f2 = new Fragment2();
                transaction.replace(R.id.fl_content, f2);
                transaction.commit();

                break;
            case R.id.rb_3 :
                hideFragment(transaction);
                f3 = new Fragment3();
                transaction.replace(R.id.fl_content, f3);
                transaction.commit();
                break;

            default :
                break;
        }
    }
    
    /*
     * 去除(隱藏)所有的Fragment
     * */
    private void hideFragment(FragmentTransaction transaction) {
        if (f1 != null) {
            //transaction.hide(f1);隱藏方法也可以實現同樣的效果,不過我一般使用去除
            transaction.remove(f1);
        }
        if (f2 != null) {
            //transaction.hide(f2);
            transaction.remove(f2);
        }
        if (f3 != null) {
            //transaction.hide(f3);
            transaction.remove(f3);
        }
    
        
    }

}

到這里基本都結束了。哈哈,然后聰明的同學一定還注意到MainActivtiy里還有3個Fragment的類,由於這三個基本是99%相同的,所以我就貼出其中一個的代碼(其他兩個無非就是修改顯示文字,類文件名而已~~其他全部相同)

先看類文件

package com.example.fragmentdemo;

import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

/**
 *************************************************************** 
 * 
 * @版權 LinFeng
 * 
 * @作者 LinFeng
 * 
 * @版本 1.0
 * 
 * @創建日期 2016-6-6
 * 
 * @功能描述 
 ***************************************************************** 
 */

/**
 * 這里要注意,Fragment是要引入android.support.v4.app.Fragment這個包里面的,不是那個app.fragment那個包哦
 * @author LinFeng
 *
 */
public class Fragment1 extends Fragment{
    
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
            Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.frament1, container,false);
        return view;
    }

}

然后是布局文件

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#ffff00"
    android:gravity="center"
    android:orientation="vertical" >

    <TextView
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:gravity="center"
        android:textSize="25sp"
        android:text="FRAGMENT_1" />

</LinearLayout>

看到這里,相信大家基本都學會動態添加Fragment了吧!為什么不直接貼出項目代碼給大家下載?主要是,我不建議大家直接下載人家的項目來運行,然后閱讀,感覺你會了。但其實,如果自己寫,可能會出現各種奇葩的問題,所以,根據人家的思路,自己寫一遍,運行一下,出來的,才是你自己的。

 

《==================================這是一條華麗的分割線================================》

最后我們看一些關於Fragment的東西,剛剛好在人家的博客里面看到覺得不錯就COPY過來給大家看看了。

a、獲取FragmentManage的方式:

getFragmentManager() // v4中,getSupportFragmentManager

b、主要的操作都是FragmentTransaction的方法

FragmentTransaction transaction = fm.benginTransatcion();//開啟一個事務

transaction.add() 

往Activity中添加一個Fragment

transaction.remove()

從Activity中移除一個Fragment,如果被移除的Fragment沒有添加到回退棧(回退棧后面會詳細說),這個Fragment實例將會被銷毀。

transaction.replace()

使用另一個Fragment替換當前的,實際上就是remove()然后add()的合體~

transaction.hide()

隱藏當前的Fragment,僅僅是設為不可見,並不會銷毀

transaction.show()

顯示之前隱藏的Fragment

detach()

會將view從UI中移除,和remove()不同,此時fragment的狀態依然由FragmentManager維護。

attach()

重建view視圖,附加到UI上並顯示。

transatcion.commit()//提交一個事務

注意:常用Fragment的哥們,可能會經常遇到這樣Activity狀態不一致:State loss這樣的錯誤。主要是因為:commit方法一定要在Activity.onSaveInstance()之前調用。

上述,基本是操作Fragment的所有的方式了,在一個事務開啟到提交可以進行多個的添加、移除、替換等操作。

值得注意的是:如果你喜歡使用Fragment,一定要清楚這些方法,哪個會銷毀視圖,哪個會銷毀實例,哪個僅僅只是隱藏,這樣才能更好的使用它們。

a、比如:我在FragmentA中的EditText填了一些數據,當切換到FragmentB時,如果希望會到A還能看到數據,則適合你的就是hide和show;也就是說,希望保留用戶操作的面板,你可以使用hide和show,當然了不要使勁在那new實例,進行下非null判斷。

b、再比如:我不希望保留用戶操作,你可以使用remove(),然后add();或者使用replace()這個和remove,add是相同的效果。

c、remove和detach有一點細微的區別,在不考慮回退棧的情況下,remove會銷毀整個Fragment實例,而detach則只是銷毀其視圖結構,實例並不會被銷毀。那么二者怎么取舍使用呢?如果你的當前Activity一直存在,那么在不希望保留用戶操作的時候,你可以優先使用detach。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM