I would like to make it possible to swipe between the tabs in my app.
I have already found plenty tutorials to do this, but I can't get it to work with my code, because I use different code.
MyActivity.class:
public class MyActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
final ActionBar actionBar = getActionBar();
actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
ActionBar.Tab tabA = actionBar.newTab();
tabA.setIcon(R.drawable.icon_settings);
actionBar.setDisplayShowHomeEnabled(false);
actionBar.setDisplayShowTitleEnabled(false);
tabA.setText("");
tabA.setTabListener(new com.example.MainActivity.TabListener<Tab1>(this, "Tab1", Tab1.class));
actionBar.addTab(tabA);
Tab tabB = actionBar.newTab();
tabB.setText("Tab2");
tabB.setTabListener(new com.example.MainActivity.TabListener<Tab2>(this, "Tab2", Tab2.class));
actionBar.addTab(tabB);
Tab tabC = actionBar.newTab();
tabC.setText("Tab3");
tabC.setTabListener(new com.example.MainActivity.TabListener<Tab3>(this, "Tab3", Tab3.class));
actionBar.addTab(tabC);
if (savedInstanceState != null) {
int savedIndex = savedInstanceState.getInt("SAVED_INDEX");
getActionBar().setSelectedNavigationItem(savedIndex);
}
}
Main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
<TabHost
android:id="#+id/tabHost"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical"
android:paddingTop="5dip">
<TabWidget
android:id="#android:id/tabs"
android:layout_width="fill_parent"
android:layout_height="wrap_content">
</TabWidget>
<FrameLayout
android:id="#android:id/tabcontent"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<LinearLayout
android:id="#+id/einstellungen"
android:layout_width="fill_parent"
android:layout_height="wrap_content" android:orientation="vertical" android:background="#ffffff">
</LinearLayout>
<LinearLayout
android:id="#+id/tab1"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
</LinearLayout>
<LinearLayout
android:id="#+id/tab2"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
</LinearLayout>
<LinearLayout
android:id="#+id/tab3"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
</LinearLayout>
</FrameLayout>
</LinearLayout>
</TabHost>
Tab1.class
public class Tab1 extends Fragment {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View myFragmentView = inflater.inflate(R.layout.fragment_a, container, false);
return myFragmentView;
}
}
TabListener.class
public class TabListener <T extends Fragment> implements ActionBar.TabListener{
private final Activity myActivity;
private final String myTag;
private final Class myClass;
public TabListener(Activity activity, String tag, Class<T> cls) {
myActivity = activity;
myTag = tag;
myClass = cls;
}
#Override
public void onTabSelected(ActionBar.Tab tab, FragmentTransaction ft) {
Fragment myFragment = myActivity.getFragmentManager().findFragmentByTag(myTag);
if (myFragment == null) {
myFragment = Fragment.instantiate(myActivity, myClass.getName());
ft.add(android.R.id.content, myFragment, myTag);
} else {
ft.attach(myFragment);
}
}
#Override
public void onTabUnselected(ActionBar.Tab tab, FragmentTransaction ft) {
Fragment myFragment = myActivity.getFragmentManager().findFragmentByTag(myTag);
if (myFragment != null) {
ft.detach(myFragment);
}
}
#Override
public void onTabReselected(ActionBar.Tab tab, FragmentTransaction ft) {
// TODO Auto-generated method stub
}
}
You can do it easier using the default ActionBar Tabs + Swipe Views of your Eclipse, Android Sudio or IntelliJ IDEA. Anyway you can take a look at my answer here Android ActionBar Tabs - Swipe or here Creating Swipe Views with Tabs you can find a very nice tutorial by Android Developers.
Hope I helped you
Related
There are some questions related to this same issue. For example, this one. But it doesn't work.
Let me show what I did in my code.
activity_main.xml
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools" android:id="#+id/container"
android:layout_width="match_parent" android:layout_height="match_parent"
tools:context=".MainActivity" tools:ignore="MergeRootFrame" >
<fragment
android:id="#+id/my_fragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:name="com.example.zhouhao.test.MyFragment"
tools:layout="#layout/fragment_my" />
</FrameLayout>
fragment_my.xml (my main fragment which include a FragmentTabHost)
<?xml version="1.0" encoding="utf-8"?>
<android.support.v4.app.FragmentTabHost xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#android:id/tabhost"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:weightSum="100"
android:orientation="horizontal">
<FrameLayout
android:id="#android:id/tabcontent"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_weight="0" />
<LinearLayout
android:layout_width="0dp"
android:layout_weight="95"
android:layout_height="match_parent"
android:orientation="vertical">
<FrameLayout
android:id="#+id/panel_content"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1" />
</LinearLayout>
</LinearLayout>
</android.support.v4.app.FragmentTabHost>
fragment_tab1.xml (for the fragment corresponding to different tab, they are similar so that I only show you one code)
<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" tools:context="com.example.zhouhao.test.TabFragment">
<!-- TODO: Update blank fragment layout -->
<TextView android:layout_width="match_parent" android:layout_height="match_parent"
android:text="#string/fragment_tab1" />
</FrameLayout>
MainActivity.java
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if (savedInstanceState == null) {
FragmentManager fm = getSupportFragmentManager();
mMyFragment = (MyFragment) fm.findFragmentById(R.id.my_fragment);
}
}
public class MyFragment extends Fragment implements TabHost.OnTabChangeListener {
FragmentTabHost mFragmentTabHost;
public MyFragment() {
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_my, container, false);
if (rootView != null) {
mFragmentTabHost = (FragmentTabHost) rootView.findViewById(android.R.id.tabhost);
mFragmentTabHost.setup(getActivity(), getActivity().getSupportFragmentManager(), R.id.panel_content);
TabFragment1 tab1Fragment = new TabFragment1();
TabFragment2 tab2Fragment = new TabFragment2();
TabFragment3 tab3Fragment = new TabFragment3();
TabHost.TabSpec spec1 = mFragmentTabHost.newTabSpec("1").setIndicator("");
TabHost.TabSpec spec2 = mFragmentTabHost.newTabSpec("2").setIndicator("");
TabHost.TabSpec spec3 = mFragmentTabHost.newTabSpec("3").setIndicator("");
mFragmentTabHost.addTab(spec1,tab1Fragment.getClass(), null);
mFragmentTabHost.addTab(spec2,tab2Fragment.getClass(), null);
mFragmentTabHost.addTab(spec3,tab3Fragment.getClass(), null);
mFragmentTabHost.setOnTabChangedListener(this);
return rootView;
} else {
return super.onCreateView(inflater, container, savedInstanceState);
}
}
#Override
public void onTabChanged(String tabId) {
BaseFragment f = (BaseFragment)getActivity().getSupportFragmentManager().findFragmentByTag(tabId);
Log.d("Log",tabId);
}
}
My problem is the BaseFragment is always null in my onTabChanged. Can anybody help? Thanks.
You cannot get the selected fragment immediately if the fragment has never been instantiated.
#Override
public void onTabChanged(final String tabId) {
Fragment fg = getSupportFragmentManager().findFragmentByTag(tabId);
Log.d(TAG, "onTabChanged(): " + tabId + ", fragment " + fg);
if (fg == null) {
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
Fragment fg = getSupportFragmentManager().findFragmentByTag(tabId);
Log.d(TAG, "onTabChanged() delay 50ms: " + tabId + ", fragment " + fg);
}
}, 50);
}
}
the output:
// cannot get the selected fragment immediately if the fragment has never been instantiated.
onTabChanged(): 1, fragment null
onTabChanged() delay 50ms: 1, fragment HistoryFragment{6f7a9d5 #2 id=0x7f09006e 1}
onTabChanged(): 2, fragment null
onTabChanged() delay 50ms: 2, fragment HistoryFragment{10c59e72 #3 id=0x7f09006e 2}
// can get the selected fragment immediately if the fragment already instantiated.
onTabChanged(): 1, fragment HistoryFragment{6f7a9d5 #2 id=0x7f09006e 1}
onTabChanged(): 2, fragment HistoryFragment{10c59e72 #3 id=0x7f09006e 2}
I think I get the right way to solve this problem, below is my answer.
Create a TabBean
private int imgId;
private int textId;
private Class fragment;
public MainTabBean(int textId, int imgId, Class fragment) {
this.textId = textId;
this.imgId = imgId;
this.fragment = fragment;
}
public int getTextId() {
return textId;
}
public void setTextId(int textId) {
this.textId = textId;
}
public int getImgId() {
return imgId;
}
public void setImgId(int imgId) {
this.imgId = imgId;
}
public Class getFragment() {
return fragment;
}
public void setFragment(Class fragment) {
this.fragment = fragment;
}
Then, get three TabBean instances with three fragments
List<MainTabBean> tabs = new ArrayList<>();
// three TabBean instances
TabBean homeTab = new MainTabBean(R.string.home, R.drawable.tab_home, HomepageFragment.class);
TabBean postcardTab = new MainTabBean(R.string.postcard, R.drawable.tab_postcard, PostcardFragment.class);
Bean notificationTab = new MainTabBean(R.string.notification, R.drawable.tab_notification, NotificationFragment.class);
// put tabs into a list
tabs.add(homeTab);
tabs.add(postcardTab);
tabs.add(notificationTab);
Third, just associate the TabBeans with FragmentTabHost as usual
// Obtain FragmentTabHost
tabHost = findViewById(android.R.id.tabhost);
// Associate fragmentManager with container
tabHost.setup(this, getSupportFragmentManager(), R.id.main_content);
// Create TabSpecs with TabBean and add it on TabHost
for(MainTabBean tab : tabs) {
TabHost.TabSpec spec = tabHost.newTabSpec(String.valueOf(tab.getTextId()))// set a tag
.setIndicator(getTabIndicator(tab));// set an indicator
tabHost.addTab(spec, tab.getFragment(), null);// add a tab
}
Forth, that's the most important step, I didn't get fragment instance with findFragmentByTag() like this
getSupportFragmentManager()
.findFragmentByTag(String.valueOf(tabs.get(1).getTextId()));
Instead, my answer is exactly like this:
tabs.get(0).getFragment().newInstance();
and cast it.
And I finally got the fragment.
How can I add a badge to tab ? I am using this code
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
viewPager = (ViewPager) findViewById(R.id.pager);
actionBar = getActionBar();
mAdapter = new TabsPagerAdapter(getSupportFragmentManager());
viewPager.setAdapter(mAdapter);
actionBar.setHomeButtonEnabled(false);
actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
// Adding Tabs
for (String tab_name : tabs) {
actionBar.addTab(actionBar.newTab().setText(tab_name)
.setTabListener(this));
}
/**
* on swiping the viewpager make respective tab selected
* */
viewPager.setOnPageChangeListener(new ViewPager.OnPageChangeListener() {
#Override
public void onPageSelected(int position) {
// on changing the page
// make respected tab selected
actionBar.setSelectedNavigationItem(position);
}
#Override
public void onPageScrolled(int arg0, float arg1, int arg2) {
}
#Override
public void onPageScrollStateChanged(int arg0) {
}
});
}
main activity.xml
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<FrameLayout
android:id="#+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<android.support.v4.view.ViewPager
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/pager"
android:layout_width="match_parent"
android:layout_height="match_parent" >
</android.support.v4.view.ViewPager>
</FrameLayout>
Tabs adapter java
public class TabsPagerAdapter extends FragmentPagerAdapter {
public TabsPagerAdapter(FragmentManager fm) {
super(fm);
}
#Override
public Fragment getItem(int index) {
switch (index) {
case 0:
return new RandomsFragment();
case 1:
return new ChatsFragment();
}
return null;
}
#Override
public int getCount() {
return 2;
}
}
I am following this tutorial for tabs:http://www.androidhive.info/2013/10/android-tab-layout-with-swipeable-views-1/
I didn't understand how can I add a badge to tabs.
first step is creating custom layout for each tabs so:
<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/text1"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceLarge"
android:gravity="center_vertical"
android:paddingLeft="6dip"
android:minHeight="?android:attr/listPreferredItemHeight"
/>
then when you want to add tabs to actionbar you must do :
private void addTabs(ActionBar actionBar)
{
ActionBar.Tab tab1=actionBar.newTab();
tab1.setTabListener(this);
tab1.setCustomView(R.layout.tab);
TextView txt1 = (TextView)tab1.getCustomView().findViewById(R.id.text1);
txt1.setText("Tab 1");
ActionBar.Tab tab2=actionBar.newTab();
tab2.setTabListener(this);
tab2.setCustomView(R.layout.tab);
TextView txt2 = (TextView)tab2.getCustomView().findViewById(R.id.text1);
txt2.setText("Tab 2");
ActionBar.Tab tab3=actionBar.newTab();
tab3.setCustomView(R.layout.tab);
tab3.setTabListener(this);
TextView txt3 = (TextView)tab3.getCustomView().findViewById(R.id.text1);
txt3.setText("Tab 3");
actionBar.addTab(tab1);
actionBar.addTab(tab2);
actionBar.addTab(tab3);
}
so in order to access them and add badgeView :
View v = getActionBar().getTabAt(0).getCustomView();
BadgeView badge = new BadgeView(getActivity(), v);
badge.setText("1");
badge.show();
the result will be:
After tweaking around with a few other solutions I came up with something simple and hope this would help someone.
create a custom tab layout tab_badge.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#android:color/transparent">
<TextView
android:id="#+id/tab_badge"
android:layout_width="30dp"
android:layout_height="30dp"
android:background="#drawable/badge_background"
android:gravity="center"
android:layout_centerVertical="true"
android:textColor="#color/colorWhite"
android:textSize="20sp"
android:textStyle="bold"/>
<TextView
android:id="#+id/tab_text"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:textSize="16sp"
android:textColor="#color/colorWhite"
android:text="test"
android:textStyle="bold"
android:gravity="center"
android:textAppearance="#style/Widget.AppCompat.Light.ActionBar.TabText"
android:layout_toRightOf="#+id/tab_badge"/>
</RelativeLayout>
badge_background.xml is an oval drawable filled with the color you want for the badge
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="oval" >
<solid android:color="#color/colormaterialred500" />
</shape>
Extend textview to get myBadgeView class:
public class myBadgeView extends TextView {
private View target;
public myBadgeView(Context context, View target) {
super(context);
init(context, target);
}
private void init(Context context, View target) {
this.target = target;
}
public void updateTabBadge(int badgeNumber) {
if (badgeNumber > 0) {
target.setVisibility(View.VISIBLE);
((TextView) target).setText(Integer.toString(badgeNumber));
}
else {
target.setVisibility(View.GONE);
}
}
}
In your activity declare the tablayout as follows:
tabLayout = (TabLayout) findViewById(R.id.tab_layout);
TabLayout.Tab tab1 = tabLayout.newTab();
tab1.setCustomView(R.layout.tab_badge);
TextView tab_text_1 = (TextView) tab1.getCustomView().findViewById(R.id.tab_text);
tab_text_1.setText("Tab1");
tabLayout.addTab(tab1);
badge1 = new myBadgeView(this, tab1.getCustomView().findViewById(R.id.tab_badge)); tab1.getCustomView().findViewById(R.id.tab_badge);
//set the badge for the tab
badge1.updateTabBadge(badge_value_1);
AFAIK, badge is not supported out of the box. You may find this library helpful: https://github.com/jgilfelt/android-viewbadger
I want to change the style of the tabhost tabbar ,same like actionbar tababar, I have tried to show in Figure.How can i do that ? PLease Help me thanks in advance.
I want to change the style from (1) to (2).
My code is below.
Class
package com.android.timeline;
#SuppressLint({ "SimpleDateFormat", "NewApi" })
public class MainActivity extends FragmentActivity implements ActionBar.TabListener
{
public int width;
private ActionBar actionBar;
private TextView actionBarTitle;
private TabPagerAdapter TabAdapter;
ArrayList<Fragment> fragmentlist = new ArrayList<Fragment>();
private ViewPager Tab;
private String[] tabs = { "About", "Watch Next", "Related" };
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
fragmentlist.add(new AboutDetail());
fragmentlist.add(new WatchNextDetail());
fragmentlist.add(new RelatedDetail());
currentAboutDetail = fragmentlist.get(0);
TabAdapter = new TabPagerAdapter(getSupportFragmentManager());
Tab = (ViewPager) findViewById(R.id.pager);
Tab.setOffscreenPageLimit(2);
pagerchangeListener();
}
private void pagerchangeListener() {
Tab.setOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener() {
#Override
public void onPageSelected(int position) {
actionBar.setSelectedNavigationItem(position);
}
});
Tab.setAdapter(TabAdapter);
}
#Override
public void onSaveInstanceState(Bundle savedInstanceState) {
super.onSaveInstanceState(savedInstanceState);
savedInstanceState.putInt("mMyCurrentPosition", Tab.getCurrentItem());
}
#Override
public void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
mMyCurrentPosition = savedInstanceState.getInt("mMyCurrentPosition");
// where mMyCurrentPosition should be a public value in your activity.
}
#Override
public void onCreateContextMenu(ContextMenu menu, View v,
ContextMenuInfo menuInfo) {
super.onCreateContextMenu(menu, v, menuInfo);
}
public class TabPagerAdapter extends FragmentStatePagerAdapter {
public TabPagerAdapter(FragmentManager fm) {
super(fm);
// TODO Auto-generated constructor stub
}
#Override
public Fragment getItem(int i) {
Log.e("LOG", "Position || " + i);
return fragmentlist.get(i);
}
#Override
public int getCount() {
return fragmentlist.size(); // No of Tabs
}
#Override
public void destroyItem(View container, int position, Object object) {
}
}
#Override
public void onTabSelected(android.app.ActionBar.Tab tab,
FragmentTransaction ft) {
// TODO Auto-generated method stub
Tab.setCurrentItem(tab.getPosition());
}
#Override
public void onTabUnselected(android.app.ActionBar.Tab tab,
FragmentTransaction ft) {
// TODO Auto-generated method stub
}
#Override
public void onTabReselected(android.app.ActionBar.Tab tab,
FragmentTransaction ft) {
// TODO Auto-generated method stub
}
}
xml
<RelativeLayout
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" >
<TabHost
android:id="#android:id/tabhost"
android:layout_width="fill_parent"
android:layout_height="fill_parent" >
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<TabWidget
android:id="#android:id/tabs"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_weight="0"
android:orientation="horizontal" />
<FrameLayout
android:id="#android:id/tabcontent"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_weight="0" />
<android.support.v4.view.ViewPager
android:id="#+id/pager"
android:layout_width="fill_parent"
android:layout_height="0dp"
android:layout_weight="1" />
</LinearLayout>
</TabHost>
</RelativeLayout>
Try like below. Please go through FragmentTabHost and ViewPager with FragmentPagerAdapter
main.xml
<android.support.v4.app.FragmentTabHost
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/tabhost"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<TabWidget
android:id="#+id/tabs"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="0"
android:orientation="horizontal" />
<FrameLayout
android:id="#+id/tabFrameLayout"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1" />
</LinearLayout>
</android.support.v4.app.FragmentTabHost>
MainActivity.java
public class MainActivity extends FragmentActivity {
private FragmentTabHost mTabHost;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
mTabHost = (FragmentTabHost) findViewById(R.id.tabhost);
mTabHost.setup(this, getSupportFragmentManager(), R.id.tabFrameLayout);
mTabHost.addTab(
mTabHost.newTabSpec("tab1").setIndicator("Tab 1",
getResources().getDrawable(android.R.drawable.star_on)),
FragmentTab1.class, null);
mTabHost.addTab(
mTabHost.newTabSpec("tab2").setIndicator("Tab 2",
getResources().getDrawable(android.R.drawable.star_on)),
FragmentTab2.class, null);
}
}
for this task refer this link http://wptrafficanalyzer.in/blog/implement-swiping-between-tabs-with-viewpager-in-action-bar-using-sherlock-library/
Good day to all. I can't figure out how to access parent Fragment layout from child Fragment. Let's say I have main activity with tabs defined in ActionBar. Each Tab is Fragment. Now in one of those tabs I want to use tabs again (sticked to bottom this time). I'm able to create needed layout using classic TabHost. Each of these sub-tabs will be operated by same Fragment class - literally it should be plain ListView with almost same data from database, it will differ by one field only (full list, "visited" items and "not visited").
So here's my parent PlanFragment, which is placed on of tabs of main Activity. It has TabHost and populates 3 Tabs using PlanListFragment:
public class PlanFragment extends Fragment implements OnTabChangeListener {
protected static final String TAG = "PlanFragment";
public static final String TAB_FULL = "full";
public static final String TAB_VISITED = "visited";
public static final String TAB_NOT_VISITED = "not_visited";
private View mRoot;
private TabHost mTabHost;
private int mCurrentTab;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
mRoot = inflater.inflate(R.layout.fragment_plan, container, false);
mTabHost = (TabHost) mRoot.findViewById(android.R.id.tabhost);
setupTabs();
return mRoot;
}
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
setRetainInstance(true);
mTabHost.setOnTabChangedListener(this);
mTabHost.setCurrentTab(mCurrentTab);
updateTab(TAB_FULL, R.id.tab_plan_full);
}
private void setupTabs() {
mTabHost.setup();
mTabHost.addTab(newTab(TAB_FULL, R.string.label_tab_plan_full,
R.id.tab_plan_full));
mTabHost.addTab(newTab(TAB_VISITED,
R.string.label_tab_plan_visited, R.id.tab_plan_visited));
mTabHost.addTab(newTab(TAB_NOT_VISITED,
R.string.label_tab_plan_unvisited, R.id.tab_plan_not_visited));
}
private TabSpec newTab(String tag, int labelId, int tabContentId) {
TabSpec tabSpec = mTabHost.newTabSpec(tag);
tabSpec.setIndicator(getActivity().getString(labelId));
tabSpec.setContent(tabContentId);
return tabSpec;
}
#Override
public void onTabChanged(String tabId) {
if(TAB_FULL.equals(tabId)) {
updateTab(tabId, R.id.tab_plan_full);
mCurrentTab = 0;
return;
}
if(TAB_VISITED.equals(tabId)) {
updateTab(tabId, R.id.tab_plan_visited);
mCurrentTab = 1;
return;
}
if(TAB_NOT_VISITED.equals(tabId)) {
updateTab(tabId, R.id.tab_plan_not_visited);
mCurrentTab = 2;
return;
}
}
private void updateTab(String tabId, int placeholder) {
FragmentManager fm = getFragmentManager();
if (fm.findFragmentByTag(tabId) == null) {
PlanListFragment plan = new PlanListFragment();
Bundle params = new Bundle();
params.putString(PlanListFragment.TAG, tabId);
plan.setArguments(params);
fm.beginTransaction()
.replace(placeholder, plan, tabId)
.commit();
}
}
}
Here's layout with TabHost:
<?xml version="1.0" encoding="utf-8"?>
<TabHost xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#android:id/tabhost"
android:layout_width="fill_parent"
android:layout_height="fill_parent" >
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical"
android:padding="5dp" >
<FrameLayout
android:id="#android:id/tabcontent"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:padding="5dp" >
<FrameLayout
android:id="#+id/tab_plan_full"
android:layout_width="fill_parent"
android:layout_height="fill_parent" >
<include layout="#layout/plan_list" />
</FrameLayout>
<FrameLayout
android:id="#+id/tab_plan_visited"
android:layout_width="fill_parent"
android:layout_height="fill_parent" >
<include layout="#layout/plan_list" />
</FrameLayout>
<FrameLayout
android:id="#+id/tab_plan_not_visited"
android:layout_width="fill_parent"
android:layout_height="fill_parent" >
<include layout="#layout/plan_list" />
</FrameLayout>
</FrameLayout>
<TabWidget
android:id="#android:id/tabs"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="-4dp"
android:layout_weight="0" />
</LinearLayout>
</TabHost>
plan_list.xml included on each tab:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/LinearLayout1"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<TextView
android:id="#+id/textView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Large Text"
android:textAppearance="?android:attr/textAppearanceLarge" />
<ListView
android:id="#+id/listView1"
android:layout_width="match_parent"
android:layout_height="wrap_content" >
</ListView>
</LinearLayout>
And finally PlanListFragment in which I plan to setup CursorAdapter for database based on parameter passed from parent Fragment. How do I access ListView here?
public class PlanListFragment extends ListFragment {
protected static final String TAG = "PlanListFragment";
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
Bundle params = getArguments();
Log.d(TAG, params.getString(TAG));
return null;
}
}
Now during my further investigations I found following scheme to work. Key parameter moved to "tag" attribute of call in layout. If there are any drawbacks please advice.
PlanFragment.java
public class PlanFragment extends Fragment implements OnTabChangeListener {
protected static final String TAG = "PlanFragment";
public static final String TAB_FULL = "full";
public static final String TAB_VISITED = "visited";
public static final String TAB_NOT_VISITED = "not_visited";
private View mRoot;
private TabHost mTabHost;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
mRoot = inflater.inflate(R.layout.fragment_plan, container, false);
mTabHost = (TabHost) mRoot.findViewById(android.R.id.tabhost);
setupTabs();
return mRoot;
}
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
setRetainInstance(true);
mTabHost.setOnTabChangedListener(this);
mTabHost.setCurrentTab(0);
}
private void setupTabs() {
mTabHost.setup();
mTabHost.addTab(newTab(TAB_FULL, R.string.label_tab_plan_full,
R.id.tab_plan_full));
mTabHost.addTab(newTab(TAB_VISITED,
R.string.label_tab_plan_visited, R.id.tab_plan_visited));
mTabHost.addTab(newTab(TAB_NOT_VISITED,
R.string.label_tab_plan_unvisited, R.id.tab_plan_not_visited));
}
private TabSpec newTab(String tag, int labelId, int tabContentId) {
TabSpec tabSpec = mTabHost.newTabSpec(tag);
tabSpec.setIndicator(getActivity().getString(labelId));
tabSpec.setContent(tabContentId);
return tabSpec;
}
#Override
public void onTabChanged(String tabId) {
}
}
fragment_plan.xml
<?xml version="1.0" encoding="utf-8"?>
<TabHost xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#android:id/tabhost"
android:layout_width="fill_parent"
android:layout_height="fill_parent" >
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical"
android:padding="5dp" >
<FrameLayout
android:id="#android:id/tabcontent"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:padding="5dp" >
<fragment
android:id="#+id/tab_plan_full"
android:tag="plan_full"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
class="com.example.collector.PlanListFragment" />
<fragment
android:id="#+id/tab_plan_visited"
android:tag="plan_visited"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
class="com.example.collector.PlanListFragment" />
<fragment
android:id="#+id/tab_plan_not_visited"
android:tag="plan_not_visited"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
class="com.example.collector.PlanListFragment" />
</FrameLayout>
<TabWidget
android:id="#android:id/tabs"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="-4dp"
android:layout_weight="0" />
</LinearLayout>
</TabHost>
plan_list.xml
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/FrameLayout1"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<TextView
android:id="#+id/textView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Large Text"
android:textAppearance="?android:attr/textAppearanceLarge" />
<ListView
android:id="#android:id/list"
android:layout_width="match_parent"
android:layout_height="wrap_content" >
</ListView>
</FrameLayout>
PlanListFragment.java
public class PlanListFragment extends ListFragment {
protected static final String TAG = "PlanListFragment";
public PlanListFragment() {}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.plan_list, container, false);
Log.d(TAG,getTag());
return view;
}
}
In child fragment try to access the parent fragment like this:
ParentFragment frag = ((ParentFragment)this.getParentFragment());
frag.sendbutton.setVisibility(View.Visible).invalidate();
Here "sendbutton" is the Button in parent fragment. You should use invalidate() in child fragment to refresh the view if required.
I searched a lot in the web about the possibility to have multiple fragments in one action bar tab.
This question comes closest to my needs but the code is not working.
Is there another possibility to include multiple fragments in one tab?
This is the StartActivity
public class StartActivity extends FragmentActivity implements ActionBar.TabListener {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_start);
// Set up the action bar.
final ActionBar actionBar = getActionBar();
actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
actionBar.addTab(
actionBar.newTab()
.setText("Karte")
.setTabListener(new MapFragmentListener(this)));
}
The corresponding layout acticity_start contains two frame layouts for the two fragments that will be placed in the tab.
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<FrameLayout
android:id="#+id/fragment_map"
android:layout_width="fill_parent"
android:layout_height="wrap_content"/>
<FrameLayout
android:id="#+id/fragment_realtime"
android:layout_width="fill_parent"
android:layout_height="wrap_content"/>
</LinearLayout>
The TabListener looks like this:
private class TabListener implements ActionBar.TabListener {
private static final String fragment1_tag = "fragment1_tag";
private static final String fragment2_tag = "fragment2_tag";
private FragmentActivity activity;
private RealtimeFragment fragment1;
private RealtimeFragment fragment2;
public TabListener(FragmentActivity activity) {
this.activity = activity;
android.support.v4.app.FragmentTransaction ft = activity.getSupportFragmentManager().beginTransaction();
fragment1 = (RealtimeFragment) activity.getSupportFragmentManager().findFragmentByTag(fragment1_tag);
if (fragment1 != null && !fragment1.isDetached()) {
ft.detach(fragment1);
}
fragment2 = (RealtimeFragment) activity.getSupportFragmentManager().findFragmentByTag(fragment2_tag);
if (fragment2 != null && !fragment2.isDetached()) {
ft.detach(fragment2);
}
ft.commit();
}
#Override
public void onTabReselected(Tab tab, FragmentTransaction ft) {
// TODO Auto-generated method stub
}
#Override
public void onTabSelected(Tab tab, FragmentTransaction ft) {
android.support.v4.app.FragmentTransaction fragmentTransaction = activity.getSupportFragmentManager().beginTransaction();
if(fragment1 == null) {
fragment1 = new RealtimeFragment();
fragmentTransaction.add(R.id.fragment_map, fragment1, fragment1_tag);
} else {
fragmentTransaction.attach(fragment1);
}
if(fragment2 == null) {
fragment2 = new RealtimeFragment();
fragmentTransaction.add(R.id.fragment_realtime, fragment2, fragment2_tag);
} else {
fragmentTransaction.attach(fragment2);
}
fragmentTransaction.commit();
}
#Override
public void onTabUnselected(Tab tab, FragmentTransaction ft) {
android.support.v4.app.FragmentTransaction fragementTransaction = activity.getSupportFragmentManager().beginTransaction();
if(fragment1_tag != null)
fragementTransaction.detach(fragment1);
if(fragment2 != null)
fragementTransaction.detach(fragment2);
fragementTransaction.commit();
}
}
The class RealtimeFragment and the corresponding layout fragment_realtime looks like this:
public class RealtimeFragment extends Fragment {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_realtime, container, false);
return view;
}
}
<?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" >
<Button
android:id="#+id/button1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Button" />
</LinearLayout>
In one tab now two fragments of the class RealtimeFragment should be displayed. The fragments just show one button but NOTHING is displayed! Why?
I was looking for a solution to the same Topic, and found this, which comes in quite handy.
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="match_parent">
<fragment android:name="com.example.news.ArticleListFragment"
android:id="#+id/list"
android:layout_weight="1"
android:layout_width="0dp"
android:layout_height="match_parent" />
<fragment android:name="com.example.news.ArticleReaderFragment"
android:id="#+id/viewer"
android:layout_weight="2"
android:layout_width="0dp"
android:layout_height="match_parent" />
</LinearLayout>
so Reference your Fragments and inflate it, just like a normal Fragment