Fragment的基本应用

来源:互联网 发布:华通云数据与马云关系 编辑:程序博客网 时间:2024/06/06 07:52

转载地址:http://blog.csdn.net/crazy1235/article/details/50933621?spm=5176.8246799.blogcont.6.v5bVkP




目录(?)[-]

  1. Fragment
    1. fragment生命周期
    2. fragment的使用
    3. Fragment的事务管理
    4. Fragment之间的切换
    5. Fragment与Activity之间传值
    6. Fragment与Fragment传值
    7. Fragment切换动画


Fragment

还是先来基本介绍。

Fragment –> 片段。 
在Android3.0的时候被引入,它的出现主要是给大屏幕设备提供更加灵活的UI支持。通过对Activity布局进行分片,更加方便的对每块进行独立控制。这些片段可以被不同的activity复用。


fragment生命周期

每个fragment拥有自己的生命周期,但是fragment要依赖于activity存在,生命周期受到包括它的activity的生命周期控制。

来两张神图~~

这里写图片描述 这里写图片描述

左图就是fragment的生命周期图。右图是fragment与activity各自生命周期的对照。

介绍一下常用的几个生命周期函数:

  • onAttach(Context) –> 当fragment被绑定到activity上时回调

  • onCreate(Bundle) –> 当fragment对象创建的时候回调,一般在此方法里做参数接收。

  • onCreateView(LayoutInflater, ViewGroup, Bundle) –> 创建fragment视图时回调

  • onDestoryView –> 视图销毁时回调

  • onDestory –> 销毁fragment时回调

  • onDetech() –> fragment与activity失去关联时回调


fragment的使用

使用fragment可以当成一个控件,直接放到activity布局文件里;也可以在代码里面动态的添加、更新或者删除。

下面的activity布局文件中定义了一个fragment和一个frameLayout。使用标签可以称之为静态的Fragment,在activity创建的时候也会去创建并显示它,而framelayout是一个容器,我们在代码中可以动态的添加一个fragment进去。

<?xml version="1.0" encoding="utf-8"?><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="horizontal"    tools:context=".fragments.ArticleActivity">    <!--headlines-->    <fragment        android:id="@+id/headline_fragment"        android:name="com.jacksen.demo.view.fragments.HeadlinesFragment"        android:layout_width="0dp"        android:layout_height="match_parent"        android:layout_weight="1"        tools:layout="@layout/fragment_item_list" />    <!--article-->    <FrameLayout        android:id="@+id/article_frame_layout"        android:layout_width="0dp"        android:layout_height="match_parent"        android:layout_weight="2" /></LinearLayout>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22

注意:

使用标签显示Fragment的时候,需要对这个fragment设置一个id或者tag,否则会出现”Error inflating class fragment”错误。

这里写图片描述

Caused by: java.lang.IllegalArgumentException: Binary XML file line #10: Must specify unique android:id, android:tag, or have a parent with an id for com.jacksen.demo.view.fragments.HeadlinesFragment
  • 1
  • 1

Fragment的子类继承的时候,如果你的minSdkVersion <= 11,需要引入V4包,然后倒入android.support.v4.app.Fragment包。如果是大于11,直接导入android.app.Fragment包即可。

