- 1月23日更新:将fragmentnew的实现改为viewpager+viewpagerindicater+fragment实现,可以在资讯详情页内滑动切换页面。
博主最近在做一个资讯类app,要求实现类似头条那种的界面,即底部导航栏切换改变fragment,在某一个界面后,点击上部导航栏也改变fragment,这里就用到了fragment嵌套fragment。
其中需要注意的地方就是在使用时, 主要要依靠宿主Fragment的 getChildFragmentManager() 来获取FragmentManger.
博主的思路是:主activity的导航栏使用radiogroup+radiobutton实现,通过点击radiobutton,来切换页面。资讯页面是一个fragmentnews嵌套viewpager+fragment实现页面滑动切换。其他页面都分别为一个fragment,内容可以自定义;其中我的界面是一个新的activity。
这里给出主界面代码,MainActivity.java
initView()函数来监听RadioGroup状态变化,在状态改变时,调用setIndexSelected()隐藏当前fragment,显示被选中RadioButton对应的fragment。
initFragment函数初始化fragment并将fragment加入到fragmentManager中,初始设置为默认隐藏。
setIndexSelected函数用来实现fragmen的显示和隐藏
package com.example.zyk97.infotest.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentTransaction;
import android.view.View;
import android.widget.Button;
import android.widget.RadioButton;
import android.widget.RadioGroup;
import android.widget.TextView;
import com.example.zyk97.infotest.Fragment.FragmentAnalysis;
import com.example.zyk97.infotest.Fragment.FragmentData;
import com.example.zyk97.infotest.Fragment.FragmentHome;
import com.example.zyk97.infotest.Fragment.FragmentNews;
import com.example.zyk97.infotest.R;
/**
* 应用主界面,主activity
* 用户打开显示首页
*/
public class Mainactivity extends FragmentActivity {
private Fragment[] mfragments;
private FragmentHome fh;
private FragmentNews fn;
private FragmentData fd;
private FragmentAnalysis fa;
private int mindex = 0;
private RadioGroup rg;
private Button searchimage;
private TextView searchtext;
private int last = 0;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.mainactivity);
initFragment();
initView();
search();
}
private void initView() {
rg = findViewById(R.id.rgbtm);
searchimage = findViewById(R.id.search_image_main);
searchtext = findViewById(R.id.search_text_main);
rg.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(RadioGroup group, int checkedId) {
//遍历RagioGroup中的所有子控件
for (int index = 0; index < 4; index++) {
//获取到指定位置的RadioButton
RadioButton rb = (RadioButton) group.getChildAt(index);
//如果被选中,显示对应fragment
if (rb.isChecked()) {
setIndexSelected(index);
last = index;
break;
}
}
RadioButton me = (RadioButton) group.getChildAt(4);
if (me.isChecked()) {
Intent intent = new Intent(Mainactivity.this, FirstIn.class);
RadioButton radioButton = (RadioButton) rg.getChildAt(last);
radioButton.setChecked(true);
startActivity(intent);
}
}
});
}
private void initFragment() {
fh = FragmentHome.newInstance();
fn = FragmentNews.newInstance();
fd = FragmentData.newInstance();
fa = FragmentAnalysis.newInstance();
mfragments = new Fragment[]{fh, fn, fd, fa};
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction ft = fragmentManager.beginTransaction();
//初始化直接全部加载所有fragment
for (int i = 0; i < 4; i++) {
ft.add(R.id.content_main, mfragments[i]).hide(mfragments[i]);
}
ft.show(fh).commit();
setIndexSelected(0);
}
//选中显示和隐藏
private void setIndexSelected(int index) {
if (mindex == index) {
return;
}
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction ft = fragmentManager.beginTransaction();
//隐藏
ft.hide(mfragments[mindex]);
//判断是否显示
if (!mfragments[index].isAdded()) {
if (index == 1) {
ft.add(R.id.content_main, mfragments[index]).show(mfragments[index]);
} else {
ft.add(R.id.content_main, mfragments[index]).show(mfragments[index]);
}
} else {
ft.show(mfragments[index]);
}
ft.commit();
//再次赋值
mindex = index;
}
private void search() {
searchimage.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent1 = new Intent(Mainactivity.this, SearchPage.class);
startActivity(intent1);
}
});
searchtext.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent2 = new Intent(Mainactivity.this, SearchPage.class);
startActivity(intent2);
}
});
}
}
资讯界面的fragment也类似主界面activity,要对他嵌套的几个fragment进行管理,其中需要注意的是,在获取FragmentManager时,需要用getChildFragmentManager(),在宿主fragment中调用这个函数,即可用它来向这个fragment内部添加fragments.
FragmentManager fragmentManager=getChildFragmentManager();
FragmentTransaction ft=fragmentManager.beginTransaction();
这里只给出资讯界面的fragmentNews.java,其他几个界面类似。
博主使用了viewpagerindicator,具体添加依赖和注意事项参考引入第三方包V4冲突解决方法
package com.example.zyk97.infotest.Fragment;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentPagerAdapter;
import android.support.v4.view.ViewPager;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import com.example.zyk97.infotest.R;
import com.example.zyk97.infotest.Update.MessageEvent;
import com.viewpagerindicator.TabPageIndicator;
import org.greenrobot.eventbus.EventBus;
import org.greenrobot.eventbus.Subscribe;
import org.greenrobot.eventbus.ThreadMode;
public class FragmentNews extends Fragment {
private static FragmentNews fm;
public String titles[] = new String[]{"快讯", "同业", "推荐", "定制", "要闻"};
private ViewPager viewPager;
private TabPageIndicator indicator;
private TabPageIndicatorAdapter mAdapter;
//首页传递的数据,表示资讯页应显示msgIndex页
private int msgIndex=0;
public static FragmentNews newInstance() {
if (fm == null) {
fm = new FragmentNews();
}
return fm;
}
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragmentnews, container, false);
initView(view);
//注册eventbus
EventBus.getDefault().register(this);
return view;
}
//接受home界面传来的数据,切换界面
@Subscribe(threadMode = ThreadMode.MAIN)
public void onEvent(MessageEvent msg) {
msgIndex = msg.getIndex();
indicator.setCurrentItem(msgIndex);
}
private void initView(View view) {
mAdapter = new TabPageIndicatorAdapter(getChildFragmentManager());
//实例化ViewPager, 然后给ViewPager设置Adapter
viewPager = view.findViewById(R.id.viewpager_news);
viewPager.setAdapter(mAdapter);
//实例化TabPageIndicator,然后与ViewPager绑在一起(核心步骤)
indicator = view.findViewById(R.id.indicator_news);
indicator.setViewPager(viewPager);
indicator.setOnPageChangeListener(new ViewPager.OnPageChangeListener() {
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
}
@Override
public void onPageSelected(int position) {
}
@Override
public void onPageScrollStateChanged(int state) {
}
});
}
@Override
public void onDestroy() {
super.onDestroy();
if (EventBus.getDefault().isRegistered(this)) {
EventBus.getDefault().unregister(this);
}
}
/**
* viewpager的adapter
*/
class TabPageIndicatorAdapter extends FragmentPagerAdapter {
Bundle args = new Bundle();
Fragment f1=new Fragment1();
Fragment f2=new Fragment2();
Fragment f3=new Fragment3();
Fragment f4=new Fragment4();
Fragment f5=new Fragment5();
public TabPageIndicatorAdapter(FragmentManager fm) {
super(fm);
}
@Override
public Fragment getItem(int position) {
switch (position){
case 0:
args.putString("arg", titles[position]);
f1.setArguments(args);
return f1;
case 1:
args.putString("arg", titles[position]);
f1.setArguments(args);
return f2;
case 2:
args.putString("arg", titles[position]);
f1.setArguments(args);
return f3;
case 3:
args.putString("arg", titles[position]);
f1.setArguments(args);
return f4;
case 4:
args.putString("arg", titles[position]);
f1.setArguments(args);
return f5;
}
return f1;
}
@Override
public CharSequence getPageTitle(int position) {
return titles[position % titles.length];
}
@Override
public int getCount() {
return titles.length;
}
}
}
下面是主界面和资讯界面布局文件:
mainactivity.xml
<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.LinearLayoutCompat 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:background="@color/white"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="55dp"
android:background="@color/dark_blue"
android:orientation="horizontal">
<Button
android:id="@+id/search_image_main"
android:layout_width="30dp"
android:layout_height="30dp"
android:layout_marginLeft="15dp"
android:layout_marginRight="5dp"
android:layout_gravity="center"
android:background="@mipmap/search"
/>
<TextView
android:id="@+id/search_text_main"
android:layout_width="match_parent"
android:layout_height="30dp"
android:layout_marginRight="15dp"
android:layout_gravity="center"
android:background="@drawable/textview_round_border"
android:gravity="center"
android:text="输入关键字!" />
</LinearLayout>
<FrameLayout
android:id="@+id/content_main"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1">
</FrameLayout>
<RadioGroup
android:id="@+id/rgbtm"
android:layout_width="match_parent"
android:layout_height="50dp"
android:background="@drawable/border_bottom"
android:orientation="horizontal">
<RadioButton
android:id="@+id/home"
style="@style/button_bottom"
android:checked="true"
android:drawableTop="@drawable/home_image_selector"
android:text="首页" />
<RadioButton
android:id="@+id/news"
style="@style/button_bottom"
android:checked="false"
android:drawableTop="@drawable/news_image_selector"
android:text="资讯" />
<RadioButton
android:id="@+id/data"
style="@style/button_bottom"
android:checked="false"
android:drawableTop="@drawable/data_image_selector"
android:text="数据" />
<RadioButton
android:id="@+id/analysis"
style="@style/button_bottom"
android:checked="false"
android:drawableTop="@drawable/analysis_image_selector"
android:text="智能分析" />
<RadioButton
android:id="@+id/me"
style="@style/button_bottom"
android:checked="false"
android:drawableTop="@drawable/me_image_selector"
android:text="我的" />
</RadioGroup>
</android.support.v7.widget.LinearLayoutCompat>
fragmentnews.xml
<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.LinearLayoutCompat xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/white"
android:orientation="vertical">
<com.viewpagerindicator.TabPageIndicator
android:id="@+id/indicator_news"
android:layout_width="match_parent"
android:layout_height="50dp"
android:theme="@style/StyledIndicators"/>
<android.support.v4.view.ViewPager
android:id="@+id/viewpager_news"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1">
</android.support.v4.view.ViewPager>
</android.support.v7.widget.LinearLayoutCompat>
TabPageIndicator的style样式文件
//indicator的style
<style name="StyledIndicators" parent="@android:style/Theme.Light">
<item name="vpiTabPageIndicatorStyle">@style/CustomTabPageIndicator</item>
</style>
<style name="CustomTabPageIndicator" parent="Widget.TabPageIndicator">
<item name="android:background">@drawable/tab_indicator</item>
<item name="android:textAppearance">@style/CustomTabPageIndicator.Text</item>
<item name="android:textSize">14sp</item>
<item name="android:dividerPadding">8dp</item>
<item name="android:showDividers">middle</item>
<item name="android:paddingLeft">10dp</item>
<item name="android:paddingRight">10dp</item>
<item name="android:fadingEdge">horizontal</item>
<item name="android:fadingEdgeLength">8dp</item>
</style>
<style name="CustomTabPageIndicator.Text" parent="android:TextAppearance.Medium">
<item name="android:typeface">monospace</item>
<item name="android:textColor">@drawable/selector_tabtext</item>
</style>
两个drawable资源文件:
selector_tabtext.xml
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_selected="true" android:color="@color/dark_blue" />
<item android:state_pressed="true" android:color="@color/dark_blue" />
<item android:state_focused="true" android:color="@color/dark_blue" />
<item android:color="@color/gray2"/>
</selector>
tab_indicator.xml
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_selected="false" android:state_pressed="false" android:drawable="@android:color/transparent" />
<item android:state_selected="false" android:state_pressed="true" android:drawable="@android:color/transparent" />
</selector>
本文样例完整代码InfoTest
本文参考:
-《 Fragment里边嵌套Fragment》,Mr_Billzhang
-《开源控件ViewPagerIndicator的使用》,陈利健