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