为什么要用Fragment
想象一个APP场景,我们开发了一个图书阅读的APP,希望这个APP能够同时在手机和平板上使用。
众所周知,手机的屏幕小且为竖向,平板的屏幕大且为横向。如果我们开发的APP在界面方面完全一样,那么用户体验并非很好。另外,通过使用fragment能很好地提高组件复用性。
那么如何提高用户体验呢?
平板——左右布局
手机——单页布局
说得再多不如上图,请看图
主要知识点
- 自适应设计(屏幕兼容适配)
- Activity中如何“嵌入”Fragment
- Activity如何与Fragment进行通信
- 如何构造Fragment
实例讲解
模拟一个读书Activity,需要用到
- 2个Activity——列表、详情
- 2个Fragment——列表、详情
- 4个布局文件——列表页布局(手机)、详情页布局(手机)、列表页布局(平板)、列表详情布局(fragment)
- 1个资源文件——用于选择手机、平板时加载哪个布局文件
- 1个图书实体类
通过resource实现自适应加载布局文件(根据屏幕大小)
在res目录下新建values-large目录,在其中新建refs.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<item name="activity_book" type="layout">@layout/activity_book_twopane</item>
</resources>
主界面Activity
public class BookActivity extends Activity implements Callbacks {
private boolean mTwoPane;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// 加载时会判断屏幕大小,大屏的会调用
setContentView(R.layout.activity_book);
if (findViewById(R.id.list_fragment) != null) {
// 实际加载了R.layout.activity_book_twopane
mTwoPane = true;
BookListFragment booklistFragment = (BookListFragment) getFragmentManager()
.findFragmentById(R.id.list_fragment);
//设置List的选中状态
booklistFragment.setActivateOnItemClick(true);
}
}
@Override
public void onItemSelected(Integer id) {
if (mTwoPane) {
// 创建Bundle准备向Fragment传数据
Bundle arguments = new Bundle();
arguments.putInt(BookDetailFragment.ITEM_ID, id);
// 创建详情页Fragment
BookDetailFragment detailFragment = new BookDetailFragment();
detailFragment.setArguments(arguments);
FragmentTransaction ft = getFragmentManager().beginTransaction();
ft.replace(R.id.detail_fragment, detailFragment);
ft.commit();
} else {
//小屏幕直接跳转新的Activity
Intent intent = new Intent(this, BookDetailActivity.class);
intent.putExtra(BookDetailFragment.ITEM_ID, id);
startActivity(intent);
}
}
}
列表页Fragment
public class BookListFragment extends ListFragment {
private Callbacks mCallBack;
public static ArrayList<BookEntity> bookList;
// 定义一个接口,该Fragment所在的Activity需要实现该接口
// 该Fragment将通过该接口与所在的Activity交互
public interface Callbacks {
public void onItemSelected(Integer id);
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setValueForBooklist();
List<String> bookNames = new ArrayList<>();
for (int i = 0;i<bookList.size();i++) {
bookNames.add(bookList.get(i).getTitle());
}
ArrayAdapter<String> adapter = new ArrayAdapter<String>(getActivity(), android.R.layout.simple_list_item_1,
android.R.id.text1, bookNames);
setListAdapter(adapter);
}
@Override
public void onAttach(Activity activity) {
super.onAttach(activity);
// 如果Activity没有实现Callbacks接口,抛出异常
if (!(activity instanceof Callbacks)) {
throw new IllegalStateException("BookListFragment所在的Activity必须实现Callbacks接口");
}
mCallBack = (Callbacks) activity;
}
// 当该Fragment从它所属的Activity中被删除时执行此方法
@Override
public void onDetach() {
super.onDetach();
mCallBack = null;
}
@Override
public void onListItemClick(ListView l, View v, int position, long id) {
super.onListItemClick(l, v, position, id);
mCallBack.onItemSelected(bookList.get(position).getId());
}
/**
* 设置ListView的选中状态
* @param itemClick
*/
public void setActivateOnItemClick(boolean itemClick) {
getListView().setChoiceMode(itemClick ? ListView.CHOICE_MODE_SINGLE : ListView.CHOICE_MODE_NONE);
}
private void setValueForBooklist() {
bookList = new ArrayList<>();
bookList.add(new BookEntity(1, "平凡的世界", "这是一个平凡的人改变命运的故事"));
bookList.add(new BookEntity(2, "三体", "一本让你重新认识宇宙、人生的书"));
bookList.add(new BookEntity(3, "遥远的救世主", "亲情、友情、爱情、创业、因缘、因果在此体现的淋漓尽致"));
}
}
详情页Activity
public class BookDetailActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_book_detail);
if (savedInstanceState == null) {
//为Fragment准备数据
Bundle args = new Bundle();
args.putInt(BookDetailFragment.ITEM_ID, getIntent().getIntExtra(BookDetailFragment.ITEM_ID, 0));
BookDetailFragment fragment = new BookDetailFragment();
//向Fragment传递数据
fragment.setArguments(args);
getFragmentManager().beginTransaction().add(R.id.detail_container, fragment).commit();
}
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
if(item.getItemId()==android.R.id.home){
Intent intent = new Intent(this,BookActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(intent);
return true;
}
return super.onOptionsItemSelected(item);
}
}
详情页Fragment
public class BookDetailFragment extends Fragment{
public static final String ITEM_ID="item_id";
private BookEntity book;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if(getArguments().containsKey(ITEM_ID)){
book = BookListFragment.bookList.get(getArguments().getInt(ITEM_ID)-1);
}
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_book_detail, container,false);
if(book!=null){
TextView titleView = (TextView) rootView.findViewById(R.id.book_title_text);
titleView.setText(book.getTitle());
TextView descView = (TextView) rootView.findViewById(R.id.book_desc_text);
descView.setText(book.getDesc());
}
return rootView;
}
}
主界面布局文件activity_book.xml
<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/book_list_fragment"
android:name="com.yeapin.demo.fragment.BookListFragment"
tools:context="${relativePackage}.${activityClass}" >
</fragment>
平板模式主界面布局文件activity_book_twopane.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="horizontal"
tools:context="${relativePackage}.${activityClass}" >
<fragment
android:id="@+id/list_fragment"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1" />
<fragment
android:id="@+id/detail_fragment"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="3"
/>
</LinearLayout>
详情页布局文件activity_book_detail.xml
<FrameLayout 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/detail_container"
tools:context="${relativePackage}.${activityClass}" >
</FrameLayout>
详情页fragment布局文件 fragment_book_detail.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="${relativePackage}.${activityClass}" >
<TextView
android:id="@+id/book_title_text"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<TextView
android:id="@+id/book_desc_text"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>
总结
- 自适应设计是通过resource文件来实现
- Activity中通过FragmentTrasaction实现对Fragment的管理,并由此创建Fragment,通过replace()和commit()方法实现加载
- Activity通过Bundle与Fragment进行通信、数据传递