2017年7月18日 星期二

Android:Fragment(片段)

當還沒有Fragment功能出來以前,必須使用很多個Activity來轉換到另一個Activity的方式來設計功能,這在手機上使用來看,感覺起來沒什麼問題,但是平板出來之後,畫面變大,一個畫面可以容納更多的元件,所以為了讓Android UI在平板上可以有更好的展示效果,Android在3.0時加入了Fragment功能。



Fragment片段是Android提供的一個畫面區塊,可以將Fragment放在一個Activity中,Fragment可以說是Activity的子畫面。

開發上使用Fragment的好處是:

  • 有自己的生命週期
  • 可以重複利用降低開發成本
  • 一個Fragment在手機和平板上可以有不同的使用者體驗


Fragment與Activity的生命週期:


Fragment的生命週期必須依附Activity的生命週期,意思是說,當 Activity 暫停時,其中的所有片段也會一併暫停;而當 Activity 遭到刪除時,所有片段也會一併刪除。 不過,當 Activity 執行時 (該 Activity 會處於繼續進行生命週期狀態),您可以個別操縱所有片段,例如新增或移除片段。

Fragment動態佈署主要分為動態新增(add)動態置換(replace兩種:

  • replace是每次呼叫,不管有沒有建立過fragment,都會創建一個新的Fragment,所以生命週期也會重跑一遍,如果使用在需要經常更換fragment的時候,非常消耗資源。
  • add則是可以搭配hide()與show()來建立Fragment,當要切換Fragment時,可以hide()當前的fragment,並且add()和show()新的fragment


動態置換(replace)程式碼:

activity_main.xml:

<?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="match_parent">

    <LinearLayout
        android:id="@+id/fragment_container"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
        android:padding="20dp" />

    <RadioGroup
        android:id="@+id/id_radioGroup"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:orientation="horizontal">

        <RadioButton
            android:id="@+id/id_one"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:button="@null"
            android:drawableTop="@mipmap/ic_launcher"
            android:gravity="center_horizontal"
            android:text="page1"
            android:onClick="onClick"/>


        <RadioButton
            android:id="@+id/id_two"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:button="@null"
            android:drawableTop="@mipmap/ic_launcher"
            android:gravity="center_horizontal"
            android:text="page2"
            android:onClick="onClick"/>

        <RadioButton
            android:id="@+id/id_three"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:button="@null"
            android:drawableTop="@mipmap/ic_launcher"
            android:gravity="center_horizontal"
            android:text="page3"
            android:onClick="onClick"/>

        <RadioButton
            android:id="@+id/id_four"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:button="@null"
            android:drawableTop="@mipmap/ic_launcher"
            android:gravity="center_horizontal"
            android:text="page4"
            android:onClick="onClick"/>

    </RadioGroup>
</RelativeLayout>


MainActivity.java:

public class MainActivity extends FragmentActivity {
    private RadioButton id_one,id_two,id_three,id_four;
    private int page = 1;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        
        findviewbyid();
        changeFragment(DetailsFragment.newInstance(page));

    }
    public void onClick(View view){
        switch (view.getId()){
            case R.id.id_one:
                changeFragment(DetailsFragment.newInstance(1));
                break;
            case R.id.id_two:
                changeFragment(DetailsFragment.newInstance(2));
                break;
            case R.id.id_three:
                changeFragment(DetailsFragment.newInstance(3));
                break;
            case R.id.id_four:
                changeFragment(DetailsFragment.newInstance(4));
                break;
        }
    }
    private void findviewbyid(){
        id_one = (RadioButton)findViewById(R.id.id_one);
        id_two = (RadioButton)findViewById(R.id.id_two);
        id_three = (RadioButton)findViewById(R.id.id_three);
        id_four = (RadioButton)findViewById(R.id.id_four);
    }

    private void changeFragment(Fragment f) {
        FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
        transaction.replace(R.id.fragment_container, f);
        transaction.commitAllowingStateLoss();
    }
    protected void onStart(){
        super.onStart();
        Log.i("tag","Activity onStart()");
    }
    protected void onResume(){
        super.onResume();
        Log.i("tag","Activity onResume()");
    }
}

fragment_tmp.xml(fragment內容的佈局文件):

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

        <TextView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:id="@+id/text_view"
            android:text="fragment"
            android:gravity="center"
            android:textSize="20sp"/>

</LinearLayout>

DetailFragment.java:

public class DetailsFragment extends Fragment {


    private View v;
    public static DetailsFragment newInstance(int index) {
        DetailsFragment f = new DetailsFragment();

        // Supply index input as an argument.
        Bundle args = new Bundle();
        args.putInt("index", index);
        f.setArguments(args);

        return f;
    }