package com.jacksen.demo.view.fragments;import android.content.Context;import android.os.Bundle;import android.support.v4.app.Fragment;import android.support.v7.widget.GridLayoutManager;import android.support.v7.widget.LinearLayoutManager;import android.support.v7.widget.RecyclerView;import android.util.Log;import android.view.LayoutInflater;import android.view.View;import android.view.ViewGroup;import com.jacksen.demo.view.R;import com.jacksen.demo.view.fragments.dummy.ArticleBean;import com.jacksen.demo.view.fragments.dummy.ArticleBean.ArticleItem;public class HeadlinesFragment extends Fragment {    private static final String ARG_COLUMN_COUNT = "column-count";    private int mColumnCount = 2;    private OnChangeArticleListener mListener;    public HeadlinesFragment() {    }    public static HeadlinesFragment newInstance(int columnCount) {        HeadlinesFragment fragment = new HeadlinesFragment();        Bundle args = new Bundle();        args.putInt(ARG_COLUMN_COUNT, columnCount);        fragment.setArguments(args);        return fragment;    }    @Override    public void onAttach(Context context) {        super.onAttach(context);        Log.d("HeadlinesFragment", "onAttach");        if (context instanceof OnChangeArticleListener) {            mListener = (OnChangeArticleListener) context;        } else {            throw new RuntimeException(context.toString()                    + " must implement OnChangeArticleListener");        }    }    @Override    public void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        Log.d("HeadlinesFragment", "onCreate");        if (getArguments() != null) {            mColumnCount = getArguments().getInt(ARG_COLUMN_COUNT);        }    }    @Override    public View onCreateView(LayoutInflater inflater, ViewGroup container,                             Bundle savedInstanceState) {        Log.d("HeadlinesFragment", "onCreateView");        View view = inflater.inflate(R.layout.fragment_item_list, container, false);        // Set the adapter        if (view instanceof RecyclerView) {            Context context = view.getContext();            RecyclerView recyclerView = (RecyclerView) view;            if (mColumnCount <= 1) {                recyclerView.setLayoutManager(new LinearLayoutManager(context));            } else {                recyclerView.setLayoutManager(new GridLayoutManager(context, mColumnCount));            }            recyclerView.setAdapter(new HeadlinesRecyclerViewAdapter(ArticleBean.ITEMS, mListener));        }        return view;    }    @Override    public void onDetach() {        super.onDetach();        Log.d("HeadlinesFragment", "onDetach");        mListener = null;    }    public interface OnChangeArticleListener {        void onChangeArticle(ArticleItem item);    }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76

动态的添加fragment就需要在代码里面通过FragmentManager等类进行操作:

frameLayout = (FrameLayout) findViewById(R.id.article_frame_layout);fragmentManager = getSupportFragmentManager();articleFragment = ArticleFragment.newInstance();fragmentManager.beginTransaction().replace(R.id.article_frame_layout, articleFragment).commit();
  • 1
  • 2
  • 3
  • 4
  • 1
  • 2
  • 3
  • 4

Fragment的事务管理

android里通过FragmentManager类进行管理fragment,一组对fragment的操作(添加、删除、替换等)称为一个事务,通过FragmentTransaction类来提交执行。也可以把事务添加到回退栈中,进行回滚。这有点类似于数据库的事务机制。

注意:

  • 事物操作最后必须调用commit()才能执行。

  • 调用commit()方法之后,也不是立刻执行;如果需要立刻执行,可以使用executePendingTransactions()方法。

  • 一次性add多个fragment,显示的是最后一个。

  • 任务栈回退针对的是事务,而不是fragment。一次事务操作过程中可以有很多个对fragment的操作。

  • 只能在activity处于可保存状态的情况下,进行事务操作。否则引发如下异常:

java.lang.IllegalStateException: Can not perform this action after onSaveInstanceState
  • 1
  • 1

比如,在onPause()或者onStop()中提交事务,就会出现以上问题,如果非要在这些生命周期里面进行事务提交,请使用FragmentTransaction类的commitAllowingStateLoss()方法,允许状态丢失。

  • 如果activity继承的是AppCompatActivity,onBackPressed()回调函数里面是利用的V4包的getSupportFragmentManager()进行的栈回退,所以做fragment回退的时候需要注意引用的是不是V4包的Fragment类
/**     * Take care of popping the fragment back stack or finishing the activity     * as appropriate.     */    public void onBackPressed() {        if (!mFragments.getSupportFragmentManager().popBackStackImmediate()) {            supportFinishAfterTransition();        }    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

Fragment之间的切换

Fragment的切换就是基本就是利用add()hide()show()replace()这四个方法。

情况一:采用add方式切换fragment

activity:

@Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_test_fragments2);        ButterKnife.bind(this);        FragmentManager fragmentManager = getSupportFragmentManager();        TabFragment1 tabFragment1 = TabFragment1.newInstance();        fragmentManager.beginTransaction().add(R.id.test_fragments_layout, tabFragment1).addToBackStack("tab1").commit();    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

TabFragment1代码:

@Override    public View onCreateView(LayoutInflater inflater, ViewGroup container,                             Bundle savedInstanceState) {        Log.d("TabFragment1", "onCreateView");        View view = inflater.inflate(R.layout.fragment_tab_fragment1, container, false);        ButterKnife.bind(this, view);        openNextBtn.setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View v) {                FragmentManager fragmentManager = getFragmentManager();                TabFragment2 tabFragment2 = TabFragment2.newInstance();                fragmentManager.beginTransaction().add(R.id.test_fragments_layout, tabFragment2).addToBackStack(null).commit();            }        });        return view;    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

TabFragment2代码:

/** * Tab Fragment 2 */public class TabFragment2 extends Fragment {    public TabFragment2() {    }    public static TabFragment2 newInstance() {        TabFragment2 fragment = new TabFragment2();        return fragment;    }    @Override    public void onAttach(Context context) {        super.onAttach(context);        Log.d("TabFragment2", "onAttach");    }    @Override    public void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        Log.d("TabFragment2", "onCreate");        if (getArguments() != null) {        }    }    @Override    public View onCreateView(LayoutInflater inflater, ViewGroup container,                             Bundle savedInstanceState) {        Log.d("TabFragment2", "onCreateView");        return inflater.inflate(R.layout.fragment_tab_fragment2, container, false);    }    @Override    public void onDestroyView() {        super.onDestroyView();        Log.d("TabFragment2", "onDestroyView");    }    @Override    public void onDestroy() {        super.onDestroy();        Log.d("TabFragment2", "onDestroy");    }    @Override    public void onDetach() {        super.onDetach();        Log.d("TabFragment2", "onDetach");    }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44

此时都是采用add的方式进行显示fragment。每次都会把添加fragment的事务叠加到回退栈上面。

在TabFragment1界面点击按钮添加TabFragment2界面,然后在按返回键回退,打印出生命周期如下:

这里写图片描述

情况二:采用replace的方式切换fragment

activity代码不变。

TabFragment1的代码如下:

@Override    public View onCreateView(LayoutInflater inflater, ViewGroup container,                             Bundle savedInstanceState) {        Log.d("TabFragment1", "onCreateView");        View view = inflater.inflate(R.layout.fragment_tab_fragment1, container, false);        ButterKnife.bind(this, view);        openNextBtn.setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View v) {                FragmentManager fragmentManager = getFragmentManager();                TabFragment2 tabFragment2 = TabFragment2.newInstance();                fragmentManager.beginTransaction().replace(R.id.test_fragments_layout, tabFragment2).addToBackStack(null).commit();            }        });        return view;    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

TabFragment1切换到TabFragment2的时候,使用的replace方法。replace方法的作用是remove掉所有添加到相同id的容器里的fragment,然后添加参数里的fragment。所以会回调TabFragment1的onDestoryView()方法,等到从TabFragment2返回的时候,去执行replace事务的相反操作,也就会重新创建TabFragment1的视图,回调onCreateView()方法。

图片名称

这里写图片描述

remove:

我们在TabFragment2界面中调用remove方法,把TabFragment1移除掉。

TabFragment1.java:

@Override    public View onCreateView(LayoutInflater inflater, ViewGroup container,                             Bundle savedInstanceState) {        Log.d("TabFragment1", "onCreateView");        View view = inflater.inflate(R.layout.fragment_tab_fragment1, container, false);        ButterKnife.bind(this, view);        openNextBtn.setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View v) {                FragmentManager fragmentManager = getFragmentManager();                TabFragment2 tabFragment2 = TabFragment2.newInstance();                fragmentManager.beginTransaction().add(R.id.test_fragments_layout, tabFragment2).addToBackStack(null).commit();            }        });        return view;    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

TabFragment2.java:

private onBtnClickListener onBtnClickListener;    public TabFragment2() {    }    public static TabFragment2 newInstance() {        TabFragment2 fragment = new TabFragment2();        return fragment;    }    @Override    public void onAttach(Context context) {        super.onAttach(context);        Log.d("TabFragment2", "onAttach");        if (context instanceof onBtnClickListener){            onBtnClickListener = (TabFragment2.onBtnClickListener) context;        }else{            throw new RuntimeException(context.toString()                    + " must implement onBtnClickListener");        }    }    @Override    public void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        Log.d("TabFragment2", "onCreate");        if (getArguments() != null) {        }    }    @Override    public View onCreateView(LayoutInflater inflater, ViewGroup container,                             Bundle savedInstanceState) {        Log.d("TabFragment2", "onCreateView");        View view = inflater.inflate(R.layout.fragment_tab_fragment2, container, false);        ButterKnife.bind(this, view);        removeFragmentBtn.setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View v) {                onBtnClickListener.removeFragment1();            }        });        return view;    }    public interface onBtnClickListener{        void removeFragment1();    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42

activity:

 @Override    public void removeFragment1() {        fragmentManager.beginTransaction().remove(tabFragment1).commit();    }
  • 1
  • 2
  • 3
  • 4
  • 1
  • 2
  • 3
  • 4

从代码里看到,remove操作的事务没有添加到回退栈中,所以从TabFragment2中返回的时候,直接退到了activity界面。

图片名称

但是从界面来看,从TabFragment2会退到activity之后,再次按返回键并没有退出activity,然后再按返回键的时候才会退出activity。原因就是,虽然remove了TabFragment1,但是只是回调了onDestoryView()方法销毁了视图,此时TabFragment1的对象资源和与activity的关联还没有断开。所以点击返回键的时候会有一个没有“响应”。

下面看看我们把reomve()操作添加到回退栈的情况:

@Override    public void removeFragment1() {        fragmentManager.beginTransaction().remove(tabFragment1).addToBackStack("remove").commit();    }
  • 1
  • 2
  • 3
  • 4
  • 1
  • 2
  • 3
  • 4

图片名称

与上面的情况相比,多了TabFragment1的onCreateView()这一步。这是因为把remove事务添加到了任务栈,回退的时候逆向执行该操作。

使用replace()方法和remove()方法会导致视图销毁,所以,切换fragment的时候,如果需要视图保留视图,就不能用这两个方法。


Fragment与Activity之间传值

  • fragment –> activity 99%的做法都是通过接口回调来做的。定义一个接口,activity中实现此接口方法,在fragment里面调用接口方法

  • activity –> fragment 通过findFragmentById()后者findFragmentByTag()方法获取fragment实例调用fragment里的public方法即可。

接着往下看~~

TabFragment2调用接口方法:

 @Override    public View onCreateView(LayoutInflater inflater, ViewGroup container,                             Bundle savedInstanceState) {        Log.d("TabFragment2", "onCreateView");        View view = inflater.inflate(R.layout.fragment_tab_fragment2, container, false);        ButterKnife.bind(this, view);        removeFragmentBtn.setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View v) {                onBtnClickListener.removeFragment1();            }        });        tellSthBtn.setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View v) {                onBtnClickListener.tellSth("这是我要对你说的话!");            }        });        return view;    }    /**     * 回调接口     */    public interface onBtnClickListener {        void removeFragment1();        void tellSth(String str);    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27

activity实现该接口的方法:

public class TestFragments extends AppCompatActivity implements TabFragment2.onBtnClickListener {    @Bind(R.id.test_fragments_layout)    FrameLayout testFragmentsLayout;    private FragmentManager fragmentManager;    private TabFragment1 tabFragment1;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_test_fragments2);        ButterKnife.bind(this);        fragmentManager = getSupportFragmentManager();        tabFragment1 = TabFragment1.newInstance();        fragmentManager.beginTransaction().add(R.id.test_fragments_layout, tabFragment1, "tab1").addToBackStack("tab1").commit();    }    @Override    public void onBackPressed() {        super.onBackPressed();    }    @Override    public void removeFragment1() {        fragmentManager.beginTransaction().remove(tabFragment1).addToBackStack("remove").commit();    }    @Override    public void tellSth(String str) {        ((TabFragment1)fragmentManager.findFragmentByTag("tab1")).showSth("hello: " + str);    }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27

