Android App開發學習第二十二天:Fragment

NikerunZoo發表於2020-12-17

1.基本概念

1)它是什麼鬼,有什麼用?

答:Fragment是Android3.0後引入的一個新的API,他出現的初衷是為了適應大螢幕的平板電腦, 當然現在他仍然是平板APP UI設計的寵兒,而且我們普通手機開發也會加入這個Fragment, 我們可以把他看成一個小型的Activity,又稱Activity片段!想想,如果一個很大的介面,我們 就一個佈局,寫起介面來會有多麻煩,而且如果元件多的話是管理起來也很麻煩!而使用Fragment 我們可以把螢幕劃分成幾塊,然後進行分組,進行一個模組化的管理!從而可以更加方便的在 執行過程中動態地更新Activity的使用者介面!另外Fragment並不能單獨使用,他需要巢狀在Activity 中使用,儘管他擁有自己的生命週期,但是還是會受到宿主Activity的生命週期的影響,比如Activity 被destory銷燬了,他也會跟著銷燬!

下圖是文件中給出的一個Fragment分別對應手機與平板間不同情況的處理圖:

在這裡插入圖片描述

PS:簡單的新聞瀏覽頁面,使用兩個Fragment分別顯示新聞列表與新聞內容;

2)Fragment的生命週期圖
在這裡插入圖片描述
3)核心要點:
下面說下使用Fragment的一些要點:

3.0版本後引入,即minSdk要大於11

Fragment需要巢狀在Activity中使用,當然也可以巢狀到另外一個Fragment中,但這個被巢狀 的Fragment也是需要巢狀在Activity中的,間接地說,Fragment還是需要巢狀在Activity中!! 受寄主Activity的生命週期影響,當然他也有自己的生命週期!另外不建議在Fragment裡面 巢狀Fragment因為巢狀在裡面的Fragment生命週期不可控!!!

官方文件說建立Fragment時至少需要實現三個方法:onCreate( ),onCreateView( ),OnPause( ); 不過貌似只寫一個onCreateView也是可以的…

Fragment的生命週期和Activity有點類似:三種狀態: Resumed:在允許中的Fragment可見 Paused:所在Activity可見,但是得不到焦點 Stoped: ①呼叫addToBackStack(),Fragment被新增到Bcak棧 ②該Activity轉向後臺,或者該Fragment被替換/刪除

ps:停止狀態的fragment仍然活著(所有狀態和成員資訊被系統保持著),然而,它對使用者 不再可見,並且如果activity被幹掉,他也會被幹掉.

4)Fragment的幾個子類:

ps:很多時候我們都是直接重寫Fragment,inflate載入佈局完成相應業務了,子類用的不多,等需要的 時候在深入研究!

對話方塊:DialogFragment
列表:ListFragment
選項設定:PreferenceFragment
WebView介面:WebViewFragment
建立Fragment
1)靜態載入Fragment
在這裡插入圖片描述
2)動態載入Fragment
實現流程:
在這裡插入圖片描述
3.Fragment管理與Fragment事務
在這裡插入圖片描述
4.Fragment與Activity的互動
在這裡插入圖片描述
可能有的朋友不喜歡看圖,接下來用文字介紹下吧:

1)元件獲取
Fragment獲得Activity中的元件: getActivity().findViewById(R.id.list);
Activity獲得Fragment中的元件(根據id和tag都可以):getFragmentManager.findFragmentByid(R.id.fragment1);

2)資料傳遞
①Activit傳遞資料給Fragment:

在Activity中建立Bundle資料包,呼叫Fragment例項的setArguments(bundle) 從而將Bundle資料包傳給Fragment,然後Fragment中呼叫getArguments獲得 Bundle物件,然後進行解析就可以了

②Fragment傳遞資料給Activity

在Fragment中定義一個內部回撥介面,再讓包含該Fragment的Activity實現該回撥介面, Fragment就可以通過回撥介面傳資料了,回撥,相信很多人都知道是什麼玩意,但是 寫不出來啊,網上的一百度"fragment傳資料給Activity",全是李剛老師的那個程式碼,真心無語 算了,這裡就寫下區域性程式碼吧,相信讀者一看就懂的了:

Step 1:定義一個回撥介面:(Fragment中)

/*介面*/  
public interface CallBack{  
    /*定義一個獲取資訊的方法*/  
    public void getResult(String result);  
}  

Step 2:介面回撥(Fragment中)

/*介面回撥*/  
public void getData(CallBack callBack){  
    /*獲取文字框的資訊,當然你也可以傳其他型別的引數,看需求咯*/  
    String msg = editText.getText().toString();  
    callBack.getResult(msg);  
}  

Step 3:使用介面回撥方法讀資料(Activity中)

/* 使用介面回撥的方法獲取資料 */  
leftFragment.getData(new CallBack() {  
 @Override  
       public void getResult(String result) {              /*列印資訊*/  
            Toast.makeText(MainActivity.this, "-->>" + result, 1).show();  
            }
        }); 

總結下方法: ->在Fragment定義一個介面,介面中定義抽象方法,你要傳什麼型別的資料引數就設定為什麼型別;
->接著還有寫一個呼叫介面中的抽象方法,把要傳遞的資料傳過去
->再接著就是Activity了,呼叫Fragment提供的那個方法,然後重寫抽象方法的時候進行資料 的讀取就可以了!!!

③Fragment與Fragment之間的資料互傳

其實這很簡單,找到要接受資料的fragment物件,直接呼叫setArguments傳資料進去就可以了 通常的話是replace時,即fragment跳轉的時候傳資料的,那麼只需要在初始化要跳轉的Fragment 後呼叫他的setArguments方法傳入資料即可!
如果是兩個Fragment需要即時傳資料,而非跳轉的話,就需要先在Activity獲得f1傳過來的資料, 再傳到f2了,就是以Activity為媒介~

示例程式碼如下:

FragmentManager fManager = getSupportFragmentManager( );
FragmentTransaction fTransaction = fManager.beginTransaction();
Fragmentthree t1 = new Fragmentthree();
Fragmenttwo t2 = new Fragmenttwo();
Bundle bundle = new Bundle();
bundle.putString("key",id);
t2.setArguments(bundle); 
fTransaction.add(R.id.fragmentRoot, t2, "~~~");  
fTransaction.addToBackStack(t1);  
fTransaction.commit(); 

5.走一次生命週期圖:
思前想後還是決定要帶大家簡單的走一趟生命週期圖,加深大家對Fragment生命週期的理解:

①Activity載入Fragment的時候,依次呼叫下面的方法: onAttach -> onCreate -> onCreateView -> onActivityCreated -> onStart ->onResume

②當我們弄出一個懸浮的對話方塊風格的Activity,或者其他,就是讓Fragment所在的Activity可見,但不獲得焦點 onPause

③當對話方塊關閉,Activity又獲得了焦點: onResume

④當我們替換Fragment,並呼叫addToBackStack()將他新增到Back棧中 onPause -> onStop -> onDestoryView !!注意,此時的Fragment還沒有被銷燬哦!!!

⑤當我們按下鍵盤的回退鍵,Fragment會再次顯示出來: onCreateView -> onActivityCreated -> onStart -> onResume

⑥如果我們替換後,在事務commit之前沒有呼叫addToBackStack()方法將 Fragment新增到back棧中的話;又或者退出了Activity的話,那麼Fragment將會被完全結束, Fragment會進入銷燬狀態 onPause -> onStop -> onDestoryView -> onDestory -> onDetach

新建一個類繼承Fragment並重寫onCreateView()方法,來為該fragment重設佈局檔案


public class ListFragment  extends Fragment {
    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {

        View view = inflater.inflate(R.layout.fragment_list,container,false);
        return view;
    }
}

在Activity中新增Fragment
1.直接在佈局檔案中新增Fragment
建立兩個Fragment,然後在Activity中使用<fragment 標籤將frament新增進去

  <fragment
        android:layout_width="wrap_content"
        android:layout_height="match_parent"
        android:name="com.example.ListFragment"
        android:id="@+id/list"
        android:layout_weight="1"/>
     <fragment
        android:layout_width="wrap_content"
        android:layout_height="match_parent"
        android:name="com.example.DetailFragment"
        android:id="@+id/detail"
        android:layout_weight="2"/>

