Fragment的使用

原文地址:http://www.cnblogs.com/kross/p/3328389.html

新浪微博:http://weibo.com/u/1928100503

 

折腾了两天,感觉有点会用了,Fragment给我的感觉就是网页上的AJAX,个人感觉,个人感觉O(∩_∩)O。

Fragment可以当成一块视图,可以动态的添加到当前的视图中,也可以进行替换,或者删除,所以才说感觉很像AJAX。

我做的一个demo就是google上的那个例子,显示一个列表,然后点击,页面就变成详细页,不过我是理解后按照自己的想法去实现的。下面就说下怎么操作吧。

 

首先,我们需要一个Activity(activity_main.xml),用来启动的时候显示,但里面并不做任何数据的输出。布局文件如下:

<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="vertical"
    tools:context=".MainActivity" >
    <FrameLayout
        android:id="@+id/pager"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
    </FrameLayout>
</LinearLayout>

需要注意的:里面有一个FrameLayout,属性里有一个id,这样就足够了。

 

然后,我们希望程序启动后页面上显示一个列表(ListView),这个时候,需要用Fragment把列表显示出来,替换到FrameLayout上面,下面我们去实现一个显示列表的TitleFragment

扩展Fragment的时候,有许多方法可以去覆写(Override),也可以不覆写,根据在下的学习与理解,我认为onCreateView()这个方法是返回一个视图的,也就是Fragment这个的视图,因此,如果你的Fragment是要去显示的,肯定要覆写这个方法,然后把视图返回出去。

代码如下,一步步来:

public class TitleFragment extends Fragment {
    
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
            Bundle savedInstanceState) { 
        View v = inflater.inflate(R.layout.title_fragment, container, false);
        return v;
    }
}

 需要注意的是LayoutInflater.inflate()这个方法,很长一段时间,我都木有理解什么叫所谓的“扩充布局”,后来去stackoverflow网站上去找找,老外说:扩充布局这是java里面的一个惯用的说法。实际上就是将一个布局文件(xml)变成一个View对象,在下是这样理解的。Activity中有一个setContentView()的方法,应该也是将布局文件转成一个View对象,然后给Activity设置上。

如上的代码就是要让onCreateView返回一个View对象啦,当然我们这个TitleFragment对象是要显示一个列表的,所以布局中应该有一个ListView的吧,看看布局文件title_fragment.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" >
    <ListView
        android:id="@+id/title_listview"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>
</LinearLayout>

这个布局也是非常的简单的。

我们仅仅是是用inflate()成功获取整个布局是不够的,我们还需要获取的ListView,并且给它设置适配器才算是完成任务。

因为在设置new适配器的时候,第一个参数是Context,所以我们必须获取到TitleFragment所附着的Activity对象,看看回调函数中,发现一个onAttach(Activity activity)这样的函数,可以获取到context对象,因此我们需要在TitleFragment类中声明一个Context的成员属性,并且在onAttach回调函数中把context保存起来,这样在new适配器的时候才有context可以用。

经过以上的加工,TitleFragment.java的代码如下:

public class TitleFragment extends Fragment {
    
    private Context context;
    
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
            Bundle savedInstanceState) { 
        View v = inflater.inflate(R.layout.title_fragment, container, false);
        ListView listView = (ListView)v.findViewById(R.id.title_listview);
        List<HashMap<String, String>> list = new ArrayList<HashMap<String, String>>();
        
        for (int i = 0; i < MyData.titleArray.length; i++) {
            HashMap<String, String> temp = new HashMap<String, String>();
            temp.put("title", MyData.titleArray[i]);
            list.add(temp);
        }

        SimpleAdapter sa = new SimpleAdapter(this.context, list, R.layout.item, new String[]{"title"}, new int[]{R.id.title_textview});
        listView.setAdapter(sa);
        return v;
    }

    @Override
    public void onAttach(Activity activity) {
        super.onAttach(activity);
        this.context = (MainActivity)activity;
    }
}

OK,这样TitleFragment能正确的返回一个带有listView的视图了,我们接着回到MainActivity中去操作。

 

操作Fragment必须要有FragmentManager这个对象的,这里有一个坑爹之处。

官方推荐我们使用的是android.support.v4.app这个包下的Fragment,而不是android.app这个包下的Fragment,因此我们需要用getSupportFragmentManager()去获取android.support.v4.app.FragmentManager