在TabFragment1中定义方法供activity调用:

    public void showSth(String str) {        getSthEt.setText(str);    }
  • 1
  • 2
  • 3
  • 1
  • 2
  • 3

这里写图片描述


Fragment与Fragment传值

activity给fragment传值你回了,fragment给activity传值你也会了。那么这个问题就不要问我了!!!


Fragment切换动画

Fragment的切换动画可以使用系统的标准动画,也可以自定义动画。 
使用系统的需要用到setTransition(),但是只能设置系统提供的有限的动画效果。

  • FragmentTransaction.TRANSIT_FRAGMENT_OPEN

  • FragmentTransaction.TRANSIT_FRAGMENT_CLOSE

  • FragmentTransaction.TRANSIT_FRAGMENT_FADE

自定义动画需要用到的类:

/**     * Set specific animation resources to run for the fragments that are     * entering and exiting in this transaction. These animations will not be     * played when popping the back stack.     */    public abstract FragmentTransaction setCustomAnimations(@AnimRes int enter,            @AnimRes int exit);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
/**     * Set specific animation resources to run for the fragments that are     * entering and exiting in this transaction. The <code>popEnter</code>     * and <code>popExit</code> animations will be played for enter/exit     * operations specifically when popping the back stack.     */    public abstract FragmentTransaction setCustomAnimations(@AnimRes int enter,            @AnimRes int exit, @AnimRes int popEnter, @AnimRes int popExit);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

注意:

setCustomAnimations()必须在add()、remove()、replace()调用之前设置,否则不起作用。 

比如:有两个fragment A和B,从A切换到B的时候

  • @AnimRes int enter 
    表示Fragment B的进入动画

  • @AnimRes int exit 
    表示Fragment A的退出动画

  • @AnimRes int popEnter 
    表示当从B界面pop回到A时,Fragment A的进入动画

  • @AnimRes int popExit 
    表示当从B界面pop回到A是,Fragment B的退出动画

如果使用add的方式显示下一个fragment,则只会触发enter 和 popExit动画,因为这种情况下A并没有被移除,只是触发了与B相关的动画。

比如: 
从TabFragment1使用add()方式显示TabFragment2:

FragmentManager fragmentManager = getFragmentManager();TabFragment2 tabFragment2 = TabFragment2.newInstance();FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();fragmentTransaction.setCustomAnimations(R.anim.slide_in_from_right, R.anim.slide_out_to_left, R.anim.slide_in_from_top, R.anim.slide_out_to_bottom);fragmentTransaction.add(R.id.test_fragments_layout, tabFragment2, "tab2");fragmentTransaction.addToBackStack("tab2");fragmentTransaction.commit();
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

4个动画都是使用的简单的view动画,用属性动画可以做出更加绚丽的动画:

slide_in_from_right.xml

<?xml version="1.0" encoding="utf-8"?><translate xmlns:android="http://schemas.android.com/apk/res/android"    android:duration="800"    android:fromXDelta="100.0%"    android:interpolator="@android:interpolator/accelerate_decelerate_interpolator"    android:toXDelta="0.0" />
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

slide_out_to_left.xml

<?xml version="1.0" encoding="utf-8"?><translate xmlns:android="http://schemas.android.com/apk/res/android"    android:duration="800"    android:fromXDelta="0.0"    android:interpolator="@android:interpolator/accelerate_decelerate_interpolator"    android:toXDelta="-100%" />
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

slide_in_from_top.xml

<?xml version="1.0" encoding="utf-8"?><translate xmlns:android="http://schemas.android.com/apk/res/android"    android:duration="1000"    android:fromYDelta="-100.0%"    android:interpolator="@android:interpolator/accelerate_decelerate"    android:toYDelta="0.0" />
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

slide_out_to_bottom.xml

<?xml version="1.0" encoding="utf-8"?><translate xmlns:android="http://schemas.android.com/apk/res/android"    android:duration="1000"    android:fromYDelta="0"    android:interpolator="@android:interpolator/accelerate_decelerate"    android:toYDelta="100%p" />
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

效果图:

这里写图片描述

如果采用的replace的方式,则会正常的触发4个动画。

FragmentManager fragmentManager = getFragmentManager();TabFragment2 tabFragment2 = TabFragment2.newInstance();FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();fragmentTransaction.setCustomAnimations(R.anim.slide_in_from_right, R.anim.slide_out_to_left, R.anim.slide_in_from_top, R.anim.slide_out_to_bottom);fragmentTransaction.replace(R.id.test_fragments_layout, tabFragment2, "tab2");fragmentTransaction.addToBackStack("tab2");fragmentTransaction.commit();
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

这里写图片描述