2.當Activity執行時新增Fragment

FragmentManager fm = getFragmentManager();建立fragment管理器
FragmentTransaction fragmentTransaction = fm.beginTransaction();開啟事務
ft.add(android.R.id.content,detailFragment):新增fragment
ft…replace(R.id.fragment,Fragment):更新fragment
ft.commit();提交事務

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        DetailFragment detailFragment = new DetailFragment();
        FragmentTransaction ft = getFragmentManager().beginTransaction();
        ft.add(android.R.id.content,detailFragment);
        ft.commit();

    }
}

實現模擬微信介面中的Tab標籤切換功能
activity_main.xml

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

   <fragment
       android:id="@+id/fragment"
       android:layout_width="match_parent"
       android:layout_height="match_parent"
       android:name="com.example.Wechat_Fragment"/>
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="50dp"
        android:layout_alignParentBottom="true"
        android:orientation="horizontal">
        <ImageView
            android:id="@+id/image1"
            android:layout_width="1dp"
            android:layout_height="50dp"
            android:layout_weight="1"
            android:src="@drawable/icon1"/>
        <ImageView
            android:id="@+id/image2"
            android:layout_width="1dp"
            android:layout_height="50dp"
            android:layout_weight="1"
            android:src="@drawable/icon2"/>


    </LinearLayout>

</RelativeLayout>

MainActivity

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        ImageView imageView1 = findViewById(R.id.image1);
        ImageView imageView2 = findViewById(R.id.image2);
        imageView1.setOnClickListener(l);
        imageView2.setOnClickListener(l);

    }
    View.OnClickListener  l= new View.OnClickListener(){

        @Override
        public void onClick(View v) {
            //使用事務管理fragment的新增和更新
            FragmentManager fm = getFragmentManager();
            FragmentTransaction fragmentTransaction = fm.beginTransaction();
            Fragment f= null;
            //獲取要切換的fragment
            switch (v.getId())
            {
                case R.id.image1:
                    f = new Wechat_Fragment();
                    break;
                case R.id.image2:
                    f = new Message_Fragment();
                    break;
                default:break;
            }
            fragmentTransaction.replace(R.id.fragment,f);
            fragmentTransaction.commit();
        }
    };
}

底部導航欄+ViewPager滑動切換頁面

1.ViewPager簡單介紹
1)是怎麼樣的一個控制元件?
答:一個頁面切換的元件,我們可以往裡面填充多個View,然後我們可以通過觸控螢幕左右滑動 切換不同的View,和前面學習的ListView一樣,我們需要一個Adapter(介面卡),將要顯示的View和 我們的ViewPager進行繫結,而ViewPager有他自己特定的Adapter——PagerAdapter!另外,Google 官方是建議我們使用Fragment來填充ViewPager的,這樣可以更加方便的生成每個Page以及管理 每個Page的生命週期!當然它給我們提供了兩個不同的Adapter,他們分別是: FragmentPageAdapter和FragmentStatePagerAdapter! 而我們本節用到的則是前者:FragmentPageAdapter! 另外要說一點的是ViewPager的快取機制: ViewPager會快取當前頁,前一頁,以及後一頁,比如有1,2,3,4這四個頁面: 當我們處於第一頁:快取1,2
——> 處於第二頁:快取 1,2,3
——> 處於第三頁:快取2,3,4 ——> 處於第四頁快取3,4這樣!

2)使用PagerAdapter要重寫相關方法:
getCount( ):獲得viewpager中有多少個view

destroyItem( ):移除一個給定位置的頁面。介面卡有責任從容器中刪除這個檢視。這是為了確保 在finishUpdate(viewGroup)返回時檢視能夠被移除。

instantiateItem( ):①將給定位置的view新增到ViewGroup(容器)中,建立並顯示出來 ②返回一個代表新增頁面的Object(key),通常都是直接返回view本身就可以了, 當然你也可以自定義自己的key,但是key和每個view要一一對應的關係

