美文网首页
Fragment的使用

Fragment的使用

作者: 破荒之恋 | 来源:发表于2016-12-27 13:14 被阅读241次

    Fragment的使用

    原文:http://developer.android.com/training/basics/fragments/creating.html

    • 我们可以把fragment想象成activity中一个模块化的部分,它拥有自己的生命周期,接收自己的输入事件,可以在acvitity运行过程中添加或者移除(有点像"子activity",可以在不同的activity里面重复使用)。这一课教我们将学习继承Support Library 中的Fragment,使应用在Android1.6这样的低版本上仍能保持兼容。
    • Note: 如果APP的最低API版本是11或以上,则不必使用Support Library,我们可以直接使用API框架中的Fragment,本课主要讲解基于Support Library的API,Support Library有一个特殊的包名,有时与平台版本的API名字存在略微不同。
    • 在开始这节课前,必须先让在项目中引用Support Library。如果没有使用过Support Library,可以根据文档 Support Library Setup 来设置项目使用Support Library。当然,也可以使用包含action bar的 v7 appcompat library。v7 appcompat library 兼容Android2.1(API level 7),也包含了Fragment APIs。

    创建一个Fragment类

    • 创建一个fragment,首先需要继承Fragment类,然后在关键的生命周期方法中插入APP的逻辑,就像activity一样。
    • 其中一个区别是当创建Fragment的时,必须重写onCreateView()回调方法来定义布局。事实上,这是使Fragment运行起来,唯一一个需要我们重写的回调方法。比如,下面是一个自定义布局的示例fragment.
    import android.os.Bundle;
    import android.support.v4.app.Fragment;
    import android.view.LayoutInflater;
    import android.view.ViewGroup;
    
    public class ArticleFragment extends Fragment {
        @Override
        public View onCreateView(LayoutInflater inflater, ViewGroup container,
            Bundle savedInstanceState) {
            // Inflate the layout for this fragment
            return inflater.inflate(R.layout.article_view, container, false);
        }
    }
    

    就像activity一样,当fragment从activity添加或者移除、当activity生命周期发生变化时,fragment通过生命周期回调函数管理其状态。例如,当activity的onPause()被调用时,它里面的所有fragment的onPause()方法也会被触发。

    更多关于fragment的声明周期和回调方法,详见Fragments developer guide.
    用XML将fragment添加到activity

    fragments是可重用的,模块化的UI组件,每个Fragment的实例都必须与一个FragmentActivity关联。我们可以在activity的XML布局文件中定义每一个fragment来实现这种关联。

    • Notes:FragmentActivity是Support Library提供的一个特殊activity ,用于处理API11版本以下的fragment。如果我们APP中的最低版本大于等于11,则可以使用普通的Activity。

    下面是一个XML布局的例子,当屏幕被认为是large(用目录名称中的large字符来区分)时,它在布局中增加了两个fragment.

    res/layout-large/news_articles.xml
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:orientation="horizontal"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent">
    
        <fragment android:name="com.example.android.fragments.HeadlinesFragment"
                  android:id="@+id/headlines_fragment"
                  android:layout_weight="1"
                  android:layout_width="0dp"
                  android:layout_height="match_parent" />
    
        <fragment android:name="com.example.android.fragments.ArticleFragment"
                  android:id="@+id/article_fragment"
                  android:layout_weight="2"
                  android:layout_width="0dp"
                  android:layout_height="match_parent" />
    
    </LinearLayout>
    
    • Notes:更多关于不同屏幕尺寸创建不同布局的信息,请阅读Supporting Different Screen Sizes

    然后将这个布局文件用到activity中。

    import android.os.Bundle;
    import android.support.v4.app.FragmentActivity;
    
    public class MainActivity extends FragmentActivity {
        @Override
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.news_articles);
        }
    }
    
    • 如果用的是 v7 appcompat library,activity应该改为继承ActionBarActivity,ActionBarActivity是FragmentActivity的一个子类(更多关于这方面的内容,请阅读Adding the Action Bar)。
    • Note:当通过XML布局文件的方式将Fragment添加进activity时,Fragment是不能被动态移除的。如果想要在用户交互的时候把fragment切入与切出,必须在activity启动后,再将fragment添加进activity。这部分内容将在下节课阐述。
    • FragmentManager类为在activity运行时对fragment进行添加,移除,替换等操作提供了方法,来实现动态的用户体验

    在activity运行时添加fragment

    • 为了执行fragment的增加或者移除操作,必须通过 FragmentManager 创建一个FragmentTransaction对象, FragmentTransaction提供了用来增加、移除、替换以及其它一些操作的APIs。
    • 如果我们的activity允许fragment移除或者替换,我们应该在activity的onCreate()方法中添加初始化fragment(s).
    • 运用fragment(尤其是那些在运行时添加的)的一个很重要的规则就是在布局中必须有一个容器View,fragment的layout将会放在这个view里面。

    下面的这个布局是上节课的一次只显示一个fragment的布局的替代布局。为了替换fragment,这个Activity的布局包含了一个空的 FrameLayout作为fragment的容器。

    res/layout/news_articles.xml:

    <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:id="@+id/fragment_container"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />
    
    • 在activity中,用Support Library APIs调用 getSupportFragmentManager()方法获取FragmentManager 对象,然后调用 beginTransaction() 方法创建一个FragmentTransaction对象,然后调用add()方法添加一个fragment.
      可以使用同一个 FragmentTransaction进行多次fragment事务。完成这些变化操作,准备开始执行改变时,必须调用commit()方法。

    下例显示了如何添加一个fragment到之前的layout中

    import android.os.Bundle;
    import android.support.v4.app.FragmentActivity;
    
    public class MainActivity extends FragmentActivity {
        @Override
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.news_articles);
    
            // Check that the activity is using the layout version with
            // the fragment_container FrameLayout
            if (findViewById(R.id.fragment_container) != null) {
    
            // However, if we're being restored from a previous state,
            // then we don't need to do anything and should return or else
            // we could end up with overlapping fragments.
            if (savedInstanceState != null) {
                return;
            }
    
            // Create a new Fragment to be placed in the activity layout
            HeadlinesFragment firstFragment = new HeadlinesFragment();
    
            // In case this activity was started with special instructions from an
            // Intent, pass the Intent's extras to the fragment as arguments
            firstFragment.setArguments(getIntent().getExtras());
    
            // Add the fragment to the 'fragment_container' FrameLayout
    
            getSupportFragmentManager().beginTransaction()
                    .add(R.id.fragment_container, firstFragment).commit();
        }
    }
    

    }

    因为fragment是在activity运行时被添加进来时(不是在XML布局中用<fragment>定义的),activity 可以移除这个fragment或者用另外一个来替换它。

    替换Fragment

    • 替换fragment的过程类似于添加过程,只需要将add()方法替换为 replace()方法。
      记住在执行fragment事务时,如移除或者替换,我们经常要适当地让用户可以向后导航与"撤销"这次改变。为了让用户向后导航fragment事务,我们必须在FragmentTransaction提交前调用addToBackStack()方法。
    • Note:当移除或者替换一个fragment并把它放入返回栈中时,被移除的fragment的生命周期是stopped(不是destoryed).当用户返回重新恢复这个fragment,它的生命周期是restarts。如果没有把fragment放入返回栈中,那么当它被移除或者替换时,其生命周期是destoryed。

    下面是一个fragment替换的例子

    // Create fragment and give it an argument specifying the article it should show
    ArticleFragment newFragment = new ArticleFragment();
    Bundle args = new Bundle();
    args.putInt(ArticleFragment.ARG_POSITION, position);
    newFragment.setArguments(args);
    
    FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
    
    // Replace whatever is in the fragment_container view with this fragment,
    // and add the transaction to the back stack so the user can navigate back
    transaction.replace(R.id.fragment_container, newFragment);
    transaction.addToBackStack(null);
    
    // Commit the transaction
    transaction.commit();
    
    • addToBackStack()方法提供了一个可选的String参数为事务指定了一个唯一的名字。除非打算用FragmentManager.BackStackEntry APIs来进行一些高级的fragments操作,这个名字不是必须的。
    • 为了重用Fragment UI组件,我们应该把每一个fragment都构建成完全的自包含的、模块化的组件,定义他们自己的布局与行为。定义好这些模块化的Fragment后,就可以让他们关联activity,使他们与application的逻辑结合起来,实现全局的复合的UI。
    • 通常fragment之间可能会需要交互,比如基于用户事件改变fragment的内容。所有fragment之间的交互需要通过他们关联的activity,两个fragment之间不应该直接交互。

    Fragments之间的交互

    原文:http://developer.android.com/training/basics/fragments/communicating.html

    • 为了重用Fragment UI组件,我们应该把每一个fragment都构建成完全的自包含的、模块化的组件,定义他们自己的布局与行为。定义好这些模块化的Fragment后,就可以让他们关联activity,使他们与application的逻辑结合起来,实现全局的复合的UI。
    • 通常fragment之间可能会需要交互,比如基于用户事件改变fragment的内容。所有fragment之间的交互需要通过他们关联的activity,两个fragment之间不应该直接交互。

    定义一个接口

    • 为了让fragment与activity交互,可以在Fragment 类中定义一个接口,并在activity中实现。Fragment在他们生命周期的onAttach()方法中获取接口的实现,然后调用接口的方法来与Activity交互。

    下面是一个fragment与activity交互的例子:

    public class HeadlinesFragment extends ListFragment {
        OnHeadlineSelectedListener mCallback;
    
        // Container Activity must implement this interface
        public interface OnHeadlineSelectedListener {
            public void onArticleSelected(int position);
        }
    
        @Override
        public void onAttach(Activity activity) {
            super.onAttach(activity);
    
            // This makes sure that the container activity has implemented
            // the callback interface. If not, it throws an exception
            try {
                mCallback = (OnHeadlineSelectedListener) activity;
            } catch (ClassCastException e) {
                throw new ClassCastException(activity.toString()
                        + " must implement OnHeadlineSelectedListener");
            }
        }
    
        ...
    }
    

    现在Fragment就可以通过调用OnHeadlineSelectedListener接口实例的mCallback中的onArticleSelected()(也可以是其它方法)方法与activity传递消息。

    举个例子,在fragment中的下面的方法在用户点击列表条目时被调用,fragment 用回调接口来传递事件给父Activity.

    @Override
    public void onListItemClick(ListView l, View v, int position, long id) {
        // Send the event to the host activity
        mCallback.onArticleSelected(position);
    }
    

    实现接口

    为了接收回调事件,宿主activity必须实现在Fragment中定义的接口。

    举个例子,下面的activity实现了上面例子中的接口。

    public static class MainActivity extends Activity
            implements HeadlinesFragment.OnHeadlineSelectedListener{
        ...
    
        public void onArticleSelected(int position) {
            // The user selected the headline of an article from the HeadlinesFragment
            // Do something here to display that article
        }
    }
    

    传消息给Fragment

    宿主activity通过findFragmentById()方法获取fragment的实例,然后直接调用Fragment的public方法来向fragment传递消息。

    例如,假设上面所示的activity可能包含另外一个fragment,这个fragment用来展示从上面的回调方法中返回的指定的数据。在这种情况下,activity可以把从回调方法中接收到的信息传递给这个展示数据的Fragment.

    public static class MainActivity extends Activity
        implements HeadlinesFragment.OnHeadlineSelectedListener{
    ...
    
    public void onArticleSelected(int position) {
        // The user selected the headline of an article from the HeadlinesFragment
        // Do something here to display that article
    
        ArticleFragment articleFrag = (ArticleFragment)
                getSupportFragmentManager().findFragmentById(R.id.article_fragment);
    
        if (articleFrag != null) {
            // If article frag is available, we're in two-pane layout...
    
            // Call a method in the ArticleFragment to update its content
            articleFrag.updateArticleView(position);
        } else {
            // Otherwise, we're in the one-pane layout and must swap frags...
    
            // Create fragment and give it an argument for the selected article
            ArticleFragment newFragment = new ArticleFragment();
            Bundle args = new Bundle();
            args.putInt(ArticleFragment.ARG_POSITION, position);
            newFragment.setArguments(args);
    
            FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
    
            // Replace whatever is in the fragment_container view with this fragment,
            // and add the transaction to the back stack so the user can navigate back
            transaction.replace(R.id.fragment_container, newFragment);
            transaction.addToBackStack(null);
    
            // Commit the transaction
            transaction.commit();
        }
    }
    }
    

    相关文章

      网友评论

          本文标题:Fragment的使用

          本文链接:https://www.haomeiwen.com/subject/xqzsvttx.html