这里只介绍了setCustomAnimations()的用法,setTransition()方式的动画很简单,就不介绍了。


目录(?)[-]

  1. Fragment
    1. fragment生命周期
    2. fragment的使用
    3. Fragment的事务管理
    4. Fragment之间的切换
    5. Fragment与Activity之间传值
    6. Fragment与Fragment传值
    7. Fragment切换动画

转载请注明出处:http://blog.csdn.net/crazy1235/article/details/50933621


Fragment

还是先来基本介绍。

Fragment –> 片段。 
在Android3.0的时候被引入,它的出现主要是给大屏幕设备提供更加灵活的UI支持。通过对Activity布局进行分片,更加方便的对每块进行独立控制。这些片段可以被不同的activity复用。


fragment生命周期

每个fragment拥有自己的生命周期,但是fragment要依赖于activity存在,生命周期受到包括它的activity的生命周期控制。

来两张神图~~

这里写图片描述 这里写图片描述

左图就是fragment的生命周期图。右图是fragment与activity各自生命周期的对照。

介绍一下常用的几个生命周期函数:

  • onAttach(Context) –> 当fragment被绑定到activity上时回调

  • onCreate(Bundle) –> 当fragment对象创建的时候回调,一般在此方法里做参数接收。

  • onCreateView(LayoutInflater, ViewGroup, Bundle) –> 创建fragment视图时回调

  • onDestoryView –> 视图销毁时回调

  • onDestory –> 销毁fragment时回调

  • onDetech() –> fragment与activity失去关联时回调


fragment的使用

使用fragment可以当成一个控件,直接放到activity布局文件里;也可以在代码里面动态的添加、更新或者删除。

下面的activity布局文件中定义了一个fragment和一个frameLayout。使用标签可以称之为静态的Fragment,在activity创建的时候也会去创建并显示它,而framelayout是一个容器,我们在代码中可以动态的添加一个fragment进去。

<?xml version="1.0" encoding="utf-8"?><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="horizontal"    tools:context=".fragments.ArticleActivity">    <!--headlines-->    <fragment        android:id="@+id/headline_fragment"        android:name="com.jacksen.demo.view.fragments.HeadlinesFragment"        android:layout_width="0dp"        android:layout_height="match_parent"        android:layout_weight="1"        tools:layout="@layout/fragment_item_list" />    <!--article-->    <FrameLayout        android:id="@+id/article_frame_layout"        android:layout_width="0dp"        android:layout_height="match_parent"        android:layout_weight="2" /></LinearLayout>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22

注意:

使用标签显示Fragment的时候,需要对这个fragment设置一个id或者tag,否则会出现”Error inflating class fragment”错误。

这里写图片描述

Caused by: java.lang.IllegalArgumentException: Binary XML file line #10: Must specify unique android:id, android:tag, or have a parent with an id for com.jacksen.demo.view.fragments.HeadlinesFragment
  • 1
  • 1

Fragment的子类继承的时候,如果你的minSdkVersion <= 11,需要引入V4包,然后倒入android.support.v4.app.Fragment包。如果是大于11,直接导入android.app.Fragment包即可。