isViewFromObject( ):判斷instantiateItem(ViewGroup, int)函式所返回來的Key與一個頁面檢視是否是 代表的同一個檢視(即它倆是否是對應的,對應的表示同一個View),通常我們直接寫 return view == object;就可以了,至於為什麼要這樣講起來比較複雜,後面有機會進行了解吧 貌似是ViewPager中有個儲存view狀態資訊的ArrayList,根據View取出對應資訊的吧!
PS:不一定要重寫所有方法~

2.實現效果圖以及工程目錄結構:
先來看下我們要實現的效果吧

在這裡插入圖片描述
3.程式碼實現:
Step 1:相關資原始檔的準備:

Step 2:編寫activity_main.xml的佈局檔案:

activity_mian.xml:

<RelativeLayout 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"
    tools:context=".MainActivity">

    <RelativeLayout
        android:id="@+id/ly_top_bar"
        android:layout_width="match_parent"
        android:layout_height="48dp"
        android:background="@color/bg_topbar">

        <TextView
            android:id="@+id/txt_topbar"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_centerInParent="true"
            android:gravity="center"
            android:text="提醒"
            android:textColor="@color/text_topbar"
            android:textSize="18sp" />

        <View
            android:layout_width="match_parent"
            android:layout_height="2px"
            android:layout_alignParentBottom="true"
            android:background="@color/div_white" />

    </RelativeLayout>


    <RadioGroup
        android:id="@+id/rg_tab_bar"
        android:layout_width="match_parent"
        android:layout_height="56dp"
        android:layout_alignParentBottom="true"
        android:background="@color/bg_white"
        android:orientation="horizontal">

        <RadioButton
            android:id="@+id/rb_channel"
            style="@style/tab_menu_item"
            android:drawableTop="@drawable/tab_menu_channel"
            android:text="@string/tab_menu_alert" />

        <RadioButton
            android:id="@+id/rb_message"
            style="@style/tab_menu_item"
            android:drawableTop="@drawable/tab_menu_message"
            android:text="@string/tab_menu_profile" />

        <RadioButton
            android:id="@+id/rb_better"
            style="@style/tab_menu_item"
            android:drawableTop="@drawable/tab_menu_better"
            android:text="@string/tab_menu_pay" />

        <RadioButton
            android:id="@+id/rb_setting"
            style="@style/tab_menu_item"
            android:drawableTop="@drawable/tab_menu_setting"
            android:text="@string/tab_menu_setting" />

    </RadioGroup>

    <View
        android:id="@+id/div_tab_bar"
        android:layout_width="match_parent"
        android:layout_height="2px"
        android:layout_above="@id/rg_tab_bar"
        android:background="@color/div_white" />

    <androidx.viewpager.widget.ViewPager
        android:id="@+id/vpager"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_above="@id/div_tab_bar"
        android:layout_below="@id/ly_top_bar" />


</RelativeLayout>

Step 3:編寫Fragment的佈局以及程式碼:
PS:這裡為了順便演示ViewPager的機制,特意寫成了四個Fragment!在onCreateView中列印建立Log!
fg_content.xml:fg_content2.xml:fg_content.xml3:fg_content4.xml:
新增的元件隨意,下面是fg_content.xml

<?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="@color/bg_white"
    android:orientation="vertical">

    <TextView
        android:id="@+id/txt_content"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:gravity="center"
        android:text="呵呵"
        android:textColor="@color/text_yellow"
        android:textSize="20sp" />

</LinearLayout>

MyFragment1.java:

/**
 * Created by Jay on 2015/8/28 0028.
 */
public class MyFragment1 extends Fragment {

    public MyFragment1() {
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.fg_content, container, false);
        TextView txt_content = (TextView) view.findViewById(R.id.txt_content);
        txt_content.setText("第一個Fragment");
        Log.e("HEHE", "1日狗");
        return view;
    }
}

其他三個照葫蘆畫瓢,換點東西就好!

Step 4:自定義FragmentPagerAdapter類:
程式碼很簡單,只需傳遞一個FragmentManager過來,其他都在這裡完成!

public class MyFragmentPagerAdapter extends FragmentPagerAdapter {

    //    private final int PAGER_COUNT = 4;
//    private MyFragment1 myFragment1 = null;
//    private MyFragment2 myFragment2 = null;
//    private MyFragment3 myFragment3 = null;
//    private MyFragment4 myFragment4 = null;
    private List<Fragment> mList = new ArrayList<>();