因此MainActivity需要继承的是FragmentActivity

接下来的操作就比较简单了,获取FragmentManager,开启事务,替换,提交即可,代码如下:

public class MainActivity extends FragmentActivity {
    
    private FragmentManager fragmentManager;
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        this.fragmentManager = getSupportFragmentManager();
        
        FragmentTransaction ft = this.fragmentManager.beginTransaction();
        TitleFragment titleFragment = new TitleFragment();
        ft.replace(R.id.pager, titleFragment);
        ft.commit();
    }
}

OKOK,到目前为止,该程序启动后,会显示出一个列表,木有任何问题,接下来我们要做的,就是点击列表中的一项,可以将整个FrameLayout给换掉,换成详细的页面。那么在ListView那里必须给设置一个监听器,代码如下:

public class TitleFragment extends Fragment {
    
    private Context context;
    
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
            Bundle savedInstanceState) { 
        View v = inflater.inflate(R.layout.title_fragment, container, false);
        ListView listView = (ListView)v.findViewById(R.id.title_listview);
        List<HashMap<String, String>> list = new ArrayList<HashMap<String, String>>();
        
        for (int i = 0; i < MyData.titleArray.length; i++) {
            HashMap<String, String> temp = new HashMap<String, String>();
            temp.put("title", MyData.titleArray[i]);
            list.add(temp);
        }
        
     //设置监听器!!!! listView.setOnItemClickListener(
new ItemClickListener()); SimpleAdapter sa = new SimpleAdapter(this.context, list, R.layout.item, new String[]{"title"}, new int[]{R.id.title_textview}); listView.setAdapter(sa); return v; } @Override public void onAttach(Activity activity) { super.onAttach(activity); this.context = (MainActivity)activity; }
  //监听器!!!
class ItemClickListener implements OnItemClickListener { @Override public void onItemClick(AdapterView<?> arg0, View arg1, int arg2, long arg3) {
        //这里调用的是Activity里面的方法!!! ((MainActivity)TitleFragment.
this.context).showDetail(arg2); } } }

因为使用FragmentManager的能力,只有Activity才具备,因此得把替换的方法写在MainActivity里面。MainActivity的代码变成如下的样子

public class MainActivity extends FragmentActivity {
    
    private FragmentManager fragmentManager;
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        this.fragmentManager = getSupportFragmentManager();
        
        FragmentTransaction ft = this.fragmentManager.beginTransaction();
        TitleFragment titleFragment = new TitleFragment();
        ft.replace(R.id.pager, titleFragment);
        ft.commit();
    }public void showDetail(int index) {
     //需要注意的是FragmentTransaction对象commit之后就不能继续使用了,需要重新new一个 FragmentTransaction ft
= this.fragmentManager.beginTransaction(); DetailFragment detailFragment = new DetailFragment(); Bundle b = new Bundle(); b.putInt("index", index);
     //给detailFragment设置一个参数,这样详细页才能知道自己显示哪一个文章,类似于get请求detail.php?id=112 detailFragment.setArguments(b); ft.replace(R.id.pager, detailFragment);
     //下面这句的作用很大,这句话将该事务加入了回退栈里面,也就是当你显示详细页后,你按后退的按钮,可以回到列表页,如果没有这样做,按后退直接退出了~ ft.addToBackStack(
"title"); ft.commit(); } }

注意的要点都在代码的注释,大家看看就懂了,接下来贴下DetailFragment的代码

public class DetailFragment extends Fragment {
    
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
            Bundle savedInstanceState) {
        View v = inflater.inflate(R.layout.detail, container, false);
        TextView textView = (TextView)v.findViewById(R.id.content);
     //这里获取到刚刚设置的参数~ Bundle b
= this.getArguments(); int index = b.getInt("index"); textView.setText(MyData.articleArray[index]); return v; } }

OKOK,代码基本上贴完了,以上就是在下这两天的学习成果,理解了不少东西,真是很开心,肯定也有些理解不到位的,希望有大神能给与一些指点。哈哈

 

原文地址:http://www.cnblogs.com/kross/p/3328389.html

新浪微博:http://weibo.com/u/1928100503

posted @ 2013-09-18 14:35  krosshuang  阅读(1627)  评论(2编辑  收藏  举报