package com.jacksen.demo.view.fragments;import android.content.Context;import android.os.Bundle;import android.support.v4.app.Fragment;import android.support.v7.widget.GridLayoutManager;import android.support.v7.widget.LinearLayoutManager;import android.support.v7.widget.RecyclerView;import android.util.Log;import android.view.LayoutInflater;import android.view.View;import android.view.ViewGroup;import com.jacksen.demo.view.R;import com.jacksen.demo.view.fragments.dummy.ArticleBean;import com.jacksen.demo.view.fragments.dummy.ArticleBean.ArticleItem;public class HeadlinesFragment extends Fragment {    private static final String ARG_COLUMN_COUNT = "column-count";    private int mColumnCount = 2;    private OnChangeArticleListener mListener;    public HeadlinesFragment() {    }    public static HeadlinesFragment newInstance(int columnCount) {        HeadlinesFragment fragment = new HeadlinesFragment();        Bundle args = new Bundle();        args.putInt(ARG_COLUMN_COUNT, columnCount);        fragment.setArguments(args);        return fragment;    }    @Override    public void onAttach(Context context) {        super.onAttach(context);        Log.d("HeadlinesFragment", "onAttach");        if (context instanceof OnChangeArticleListener) {            mListener = (OnChangeArticleListener) context;        } else {            throw new RuntimeException(context.toString()                    + " must implement OnChangeArticleListener");        }    }    @Override    public void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        Log.d("HeadlinesFragment", "onCreate");        if (getArguments() != null) {            mColumnCount = getArguments().getInt(ARG_COLUMN_COUNT);        }    }    @Override    public View onCreateView(LayoutInflater inflater, ViewGroup container,                             Bundle savedInstanceState) {        Log.d("HeadlinesFragment", "onCreateView");        View view = inflater.inflate(R.layout.fragment_item_list, container, false);        // Set the adapter        if (view instanceof RecyclerView) {            Context context = view.getContext();            RecyclerView recyclerView = (RecyclerView) view;            if (mColumnCount <= 1) {                recyclerView.setLayoutManager(new LinearLayoutManager(context));            } else {                recyclerView.setLayoutManager(new GridLayoutManager(context, mColumnCount));            }            recyclerView.setAdapter(new HeadlinesRecyclerViewAdapter(ArticleBean.ITEMS, mListener));        }        return view;    }    @Override    public void onDetach() {        super.onDetach();        Log.d("HeadlinesFragment", "onDetach");        mListener = null;    }    public interface OnChangeArticleListener {        void onChangeArticle(ArticleItem item);    }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76

动态的添加fragment就需要在代码里面通过FragmentManager等类进行操作:

frameLayout = (FrameLayout) findViewById(R.id.article_frame_layout);fragmentManager = getSupportFragmentManager();articleFragment = ArticleFragment.newInstance();fragmentManager.beginTransaction().replace(R.id.article_frame_layout, articleFragment).commit();
  • 1
  • 2
  • 3
  • 4
  • 1
  • 2
  • 3
  • 4

Fragment的事务管理

android里通过FragmentManager类进行管理fragment,一组对fragment的操作(添加、删除、替换等)称为一个事务,通过FragmentTransaction类来提交执行。也可以把事务添加到回退栈中,进行回滚。这有点类似于数据库的事务机制。

注意:

  • 事物操作最后必须调用commit()才能执行。

  • 调用commit()方法之后,也不是立刻执行;如果需要立刻执行,可以使用executePendingTransactions()方法。

  • 一次性add多个fragment,显示的是最后一个。

  • 任务栈回退针对的是事务,而不是fragment。一次事务操作过程中可以有很多个对fragment的操作。

  • 只能在activity处于可保存状态的情况下,进行事务操作。否则引发如下异常:

java.lang.IllegalStateException: Can not perform this action after onSaveInstanceState
  • 1
  • 1

比如,在onPause()或者onStop()中提交事务,就会出现以上问题,如果非要在这些生命周期里面进行事务提交,请使用FragmentTransaction类的commitAllowingStateLoss()方法,允许状态丢失。

  • 如果activity继承的是AppCompatActivity,onBackPressed()回调函数里面是利用的V4包的getSupportFragmentManager()进行的栈回退,所以做fragment回退的时候需要注意引用的是不是V4包的Fragment类
/**     * Take care of popping the fragment back stack or finishing the activity     * as appropriate.     */    public void onBackPressed() {        if (!mFragments.getSupportFragmentManager().popBackStackImmediate()) {            supportFinishAfterTransition();        }    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

Fragment之间的切换

Fragment的切换就是基本就是利用add()hide()show()replace()这四个方法。

情况一:采用add方式切换fragment

activity:

@Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_test_fragments2);        ButterKnife.bind(this);        FragmentManager fragmentManager = getSupportFragmentManager();        TabFragment1 tabFragment1 = TabFragment1.newInstance();        fragmentManager.beginTransaction().add(R.id.test_fragments_layout, tabFragment1).addToBackStack("tab1").commit();    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

TabFragment1代码:

@Override    public View onCreateView(LayoutInflater inflater, ViewGroup container,                             Bundle savedInstanceState) {        Log.d("TabFragment1", "onCreateView");        View view = inflater.inflate(R.layout.fragment_tab_fragment1, container, false);        ButterKnife.bind(this, view);        openNextBtn.setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View v) {                FragmentManager fragmentManager = getFragmentManager();                TabFragment2 tabFragment2 = TabFragment2.newInstance();                fragmentManager.beginTransaction().add(R.id.test_fragments_layout, tabFragment2).addToBackStack(null).commit();            }        });        return view;    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

TabFragment2代码:

/** * Tab Fragment 2 */public class TabFragment2 extends Fragment {    public TabFragment2() {    }    public static TabFragment2 newInstance() {        TabFragment2 fragment = new TabFragment2();        return fragment;    }    @Override    public void onAttach(Context context) {        super.onAttach(context);        Log.d("TabFragment2", "onAttach");    }    @Override    public void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        Log.d("TabFragment2", "onCreate");        if (getArguments() != null) {        }    }    @Override    public View onCreateView(LayoutInflater inflater, ViewGroup container,                             Bundle savedInstanceState) {        Log.d("TabFragment2", "onCreateView");        return inflater.inflate(R.layout.fragment_tab_fragment2, container, false);    }    @Override    public void onDestroyView() {        super.onDestroyView();        Log.d("TabFragment2", "onDestroyView");    }    @Override    public void onDestroy() {        super.onDestroy();        Log.d("TabFragment2", "onDestroy");    }    @Override    public void onDetach() {        super.onDetach();        Log.d("TabFragment2", "onDetach");    }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44

此时都是采用add的方式进行显示fragment。每次都会把添加fragment的事务叠加到回退栈上面。

在TabFragment1界面点击按钮添加TabFragment2界面,然后在按返回键回退,打印出生命周期如下:

这里写图片描述

情况二:采用replace的方式切换fragment

activity代码不变。

TabFragment1的代码如下:

@Override    public View onCreateView(LayoutInflater inflater, ViewGroup container,                             Bundle savedInstanceState) {        Log.d("TabFragment1", "onCreateView");        View view = inflater.inflate(R.layout.fragment_tab_fragment1, container, false);        ButterKnife.bind(this, view);        openNextBtn.setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View v) {                FragmentManager fragmentManager = getFragmentManager();                TabFragment2 tabFragment2 = TabFragment2.newInstance();                fragmentManager.beginTransaction().replace(R.id.test_fragments_layout, tabFragment2).addToBackStack(null).commit();            }        });        return view;    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

