Fragment详解,以开发"显示图书详情的Fragment"为例
2015-07-16 12:21
489 查看
Fragment是学习Android以来觉得最麻烦的一个知识点,涉及的内容比较多,在书本上不好记录,所以决定写一篇博文来梳理内容。
Fragment的难点重点是消息传递,本文中的图书详情案例中的消息顺序是:1、用户点击图书的标题(BookListFragment) 2、通知activity 3、activity通知显示图书详细信息(BookDetailFragment)
部分内容参考博文:http://www.cnblogs.com/mengdd/archive/2013/01/11/2856374.html
1、界面
创建Activity的界面。左边为一个fragment,id为book_list,对应的类为org.crazyit.app.BookListFragment。右边为FrameLayout,id为book_detail_container。
发现他们的layout_width都为0dp,Layout_weight分别为1和3,所以两者显示的界面区域大小为1:3,Layout_weight的理解可以参考博文中的Layout_weight详解。
activity_book_twopane.xml
2、创建ListFragment
在BookListFragment类中定义一个接口——Callbacks( 内有onItemSelected(Interger id方法) ),该Fragment所在Activity需要实现该接口,Fragment将通过该接口与它所在的Activity交互。
ListFragment显示的数据,使用ArrayAdapter适配器,数据类型为BookContent.Book,ITEMS为List<Book>!!!!。原因:ArrayAdapter为什么可以处理对象类型的数据呢?其实,ArrayAdapter是使用数组中对象的toString()方法来填充指定的TextView,所以我们可以通过重写对象的toString()方法来自定义ListView的显示。而Book的toString()方法显示的是第一个字符串,即书本的标题。
onAttach方法在该Fragment被添加、显示到Activity时回调该方法。
onDetach方法在该Fragment从它所属的Activity中被删除时回调该方法。
onLIstItemClick为用户单机某列表时激发该回调方法,传入选中页面的书本id。
为什么创建接口CalBacks?
一些情况下,可能需要fragment和activity共享事件,一个比较好的做法是在fragment里面定义一个回调接口,然后要求宿主activity实现它。当activity通过这个接口接收到一个回调,它可以同布局中的其他fragment分享这个信息。
例如,一个新闻显示应用在一个activity中有两个fragment,一个fragment A显示文章题目的列表,一个fragment B显示文章。所以当一个文章被选择的时候,fragment A必须通知activity,然后activity通知fragment B,让它显示这篇文章。这个情况下,在fragment A中声明一个这样的接口OnArticleSelectedListener:
之后包含这个fragment的activity实现这个OnArticleSelectedListener接口,用覆写的onArticleSelected()方法将fragment A中发生的事通知fragment B。
为了确保宿主activity实现这个接口,fragment A的onAttach() 方法(这个方法在fragment
被加入到activity中时由系统调用)中通过将传入的activity强制类型转换,实例化一个OnArticleSelectedListener对象:
如果activity没有实现这个接口,fragment将会抛出ClassCastException异常,如果成功了,mListener将会是activity实现OnArticleSelectedListener接口的一个引用,所以通过调用OnArticleSelectedListener接口的方法,fragment
A可以和activity共享事件。
比如,如果fragment A是ListFragment的子类,每一次用户点击一个列表项目,系统调用fragment中的onListItemClick() 方法,在这个方法中可以调用onArticleSelected()方法与activity共享事件。
BookListFragment.java
3、图书详细信息显示的Fragment
每次BookDetailFragment切换时系统会调用onCreate方法,根据activity中传入的参数获取book信息。
Fragment每次切换时显示的界面也会发生变化,onCreateView方法返回显示的View,使用的布局文件为R.layout.fragment_book_detail,显示标题和描述内容。
获取activity传入的参数,通过getArguments方法
BookDetailFragment.java
4、编写activity
设置activity_book_twopane为布局文件,即左边是Fragment,右边是FrameLayout。
实现Callbacks接口的onItemSelected方法,用户点击Fragment时激发mCallbacks的onItemSelected方法,通知BookDetailFragment这个描述书本详细信息的Fragment类,更新内容。
Activity的getFragmentManager()方法可以返回FragmentManager,FragmentManager对象的beginTransaction()方法即可开启并返回FragmentTransaction对象,使用Fragment替换book_detail_container容器当前显示的Fragment。
通过setArguments方法传入参数。
SelectBookActivity.java
Fragment的难点重点是消息传递,本文中的图书详情案例中的消息顺序是:1、用户点击图书的标题(BookListFragment) 2、通知activity 3、activity通知显示图书详细信息(BookDetailFragment)
部分内容参考博文:http://www.cnblogs.com/mengdd/archive/2013/01/11/2856374.html
1、界面
创建Activity的界面。左边为一个fragment,id为book_list,对应的类为org.crazyit.app.BookListFragment。右边为FrameLayout,id为book_detail_container。
发现他们的layout_width都为0dp,Layout_weight分别为1和3,所以两者显示的界面区域大小为1:3,Layout_weight的理解可以参考博文中的Layout_weight详解。
activity_book_twopane.xml
<?xml version="1.0" encoding="utf-8"?> <!-- 定义一个水平排列的LinearLayout,并指定使用中等分隔条 --> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="horizontal" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_marginLeft="16dp" android:layout_marginRight="16dp" android:divider="?android:attr/dividerHorizontal" android:showDividers="middle"> <!-- 添加一个Fragment --> <fragment android:name="org.crazyit.app.BookListFragment" android:id="@+id/book_list" android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="1" /> <!-- 添加一个FrameLayout容器 --> <FrameLayout android:id="@+id/book_detail_container" android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="3" /> </LinearLayout>
2、创建ListFragment
在BookListFragment类中定义一个接口——Callbacks( 内有onItemSelected(Interger id方法) ),该Fragment所在Activity需要实现该接口,Fragment将通过该接口与它所在的Activity交互。
ListFragment显示的数据,使用ArrayAdapter适配器,数据类型为BookContent.Book,ITEMS为List<Book>!!!!。原因:ArrayAdapter为什么可以处理对象类型的数据呢?其实,ArrayAdapter是使用数组中对象的toString()方法来填充指定的TextView,所以我们可以通过重写对象的toString()方法来自定义ListView的显示。而Book的toString()方法显示的是第一个字符串,即书本的标题。
onAttach方法在该Fragment被添加、显示到Activity时回调该方法。
onDetach方法在该Fragment从它所属的Activity中被删除时回调该方法。
onLIstItemClick为用户单机某列表时激发该回调方法,传入选中页面的书本id。
为什么创建接口CalBacks?
一些情况下,可能需要fragment和activity共享事件,一个比较好的做法是在fragment里面定义一个回调接口,然后要求宿主activity实现它。当activity通过这个接口接收到一个回调,它可以同布局中的其他fragment分享这个信息。
例如,一个新闻显示应用在一个activity中有两个fragment,一个fragment A显示文章题目的列表,一个fragment B显示文章。所以当一个文章被选择的时候,fragment A必须通知activity,然后activity通知fragment B,让它显示这篇文章。这个情况下,在fragment A中声明一个这样的接口OnArticleSelectedListener:
public static class FragmentA extends ListFragment { ... // Container Activity must implement this interface public interface OnArticleSelectedListener { public void onArticleSelected(Uri articleUri); } ... }
之后包含这个fragment的activity实现这个OnArticleSelectedListener接口,用覆写的onArticleSelected()方法将fragment A中发生的事通知fragment B。
为了确保宿主activity实现这个接口,fragment A的onAttach() 方法(这个方法在fragment
被加入到activity中时由系统调用)中通过将传入的activity强制类型转换,实例化一个OnArticleSelectedListener对象:
public static class FragmentA extends ListFragment { OnArticleSelectedListener mListener; ... @Override public void onAttach(Activity activity) { super.onAttach(activity); try { mListener = (OnArticleSelectedListener) activity; } catch (ClassCastException e) { throw new ClassCastException(activity.toString() + " must implement OnArticleSelectedListener"); } } ... }
如果activity没有实现这个接口,fragment将会抛出ClassCastException异常,如果成功了,mListener将会是activity实现OnArticleSelectedListener接口的一个引用,所以通过调用OnArticleSelectedListener接口的方法,fragment
A可以和activity共享事件。
比如,如果fragment A是ListFragment的子类,每一次用户点击一个列表项目,系统调用fragment中的onListItemClick() 方法,在这个方法中可以调用onArticleSelected()方法与activity共享事件。
public static class FragmentA extends ListFragment { OnArticleSelectedListener mListener; ... @Override public void onListItemClick(ListView l, View v, int position, long id) { // Append the clicked item's row ID with the content provider Uri Uri noteUri = ContentUris.withAppendedId(ArticleColumns.CONTENT_URI, id); // Send the event and Uri to the host activity mListener.onArticleSelected(noteUri); } ... }
BookListFragment.java
public class BookListFragment extends ListFragment { private Callbacks mCallbacks; // 定义一个回调接口,该Fragment所在Activity需要实现该接口 // 该Fragment将通过该接口与它所在的Activity交互 public interface Callbacks { public void onItemSelected(Integer id); } @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // 为该ListFragment设置Adapter setListAdapter(new ArrayAdapter<BookContent.Book>(getActivity(), android.R.layout.simple_list_item_activated_1, android.R.id.text1, BookContent.ITEMS)); } // 当该Fragment被添加、显示到Activity时,回调该方法 @Override public void onAttach(Activity activity) { super.onAttach(activity); // 如果Activity没有实现Callbacks接口,抛出异常 if (!(activity instanceof Callbacks)) { throw new IllegalStateException( "BookListFragment所在的Activity必须实现Callbacks接口!"); } // 把该Activity当成Callbacks对象 mCallbacks = (Callbacks)activity; } // 当该Fragment从它所属的Activity中被删除时回调该方法 @Override public void onDetach() { super.onDetach(); // 将mCallbacks赋为null。 mCallbacks = null; } // 当用户点击某列表项时激发该回调方法 @Override public void onListItemClick(ListView listView , View view, int position, long id) { super.onListItemClick(listView, view, position, id); // 激发mCallbacks的onItemSelected方法 mCallbacks.onItemSelected(BookContent .ITEMS.get(position).id); } public void setActivateOnItemClick(boolean activateOnItemClick) { getListView().setChoiceMode( activateOnItemClick ? ListView.CHOICE_MODE_SINGLE : ListView.CHOICE_MODE_NONE); } }
3、图书详细信息显示的Fragment
每次BookDetailFragment切换时系统会调用onCreate方法,根据activity中传入的参数获取book信息。
Fragment每次切换时显示的界面也会发生变化,onCreateView方法返回显示的View,使用的布局文件为R.layout.fragment_book_detail,显示标题和描述内容。
获取activity传入的参数,通过getArguments方法
BookDetailFragment.java
public class BookDetailFragment extends Fragment { public static final String ITEM_ID = "item_id"; // 保存该Fragment显示的Book对象 BookContent.Book book; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // 如果启动该Fragment时包含了ITEM_ID参数 if (getArguments().containsKey(ITEM_ID)) { book = BookContent.ITEM_MAP.get(getArguments() .getInt(ITEM_ID)); //① } } // 重写该方法,该方法返回的View将作为Fragment显示的组件 @Override public View onCreateView(LayoutInflater inflater , ViewGroup container, Bundle savedInstanceState) { // 加载/res/layout/目录下的fragment_book_detail.xml布局文件 View rootView = inflater.inflate(R.layout.fragment_book_detail, container, false); if (book != null) { // 让book_title文本框显示book对象的title属性 ((TextView) rootView.findViewById(R.id.book_title)) .setText(book.title); // 让book_desc文本框显示book对象的desc属性 ((TextView) rootView.findViewById(R.id.book_desc)) .setText(book.desc); } return rootView; } }
4、编写activity
设置activity_book_twopane为布局文件,即左边是Fragment,右边是FrameLayout。
实现Callbacks接口的onItemSelected方法,用户点击Fragment时激发mCallbacks的onItemSelected方法,通知BookDetailFragment这个描述书本详细信息的Fragment类,更新内容。
Activity的getFragmentManager()方法可以返回FragmentManager,FragmentManager对象的beginTransaction()方法即可开启并返回FragmentTransaction对象,使用Fragment替换book_detail_container容器当前显示的Fragment。
通过setArguments方法传入参数。
SelectBookActivity.java
public class SelectBookActivity extends Activity implements BookListFragment.Callbacks { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // 加载/res/layout目录下的activity_book_twopane.xml布局文件 setContentView(R.layout.activity_book_twopane); } // 实现Callbacks接口必须实现的方法 @Override public void onItemSelected(Integer id) { // 创建Bundle,准备向Fragment传入参数 Bundle arguments = new Bundle(); arguments.putInt(BookDetailFragment.ITEM_ID, id); // 创建BookDetailFragment对象 BookDetailFragment fragment = new BookDetailFragment(); // 向Fragment传入参数 fragment.setArguments(arguments); // 使用fragment替换book_detail_container容器当前显示的Fragment getFragmentManager().beginTransaction() .replace(R.id.book_detail_container, fragment) .commit(); //① } }
相关文章推荐
- Laravel数据模型层M错误MassAssignmentException in Model.php line 407: username
- Afianl框架里面的FinalBitmap加载网络图片
- 调用有道词典查询
- 中文分词技术(中文分词原理)
- LeetCode#226 Invert Binary Tree
- python中的map()函数
- com.mchange.v2.async.ThreadPoolAsynchronousRunner$DeadlockDetector@d3ade7 ,项目启动错误
- Activity Intent相关FLAG介绍
- linux 下解压rar文件
- 日期
- hive支持sql大全
- spring 基于XML配置的Cache支持
- 对按时间先后顺序的列表按同一天进行分组
- java简单实现链表
- 解决SQL Server管理器无法连接远程数据库Error: 1326错误
- 【BLE】CC2541之参数更新
- python中的map、filter、reduce函数
- 仿新浪微博
- PHP计算加权平均数的方法
- svn自助修改密码(PHP脚本实现)