对于Fragment,《Android编程权威指南》的作者极力推崇,坚持AUF(Always Use Fragment)原则,即总是使用Fragment。Fragment本身占用内存比Activity少很多,在流畅性,性能上具有很大的优势,尤其是在中低端手机上。此外,如果你的应用需要移植到平板上的话,那使用Fragment更是你的不二之选。
本文就是通过一个实战案例来解剖一下Fragment。
效果图:
主界面是一个空的FrameLayout,这里我们将添加一个HomeFragment来显示首页内容,此外还有一个抽屉菜单,这里我们用NavigationView来实现,既然官方提供了这个控件,感觉我们也就没必要来自己写一个侧滑栏了。
<?xml version="1.0" encoding="utf-8"?>
<android.support.v4.widget.DrawerLayout
android:id="@+id/drawer_layout"
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
tools:openDrawer="start">
<FrameLayout
android:id="@+id/fl_container"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
</FrameLayout>
<android.support.design.widget.NavigationView
android:id="@+id/nav_view"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="start"
android:fitsSystemWindows="true"
app:headerLayout="@layout/nav_header_main"
app:menu="@menu/activity_main_drawer"/>
</android.support.v4.widget.DrawerLayout>
其中属性app:headerLayout=”@layout/nav_header_main”中的nav_header_main就是布局左上角的图标以及一些用户名信息等,app:menu=”@menu/activity_main_drawer”中的activity_main_drawer就是菜单栏。
接下来就需要把我们的HomeFragment加载进来了
if (savedInstanceState == null) {
loadRootFragment(R.id.fl_container, HomeFragment.newInstance());
}
其中的loadRootFragment如果在Activity使用,则本质是FragmentActivity.getSupportFragmentManager().getTopFragment().start(f);
如果在Fragment中使用,则是Fragment.getFragmentManager().start(f);
然后是初始化抽屉菜单:
private void initView() {
mDrawer = (DrawerLayout) findViewById(R.id.drawer_layout);
ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(this, mDrawer, R.string.navigation_drawer_open, R.string.navigation_drawer_close);
// mDrawer.setDrawerListener(toggle);
toggle.syncState();
mNavigationView = (NavigationView) findViewById(R.id.nav_view);
mNavigationView.setNavigationItemSelectedListener(this);
mNavigationView.setCheckedItem(R.id.nav_home);//默认点击栏
LinearLayout llNavHeader = (LinearLayout) mNavigationView.getHeaderView(0);
mTvName = (TextView) llNavHeader.findViewById(R.id.tv_name);
mImgNav = (ImageView) llNavHeader.findViewById(R.id.img_nav);
llNavHeader.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mDrawer.closeDrawer(GravityCompat.START);
mDrawer.postDelayed(new Runnable() {
@Override
public void run() {
goLogin();
}
}, 250);
}
});
}
为了实现侧滑栏的点击事件,我们需要实现OnNavigationItemSelectedListener中的onNavigationItemSelected方法:
@Override
public boolean onNavigationItemSelected(final MenuItem item) {
mDrawer.closeDrawer(GravityCompat.START);
mDrawer.postDelayed(new Runnable() {
@Override
public void run() {
int id = item.getItemId();
final SupportFragment topFragment = getTopFragment();
if (id == R.id.nav_home) {
HomeFragment fragment = findFragment(HomeFragment.class);
Bundle newBundle = new Bundle();
newBundle.putString("from", "主页来自-->" + topFragment.getClass().getSimpleName());
fragment.putNewBundle(newBundle);
start(fragment, SupportFragment.SINGLETASK);
} else if (id == R.id.nav_discover) {
DiscoverFragment fragment = findFragment(DiscoverFragment.class);
if (fragment == null) {
popTo(HomeFragment.class, false, new Runnable() {
@Override
public void run() {
start(DiscoverFragment.newInstance());
}
});
} else {
// 如果已经在栈内,则以SingleTask模式start
start(fragment, SupportFragment.SINGLETASK);
}
} else if (id == R.id.nav_msg) {
ShopFragment fragment = findFragment(ShopFragment.class);
if (fragment == null) {
popTo(HomeFragment.class, false, new Runnable() {
@Override
public void run() {
start(ShopFragment.newInstance());
}
});
} else {
// 如果已经在栈内,则以SingleTask模式start,也可以用popTo
// start(fragment, SupportFragment.SINGLETASK);
popTo(ShopFragment.class, false);
}
} else if (id == R.id.nav_login) {
goLogin();
} else if (id == R.id.nav_swipe_back) {
startActivity(new Intent(MainActivity.this, SwipeBackSampleActivity.class));
} else if (id == R.id.nav_swipe_back_f) {
start(SwipeBackSampleFragment.newInstance());
}
}
}, 250);
return true;
}
接着就是根据各自的点击栏实现相应的Fragment,还有一些细节需要看相应的代码,文末提供源码。