TabFragment1切换到TabFragment2的时候,使用的replace方法。replace方法的作用是remove掉所有添加到相同id的容器里的fragment,然后添加参数里的fragment。所以会回调TabFragment1的onDestoryView()方法,等到从TabFragment2返回的时候,去执行replace事务的相反操作,也就会重新创建TabFragment1的视图,回调onCreateView()方法。

图片名称

这里写图片描述

remove:

我们在TabFragment2界面中调用remove方法,把TabFragment1移除掉。

TabFragment1.java:

@Override    public View onCreateView(LayoutInflater inflater, ViewGroup container,                             Bundle savedInstanceState) {        Log.d("TabFragment1", "onCreateView");        View view = inflater.inflate(R.layout.fragment_tab_fragment1, container, false);        ButterKnife.bind(this, view);        openNextBtn.setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View v) {                FragmentManager fragmentManager = getFragmentManager();                TabFragment2 tabFragment2 = TabFragment2.newInstance();                fragmentManager.beginTransaction().add(R.id.test_fragments_layout, tabFragment2).addToBackStack(null).commit();            }        });        return view;    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

TabFragment2.java:

private onBtnClickListener onBtnClickListener;    public TabFragment2() {    }    public static TabFragment2 newInstance() {        TabFragment2 fragment = new TabFragment2();        return fragment;    }    @Override    public void onAttach(Context context) {        super.onAttach(context);        Log.d("TabFragment2", "onAttach");        if (context instanceof onBtnClickListener){            onBtnClickListener = (TabFragment2.onBtnClickListener) context;        }else{            throw new RuntimeException(context.toString()                    + " must implement onBtnClickListener");        }    }    @Override    public void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        Log.d("TabFragment2", "onCreate");        if (getArguments() != null) {        }    }    @Override    public View onCreateView(LayoutInflater inflater, ViewGroup container,                             Bundle savedInstanceState) {        Log.d("TabFragment2", "onCreateView");        View view = inflater.inflate(R.layout.fragment_tab_fragment2, container, false);        ButterKnife.bind(this, view);        removeFragmentBtn.setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View v) {                onBtnClickListener.removeFragment1();            }        });        return view;    }    public interface onBtnClickListener{        void removeFragment1();    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42

activity:

 @Override    public void removeFragment1() {        fragmentManager.beginTransaction().remove(tabFragment1).commit();    }
  • 1
  • 2
  • 3
  • 4
  • 1
  • 2
  • 3
  • 4

从代码里看到,remove操作的事务没有添加到回退栈中,所以从TabFragment2中返回的时候,直接退到了activity界面。

图片名称

但是从界面来看,从TabFragment2会退到activity之后,再次按返回键并没有退出activity,然后再按返回键的时候才会退出activity。原因就是,虽然remove了TabFragment1,但是只是回调了onDestoryView()方法销毁了视图,此时TabFragment1的对象资源和与activity的关联还没有断开。所以点击返回键的时候会有一个没有“响应”。

下面看看我们把reomve()操作添加到回退栈的情况:

@Override    public void removeFragment1() {        fragmentManager.beginTransaction().remove(tabFragment1).addToBackStack("remove").commit();    }
  • 1
  • 2
  • 3
  • 4
  • 1
  • 2
  • 3
  • 4

图片名称

与上面的情况相比,多了TabFragment1的onCreateView()这一步。这是因为把remove事务添加到了任务栈,回退的时候逆向执行该操作。

使用replace()方法和remove()方法会导致视图销毁,所以,切换fragment的时候,如果需要视图保留视图,就不能用这两个方法。


Fragment与Activity之间传值

  • fragment –> activity 99%的做法都是通过接口回调来做的。定义一个接口,activity中实现此接口方法,在fragment里面调用接口方法

  • activity –> fragment 通过findFragmentById()后者findFragmentByTag()方法获取fragment实例调用fragment里的public方法即可。

接着往下看~~

TabFragment2调用接口方法:

 @Override    public View onCreateView(LayoutInflater inflater, ViewGroup container,                             Bundle savedInstanceState) {        Log.d("TabFragment2", "onCreateView");        View view = inflater.inflate(R.layout.fragment_tab_fragment2, container, false);        ButterKnife.bind(this, view);        removeFragmentBtn.setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View v) {                onBtnClickListener.removeFragment1();            }        });        tellSthBtn.setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View v) {                onBtnClickListener.tellSth("这是我要对你说的话!");            }        });        return view;    }    /**     * 回调接口     */    public interface onBtnClickListener {        void removeFragment1();        void tellSth(String str);    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27

activity实现该接口的方法:

public class TestFragments extends AppCompatActivity implements TabFragment2.onBtnClickListener {    @Bind(R.id.test_fragments_layout)    FrameLayout testFragmentsLayout;    private FragmentManager fragmentManager;    private TabFragment1 tabFragment1;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_test_fragments2);        ButterKnife.bind(this);        fragmentManager = getSupportFragmentManager();        tabFragment1 = TabFragment1.newInstance();        fragmentManager.beginTransaction().add(R.id.test_fragments_layout, tabFragment1, "tab1").addToBackStack("tab1").commit();    }    @Override    public void onBackPressed() {        super.onBackPressed();    }    @Override    public void removeFragment1() {        fragmentManager.beginTransaction().remove(tabFragment1).addToBackStack("remove").commit();    }    @Override    public void tellSth(String str) {        ((TabFragment1)fragmentManager.findFragmentByTag("tab1")).showSth("hello: " + str);    }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27