    public MyFragmentPagerAdapter(FragmentManager fm, List<Fragment> mList) {
        super(fm);
//        myFragment1 = new MyFragment1();
//        myFragment2 = new MyFragment2();
//        myFragment3 = new MyFragment3();
//        myFragment4 = new MyFragment4();
        this.mList = mList;
    }


    @Override
    public int getCount() {
        return mList.size();
    }

    @Override
    public Object instantiateItem(ViewGroup vg, int position) {
        return super.instantiateItem(vg, position);
    }

    @Override
    public void destroyItem(ViewGroup container, int position, Object object) {
        System.out.println("position Destory" + position);
        super.destroyItem(container, position, object);
    }

    @Override
    public Fragment getItem(int position) {

        return mList.get(position);
    }

}

Step 5:MainActivity的編寫:
邏輯很簡單,自己看~

MainActivity.java:


public class MainActivity extends AppCompatActivity implements RadioGroup.OnCheckedChangeListener,
        ViewPager.OnPageChangeListener {

    //UI Objects
    private TextView txt_topbar;
    private RadioGroup rg_tab_bar;
    private RadioButton rb_channel;
    private RadioButton rb_message;
    private RadioButton rb_better;
    private RadioButton rb_setting;
    private ViewPager vpager;

    private MyFragmentPagerAdapter mAdapter;

    //幾個代表頁面的常量
    public static final int PAGE_ONE = 0;
    public static final int PAGE_TWO = 1;
    public static final int PAGE_THREE = 2;
    public static final int PAGE_FOUR = 3;

    private MyFragment1 myFragment1 = null;
    private MyFragment2 myFragment2 = null;
    private MyFragment3 myFragment3 = null;
    private MyFragment4 myFragment4 = null;
    private List<Fragment> mList = new ArrayList<>();


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        initData();
        mAdapter = new MyFragmentPagerAdapter(getSupportFragmentManager(), mList);
        bindViews();
        rb_channel.setChecked(true);
    }

    private void initData() {
        myFragment1 = new MyFragment1();
        myFragment2 = new MyFragment2();
        myFragment3 = new MyFragment3();
        myFragment4 = new MyFragment4();
        mList.add(myFragment1);
        mList.add(myFragment2);
        mList.add(myFragment3);
        mList.add(myFragment4);
    }

    private void bindViews() {
        txt_topbar = (TextView) findViewById(R.id.txt_topbar);
        rg_tab_bar = (RadioGroup) findViewById(R.id.rg_tab_bar);
        rb_channel = (RadioButton) findViewById(R.id.rb_channel);
        rb_message = (RadioButton) findViewById(R.id.rb_message);
        rb_better = (RadioButton) findViewById(R.id.rb_better);
        rb_setting = (RadioButton) findViewById(R.id.rb_setting);
        rg_tab_bar.setOnCheckedChangeListener(this);

        vpager = (ViewPager) findViewById(R.id.vpager);
        vpager.setAdapter(mAdapter);
        vpager.setCurrentItem(0);
        vpager.addOnPageChangeListener(this);
    }

    @Override
    public void onCheckedChanged(RadioGroup group, int checkedId) {
        switch (checkedId) {
            case R.id.rb_channel:
                vpager.setCurrentItem(PAGE_ONE);
                break;
            case R.id.rb_message:
                vpager.setCurrentItem(PAGE_TWO);
                break;
            case R.id.rb_better:
                vpager.setCurrentItem(PAGE_THREE);
                break;
            case R.id.rb_setting:
                vpager.setCurrentItem(PAGE_FOUR);
                break;
        }
    }


    //重寫ViewPager頁面切換的處理方法
    @Override
    public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
    }

    @Override
    public void onPageSelected(int position) {
    }

    @Override
    public void onPageScrollStateChanged(int state) {
        //state的狀態有三個,0表示什麼都沒做,1正在滑動,2滑動完畢
        if (state == 2) {
            switch (vpager.getCurrentItem()) {
                case PAGE_ONE:
                    rb_channel.setChecked(true);
                    break;
                case PAGE_TWO:
                    rb_message.setChecked(true);
                    break;
                case PAGE_THREE:
                    rb_better.setChecked(true);
                    break;
                case PAGE_FOUR:
                    rb_setting.setChecked(true);
                    break;
            }
        }
    }
}

