深入学习Fragment

创建一个碎片

创建一个碎片有两种方式,一种是直接在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>
name指定实现类,这样的确定就是这个碎片一直占着位置,不能移除,只能替换,不过我们貌似很少移除(还是用的少),目前的两个例子没有。
一般的大屏都是写这两个,一个列表,一个详情,然后详情被换掉。
对于小屏的,一般就是定义一个Fragment。
<?xml version="1.0" encoding="utf-8"?>
<fragment 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:id="@+id/fragment_forecast"
    android:name="com.loveqiqi.sy.mysunshine.ForecastFragment"
    android:layout_marginLeft="@dimen/activity_horizontal_margin"
    android:layout_marginRight="@dimen/activity_horizontal_margin"
    tools:context="com.loveqiqi.sy.mysunshine.MainActivity"
    tools:layout="@android:layout/list_content"
    >

</fragment>

这两个布局文件分别对于layout-land或larger和layout,系统会帮我们决定加载,然后在活动的OnCreate方法中我们要判断是不是需要替换detail,
Training的例子:
单屏幕定一个定义的容器有唯一id,然后判断,如果这个id的view存在就是单屏幕,这是布局:
<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" />

判断如下:
// Check whether the activity is using the layout version with
// the fragment_container FrameLayout. If so, we must add the first fragment
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 an instance of ExampleFragment
    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();
}

双屏幕的问题就是一进去,要选择合适的或者默认的显示:
Training没有,因为默认的poSition给的是-1,然后判断就不更新了,给个0,就会默认显示第一个,这个还需要学习啊


替换或者删除Fragment

如果替换或者删除碎片,在提交之前调用
transaction.addToBackStack(null);

这样,用户导航返回就可以恢复,取消变化。如果调用了,被替换或者删除的碎片不被销毁,而是停止了,用户返回的话重启,这样会快些吧,碎片的生命周期:

深入学习Fragment_第1张图片

深入学习Fragment_第2张图片


和其他碎片或者活动通信

首先我们看到,碎片是隶属于活动的,碎片直接要是想通信,必须要靠活动这个中转人啊,不然根本就没法用,所以还是和活动通信

碎片定义一个接口,这个接口主要是处理碎片的一些事件,比如选择某个item,但是碎片自己无法启动新的活动或者是替换碎片,就是要告诉活动。
因此定义一个接口,比如:
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");
        }
    }
    
    ...
}
在onAttach中强制转换,这样就系统会用它来帮我们传递信息的。
这样点击事件可以交给这个接口处理,而这个接口就是活动,他只需要实现这个接口:
  @Override
    public void onListItemClick(ListView l, View v, int position, long id) {
        // Send the event to the host activity
        mCallback.onArticleSelected(position);
    }

实现接口活动如下,这样活动就可以处理碎片处理不了事件了。
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();
        }
    }
}


碎片是可复用的子活动,所以它自己处理不了事情就需要交给宿主活动处理,这个宿主活动必须实现碎片定义的接口,接口的参数可以根据我们的需要来定义,这里只有一个

参数,其实多个也可以,根据我们的需要。sunshine就定义了两个,接收查询项的Uri,和位置,一般,位置是必须的,其他看需求吧。

sunshine的活动:其实position是多余的,自己真是多余了,哈哈。

@Override
public void onItemSelected(Uri itemUir, int position) {
    if(mTwoPane){
        Bundle args = new Bundle();
        args.putParcelable(DetailFragment.DETAIL_URI, itemUir);
        //替换DetaiFragment
        DetailFragment detailFragment = new DetailFragment();
        detailFragment.setArguments(args);
        getSupportFragmentManager().beginTransaction().replace(R.id.weather_detail_container, detailFragment, DETAILFRAGMENT_TAG).commit();

    }else{
        Intent intent = new Intent(getApplicationContext(), DetailActivity.class)
                .setData(itemUir);

        startActivity(intent);
    }
}

其实还是不麻烦的,比较好用。

你可能感兴趣的:(深入学习Fragment)