在TabFragment1中定义方法供activity调用:

    public void showSth(String str) {        getSthEt.setText(str);    }
  • 1
  • 2
  • 3
  • 1
  • 2
  • 3

这里写图片描述


Fragment与Fragment传值

activity给fragment传值你回了,fragment给activity传值你也会了。那么这个问题就不要问我了!!!


Fragment切换动画

Fragment的切换动画可以使用系统的标准动画,也可以自定义动画。 
使用系统的需要用到setTransition(),但是只能设置系统提供的有限的动画效果。

  • FragmentTransaction.TRANSIT_FRAGMENT_OPEN

  • FragmentTransaction.TRANSIT_FRAGMENT_CLOSE

  • FragmentTransaction.TRANSIT_FRAGMENT_FADE

自定义动画需要用到的类:

/**     * Set specific animation resources to run for the fragments that are     * entering and exiting in this transaction. These animations will not be     * played when popping the back stack.     */    public abstract FragmentTransaction setCustomAnimations(@AnimRes int enter,            @AnimRes int exit);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
/**     * Set specific animation resources to run for the fragments that are     * entering and exiting in this transaction. The <code>popEnter</code>     * and <code>popExit</code> animations will be played for enter/exit     * operations specifically when popping the back stack.     */    public abstract FragmentTransaction setCustomAnimations(@AnimRes int enter,            @AnimRes int exit, @AnimRes int popEnter, @AnimRes int popExit);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

注意:

setCustomAnimations()必须在add()、remove()、replace()调用之前设置,否则不起作用。 

比如:有两个fragment A和B,从A切换到B的时候

  • @AnimRes int enter 
    表示Fragment B的进入动画

  • @AnimRes int exit 
    表示Fragment A的退出动画

  • @AnimRes int popEnter 
    表示当从B界面pop回到A时,Fragment A的进入动画

  • @AnimRes int popExit 
    表示当从B界面pop回到A是,Fragment B的退出动画

如果使用add的方式显示下一个fragment,则只会触发enter 和 popExit动画,因为这种情况下A并没有被移除,只是触发了与B相关的动画。

比如: 
从TabFragment1使用add()方式显示TabFragment2:

FragmentManager fragmentManager = getFragmentManager();TabFragment2 tabFragment2 = TabFragment2.newInstance();FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();fragmentTransaction.setCustomAnimations(R.anim.slide_in_from_right, R.anim.slide_out_to_left, R.anim.slide_in_from_top, R.anim.slide_out_to_bottom);fragmentTransaction.add(R.id.test_fragments_layout, tabFragment2, "tab2");fragmentTransaction.addToBackStack("tab2");fragmentTransaction.commit();
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

4个动画都是使用的简单的view动画,用属性动画可以做出更加绚丽的动画:

slide_in_from_right.xml

<?xml version="1.0" encoding="utf-8"?><translate xmlns:android="http://schemas.android.com/apk/res/android"    android:duration="800"    android:fromXDelta="100.0%"    android:interpolator="@android:interpolator/accelerate_decelerate_interpolator"    android:toXDelta="0.0" />
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

slide_out_to_left.xml

<?xml version="1.0" encoding="utf-8"?><translate xmlns:android="http://schemas.android.com/apk/res/android"    android:duration="800"    android:fromXDelta="0.0"    android:interpolator="@android:interpolator/accelerate_decelerate_interpolator"    android:toXDelta="-100%" />
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

slide_in_from_top.xml

<?xml version="1.0" encoding="utf-8"?><translate xmlns:android="http://schemas.android.com/apk/res/android"    android:duration="1000"    android:fromYDelta="-100.0%"    android:interpolator="@android:interpolator/accelerate_decelerate"    android:toYDelta="0.0" />
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

slide_out_to_bottom.xml

<?xml version="1.0" encoding="utf-8"?><translate xmlns:android="http://schemas.android.com/apk/res/android"    android:duration="1000"    android:fromYDelta="0"    android:interpolator="@android:interpolator/accelerate_decelerate"    android:toYDelta="100%p" />
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

效果图:

这里写图片描述

如果采用的replace的方式,则会正常的触发4个动画。

FragmentManager fragmentManager = getFragmentManager();TabFragment2 tabFragment2 = TabFragment2.newInstance();FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();fragmentTransaction.setCustomAnimations(R.anim.slide_in_from_right, R.anim.slide_out_to_left, R.anim.slide_in_from_top, R.anim.slide_out_to_bottom);fragmentTransaction.replace(R.id.test_fragments_layout, tabFragment2, "tab2");fragmentTransaction.addToBackStack("tab2");fragmentTransaction.commit();
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

这里写图片描述

这里只介绍了setCustomAnimations()的用法,setTransition()方式的动画很简单,就不介绍了。

0 0
原创粉丝点击