PS:另外獲取FragmentManager的方法不是直接用getFragmentManager()而是使用 getSupportFragmentManager()哦!

注意:如果 ViewPager 放在 RadioButton 後,RadioButton 的點選事件會失效。

新聞(購物)類App列表Fragment的簡單實現

相信大家對點選列表,然後進入詳情這種App並不陌生吧,在購物類App和新聞類App中最為常見: 下面我們簡單來講一下流程邏輯!
在這裡插入圖片描述

嘿嘿,市面上很多APP都是這種樣子的,而這個可以用我們學到的Fragment來實現: 可能gif動畫看不清,筆者用介面原型工具畫個大概吧:

在這裡插入圖片描述

大概就這樣,中間區域是一個佈局容器,一般是FrameLayout,然後我們將一個Fragment replace 到這個容器中或者add也行,而這個Fragment中有一個listview,當我們點選這個ListView中的一項, 中間容器中的Fragment就會被replace成對應詳細資訊的Fragment所替代,如果我們只是replace的話, 就不會儲存第一個Fragment的狀態,使用者又得從頭開始瀏覽,這肯定是很不方便的,這裡我們可以 通過Fragment棧的addtobackStack和popbackstack來解決這個問題!當replace的同時,我們將被替換 的Fragment新增到stack中,當使用者點選回退按鈕時,呼叫popbackstack彈出棧,具體實現見下述程式碼 示例!

2.程式碼示例:簡單新聞類APP列表和內容切換的實現
執行效果圖:

在這裡插入圖片描述

實現程式碼:

Step 1:先把兩個Fragment以及Activity的佈局實現了

fg_newlist.xml:

<?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="@color/white"
    android:orientation="horizontal">

    <ListView
        android:id="@+id/list_news"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

</LinearLayout>

fg_context.xml:

<?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:orientation="vertical">

    <TextView
        android:id="@+id/txt_content"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:gravity="center"
        android:textColor="@color/blue"
        android:textSize="20sp" />

</LinearLayout>

activity_main.xml:

<RelativeLayout 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"
    tools:context=".MainActivity">

    <TextView
        android:id="@+id/txt_title"
        android:layout_width="match_parent"
        android:layout_height="56dp"
        android:background="@color/blue"
        android:textColor="@color/white"
        android:text="新聞列表"
        android:textSize="20sp"
        android:textStyle="bold"
        android:gravity="center"/>

    <FrameLayout
        android:id="@+id/fl_content"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_below="@id/txt_title"/>


</RelativeLayout>

Step 2:實現我們的業務Bean類和自定義BaseAdapter類:

Data.java:

/**
 * Created by Jay on 2015/9/6 0006.
 */
public class Data {

    private String new_title;
    private String new_content;

    public Data(){}

    public Data(String new_title, String new_content) {
        this.new_title = new_title;
        this.new_content = new_content;
    }

    public String getNew_title() {
        return new_title;
    }

    public String getNew_content() {
        return new_content;
    }

    public void setNew_title(String new_title) {
        this.new_title = new_title;
    }

    public void setNew_content(String new_content) {
        this.new_content = new_content;
    }
}

MyAdapter.java:

public class MyAdapter extends BaseAdapter {

    private List<Data> mData;
    private Context mContext;

    public MyAdapter(List<Data> mData, Context mContext) {
        this.mData = mData;
        this.mContext = mContext;
    }

    @Override
    public int getCount() {
        return mData.size();
    }

    @Override
    public Object getItem(int position) {
        return null;
    }

    @Override
    public long getItemId(int position) {
        return position;
    }


    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        ViewHolder viewHolder;
        if(convertView == null){
            convertView = LayoutInflater.from(mContext).inflate(R.layout.activity_main,parent,false);
            viewHolder = new ViewHolder();
            viewHolder.txt_title = (TextView) convertView.findViewById(R.id.txt_title);
            convertView.setTag(viewHolder);
        }else{
            viewHolder = (ViewHolder) convertView.getTag();
        }
        viewHolder.txt_title.setText(mData.get(position).getNew_title());
        return convertView;
    }

    private class ViewHolder{
        TextView txt_title;
    }

}