    public int getShownIndex() {
        return getArguments().getInt("index", 0);
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        Log.i("tag","Fragment onCreateView()");
        v = inflater.inflate(R.layout.fragment_tmp, container, false);
        TextView text = (TextView)v.findViewById(R.id.text_view);
        text.setText("Page" + getShownIndex());
        return v;
    }


}

執行結果:


動態新增(add)程式碼:

activity_main.xml :

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <LinearLayout
        android:id="@+id/fragment_container"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
        android:padding="20dp" />

    <RadioGroup
        android:id="@+id/id_radioGroup"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:orientation="horizontal">

        <RadioButton
            android:id="@+id/id_one"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:button="@null"
            android:drawableTop="@mipmap/ic_launcher"
            android:gravity="center_horizontal"
            android:text="page1"
            android:onClick="onClick"/>


        <RadioButton
            android:id="@+id/id_two"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:button="@null"
            android:drawableTop="@mipmap/ic_launcher"
            android:gravity="center_horizontal"
            android:text="page2"
            android:onClick="onClick"/>

    </RadioGroup>
</RelativeLayout>

MainActivity.java:

public class MainActivity extends AppCompatActivity {

    private RadioButton id_one,id_two;
    private Fragment1 mFragment01;
    private Fragment2 mFragment02;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        findviewbyid();
        mFragment01 = new Fragment1();
        mFragment02 = new Fragment2();
        FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
        transaction.replace(R.id.fragment_container, mFragment01,"TAG-mFragment01");
        transaction.commitAllowingStateLoss();

    }

    private void findviewbyid(){
        id_one = (RadioButton)findViewById(R.id.id_one);
        id_two = (RadioButton)findViewById(R.id.id_two);
    }
    public void onClick(View view){
        switch (view.getId()){
            case R.id.id_one:
                chaangefragment(mFragment01,"TAG-mFragment01");
                break;
            case R.id.id_two:
                chaangefragment(mFragment02,"TAG-mFragment02");
                break;
        }
    }
    public void chaangefragment(Fragment fragment,String tag){
        FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
        FragmentManager fragmentManager = MainActivity.this.getSupportFragmentManager();
        List fragments = fragmentManager.getFragments();
        Fragment tmp=null;
        for (Fragment f: fragments){
            if (f!=null && f.isVisible()) {
                System.out.println("hide"+f.getTag());
                tmp=f;
            }
        }
//        Fragment fragment = getSupportFragmentManager().findFragmentByTag("TAG-mFragment01");
//        System.out.println(fragment);
        if (fragment.isAdded()){
            transaction.hide(tmp).show(fragment).commit();
        }else {
            transaction.hide(tmp).add(R.id.fragment_container,fragment,tag).commit();
        }
    }
}

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

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/txt"
        android:text="fragment"/>

</LinearLayout>

fragment1.java:

public class Fragment1 extends Fragment {

    private TextView txt;

    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        Log.i("tag","Fragment1  onCreateView");
        return inflater.inflate(R.layout.fragment_layout, container, false);

    }

    @Override
    public void onActivityCreated(@Nullable Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
        Log.i("tag","Fragment1  onActivityCreated");
        txt = (TextView)getView().findViewById(R.id.txt);
        txt.setText("fragment1");
    }


    @Override
    public void onAttach(Context context) {
        super.onAttach(context);
        Log.i("tag","Fragment1  onAttach");
    }

    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Log.i("tag","Fragment1  onCreate");
    }

    @Override
    public void onStart() {
        super.onStart();
        Log.i("tag","Fragment1  onStart");
    }

    @Override
    public void onResume() {
        super.onResume();
        Log.i("tag","Fragment1  onResume");
    }
}

fragment2.java:

public class Fragment2 extends Fragment{

    private TextView txt;

    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        Log.i("tag","Fragment2  onCreateView");
        return inflater.inflate(R.layout.fragment_layout, container, false);
    }

    @Override
    public void onActivityCreated(@Nullable Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
        Log.i("tag","Fragment2  onActivityCreated");
        txt = (TextView)getView().findViewById(R.id.txt);
        txt.setText("fragment2");
    }
    @Override
    public void onAttach(Context context) {
        super.onAttach(context);
        Log.i("tag","Fragment2  onAttach");
    }

    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Log.i("tag","Fragment2  onCreate");
    }

    @Override
    public void onStart() {
        super.onStart();
        Log.i("tag","Fragment2  onStart");
    }

    @Override
    public void onResume() {
        super.onResume();
        Log.i("tag","Fragment2  onResume");
    }
}

執行順續page1(起始) -> page2 -> page1 -> page2
執行結果:

可以看到fragment1和fragment2個別被建立1次後,之後再呼叫時就不會再被建立新的Fragment了。





沒有留言:

張貼留言