Step 3:MainActivity的實現

MainActivity.java:

public class MainActivity extends AppCompatActivity {

    private TextView txt_title;
    private FrameLayout fl_content;
    private Context mContext;
    private ArrayList<Data> datas = null;
    private FragmentManager fManager = null;
    private long exitTime = 0;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mContext = MainActivity.this;
        fManager = getFragmentManager();
        bindViews();

        datas = new ArrayList<Data>();
        for (int i = 1; i <= 20; i++) {
            Data data = new Data("新聞標題" + i, i + "~新聞內容~~~~~~~~");
            datas.add(data);
        }
        NewListFragment nlFragment = new NewListFragment(fManager, datas);
        FragmentTransaction ft = fManager.beginTransaction();
        ft.replace(R.id.fl_content, nlFragment);
        ft.commit();
    }


    private void bindViews() {
        txt_title = (TextView) findViewById(R.id.txt_title);
        fl_content = (FrameLayout) findViewById(R.id.fl_content);
    }


    //點選回退鍵的處理:判斷Fragment棧中是否有Fragment
    //沒,雙擊退出程式,否則像是Toast提示
    //有,popbackstack彈出棧
    @Override
    public void onBackPressed() {
        if (fManager.getBackStackEntryCount() == 0) {
            if ((System.currentTimeMillis() - exitTime) > 2000) {
                Toast.makeText(getApplicationContext(), "再按一次退出程式",
                        Toast.LENGTH_SHORT).show();
                exitTime = System.currentTimeMillis();
            } else {
                super.onBackPressed();
            }
        } else {
            fManager.popBackStack();
            txt_title.setText("新聞列表");
        }
    }
}

Step 4:列表Fragment的實現:

NewListFragment.java:

package com.jay.fragmentdemo4;

import android.app.Fragment;
import android.app.FragmentManager;
import android.app.FragmentTransaction;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.ListView;
import android.widget.TextView;

import java.util.ArrayList;

/**
 * Created by Jay on 2015/9/6 0006.
 */
public class NewListFragment extends Fragment implements AdapterView.OnItemClickListener {
    private FragmentManager fManager;
    private ArrayList<Data> datas;
    private ListView list_news;

    public NewListFragment(FragmentManager fManager, ArrayList<Data> datas) {
        this.fManager = fManager;
        this.datas = datas;
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.fg_newlist, container, false);
        list_news = (ListView) view.findViewById(R.id.list_news);
        MyAdapter myAdapter = new MyAdapter(datas, getActivity());
        list_news.setAdapter(myAdapter);
        list_news.setOnItemClickListener(this);
        return view;
    }


    @Override
    public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
        FragmentTransaction fTransaction = fManager.beginTransaction();
        NewContentFragment ncFragment = new NewContentFragment();
        Bundle bd = new Bundle();
        bd.putString("content", datas.get(position).getNew_content());
        ncFragment.setArguments(bd);
        //獲取Activity的控制元件
        TextView txt_title = (TextView) getActivity().findViewById(R.id.txt_title);
        txt_title.setText(datas.get(position).getNew_content());
        //加上Fragment替換動畫
        fTransaction.setCustomAnimations(R.anim.fragment_slide_left_enter, R.anim.fragment_slide_left_exit);
        fTransaction.replace(R.id.fl_content, ncFragment);
        //呼叫addToBackStack將Fragment新增到棧中
        fTransaction.addToBackStack(null);
        fTransaction.commit();
    }
}

Step 5:內容Fragment的實現:

NewContentFragment.java:

/**
 * Created by Jay on 2015/9/6 0006.
 */
public class NewContentFragment extends Fragment {

    NewContentFragment() {
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.fg_content, container, false);
        TextView txt_content = (TextView) view.findViewById(R.id.txt_content);
        //getArgument獲取傳遞過來的Bundle物件
        txt_content.setText(getArguments().getString("content"));
        return view;
    }

}

相關文章