API demo for nesting fragments.

Change-Id: I7f20e4f00cf68c78c578ae620a95de7fa97f0761
This commit is contained in:
Dianne Hackborn
2012-09-05 16:37:36 -07:00
parent 7002083f08
commit f3f7c5f775
23 changed files with 1281 additions and 93 deletions

View File

@@ -358,6 +358,15 @@
</intent-filter>
</activity>
<activity android:name=".app.FragmentNestingTabs"
android:label="@string/fragment_nesting_tabs"
android:enabled="@bool/atLeastJellyBeanMR1">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.SAMPLE_CODE" />
</intent-filter>
</activity>
<activity android:name=".app.FragmentRetainInstance"
android:label="@string/fragment_retain_instance"
android:enabled="@bool/atLeastHoneycomb">

View File

@@ -0,0 +1,50 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2012 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:padding="4dip"
android:gravity="center_horizontal"
android:layout_width="match_parent" android:layout_height="match_parent">
<TextView
android:id="@+id/text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="0"
android:padding="4dip"
android:layout_gravity="center_vertical|center_horizontal"
android:gravity="top|center_horizontal"
android:textAppearance="?android:attr/textAppearanceMedium"
android:text="@string/fragment_arguments_fragment_msg" />
<LinearLayout android:orientation="horizontal" android:padding="4dip"
android:layout_width="match_parent" android:layout_height="wrap_content">
<FrameLayout
android:id="@+id/created1"
android:layout_width="0px"
android:layout_height="wrap_content"
android:layout_weight="1" />
<FrameLayout
android:id="@+id/created2"
android:layout_width="0px"
android:layout_height="wrap_content"
android:layout_weight="1" />
</LinearLayout>
</LinearLayout>

View File

@@ -1,44 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2010 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<!-- Top-level content view for the simple fragment sample. -->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:padding="4dip"
android:gravity="center_horizontal"
android:layout_width="match_parent" android:layout_height="match_parent">
<android.support.v4.app.FragmentPager
android:id="@+id/pager"
android:layout_width="match_parent"
android:layout_height="0px"
android:layout_weight="1">
</android.support.v4.app.FragmentPager>
<LinearLayout android:orientation="horizontal"
android:gravity="center" android:measureWithLargestChild="true"
android:layout_width="match_parent" android:layout_height="wrap_content"
android:layout_weight="0">
<Button android:id="@+id/goto_first"
android:layout_width="wrap_content" android:layout_height="wrap_content"
android:text="@string/first">
</Button>
<Button android:id="@+id/goto_last"
android:layout_width="wrap_content" android:layout_height="wrap_content"
android:text="@string/last">
</Button>
</LinearLayout>
</LinearLayout>

View File

@@ -28,11 +28,19 @@
android:layout_weight="1">
</FrameLayout>
<LinearLayout android:orientation="horizontal" android:padding="4dip"
android:gravity="center_horizontal" android:measureWithLargestChild="true"
android:layout_width="wrap_content" android:layout_height="wrap_content"
android:layout_weight="0">
<Button android:id="@+id/new_fragment"
android:layout_width="wrap_content" android:layout_height="wrap_content"
android:layout_weight="0"
android:text="@string/new_fragment">
<requestFocus />
</Button>
<Button android:id="@+id/delete_fragment"
android:layout_width="wrap_content" android:layout_height="wrap_content"
android:layout_weight="0"
android:text="@string/delete_fragment">
</Button>
</LinearLayout>
</LinearLayout>

View File

@@ -0,0 +1,50 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
/* Copyright 2012, The Android Open Source Project
**
** Licensed under the Apache License, Version 2.0 (the "License");
** you may not use this file except in compliance with the License.
** You may obtain a copy of the License at
**
** http://www.apache.org/licenses/LICENSE-2.0
**
** Unless required by applicable law or agreed to in writing, software
** distributed under the License is distributed on an "AS IS" BASIS,
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
** See the License for the specific language governing permissions and
** limitations under the License.
*/
-->
<TabHost
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:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TabWidget
android:id="@android:id/tabs"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="0"/>
<FrameLayout
android:id="@android:id/tabcontent"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_weight="0"/>
<FrameLayout
android:id="@+android:id/realtabcontent"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"/>
</LinearLayout>
</TabHost>

View File

@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2007 The Android Open Source Project
<!-- Copyright (C) 2011 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -14,13 +14,7 @@
limitations under the License.
-->
<!-- Demonstrates basic application screen.
See corresponding Java code com.android.sdk.app.HelloWorld.java. -->
<!-- This screen consists of a single text field that
displays our "Hello, World!" text. -->
<TextView xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/text"
android:layout_width="match_parent" android:layout_height="match_parent"
android:gravity="center_vertical|center_horizontal"
android:textAppearance="?android:attr/textAppearanceMedium"
android:text="@string/hello_world"/>
<resources>
<!-- True if running under JellyBean MR1 or later. -->
<bool name="atLeastJellyBeanMR1">true</bool>
</resources>

View File

@@ -34,4 +34,9 @@
for JellyBean is true. -->
<bool name="atLeastJellyBean">false</bool>
<!-- This resource is true if running under at least JellyBean MR1
API level. The default value is false; an alternative value
for JellyBean MR 1 is true. -->
<bool name="atLeastJellyBeanMR1">false</bool>
</resources>

View File

@@ -124,6 +124,9 @@
<string name="fragment_arguments_embedded">From Attributes</string>
<string name="fragment_arguments_embedded_land">Landscape Only</string>
<string name="fragment_arguments_fragment_msg">Demonstrates two embedded fragments
that are instantiated with arguments.</string>
<string name="fragment_custom_animations">App/Fragment/Custom Animations</string>
<string name="fragment_hide_show">App/Fragment/Hide and Show</string>
@@ -152,6 +155,8 @@
<string name="fragment1menu">Show fragment 1 menu</string>
<string name="fragment2menu">Show fragment 2 menu</string>
<string name="fragment_nesting_tabs">App/Fragment/Nesting Tabs</string>
<string name="fragment_retain_instance">App/Fragment/Retain Instance</string>
<string name="fragment_retain_instance_msg">Current progress of retained fragment;
restarts if fragment is re-created.</string>
@@ -160,7 +165,8 @@
<string name="fragment_receive_result">App/Fragment/Receive Result</string>
<string name="fragment_stack">App/Fragment/Stack</string>
<string name="new_fragment">New fragment</string>
<string name="new_fragment">Push</string>
<string name="delete_fragment">Pop</string>
<string name="first">First</string>
<string name="last">Last</string>

View File

@@ -0,0 +1,53 @@
/*
* Copyright (C) 2012 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.example.android.apis.app;
import com.example.android.apis.R;
import android.app.Fragment;
import android.app.FragmentTransaction;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
/**
* Demonstrates a fragment that can be configured through both Bundle arguments
* and layout attributes.
*/
public class FragmentArgumentsFragment extends Fragment {
@Override public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (savedInstanceState == null) {
// First-time init; create fragment to embed in activity.
FragmentTransaction ft = getChildFragmentManager().beginTransaction();
Fragment newFragment = FragmentArguments.MyFragment.newInstance("From Arguments 1");
ft.add(R.id.created1, newFragment);
newFragment = FragmentArguments.MyFragment.newInstance("From Arguments 2");
ft.add(R.id.created2, newFragment);
ft.commit();
}
}
@Override public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.fragment_arguments_fragment, container, false);
return v;
}
//END_INCLUDE(create)
}

View File

@@ -29,6 +29,7 @@ import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.view.ContextMenu.ContextMenuInfo;
import android.widget.Toast;
/**
* Demonstration of displaying a context menu from a fragment.
@@ -65,10 +66,10 @@ public class FragmentContextMenu extends Activity {
public boolean onContextItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.a_item:
Log.i("ContextMenu", "Item 1a was chosen");
Toast.makeText(getActivity(), "Item 1a was chosen", Toast.LENGTH_SHORT).show();
return true;
case R.id.b_item:
Log.i("ContextMenu", "Item 1b was chosen");
Toast.makeText(getActivity(), "Item 1b was chosen", Toast.LENGTH_SHORT).show();
return true;
}
return super.onContextItemSelected(item);

View File

@@ -0,0 +1,95 @@
/*
* Copyright (C) 2012 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.example.android.apis.app;
import com.example.android.apis.R;
import android.app.Fragment;
import android.app.FragmentManager;
import android.app.FragmentTransaction;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.CheckBox;
/**
* Demonstrates how fragments can participate in the options menu.
*/
public class FragmentMenuFragment extends Fragment {
Fragment mFragment1;
Fragment mFragment2;
CheckBox mCheckBox1;
CheckBox mCheckBox2;
// Update fragment visibility when check boxes are changed.
final OnClickListener mClickListener = new OnClickListener() {
public void onClick(View v) {
updateFragmentVisibility();
}
};
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.fragment_menu, container, false);
// Make sure the two menu fragments are created.
FragmentManager fm = getChildFragmentManager();
FragmentTransaction ft = fm.beginTransaction();
mFragment1 = fm.findFragmentByTag("f1");
if (mFragment1 == null) {
mFragment1 = new FragmentMenu.MenuFragment();
ft.add(mFragment1, "f1");
}
mFragment2 = fm.findFragmentByTag("f2");
if (mFragment2 == null) {
mFragment2 = new FragmentMenu.Menu2Fragment();
ft.add(mFragment2, "f2");
}
ft.commit();
// Watch check box clicks.
mCheckBox1 = (CheckBox)v.findViewById(R.id.menu1);
mCheckBox1.setOnClickListener(mClickListener);
mCheckBox2 = (CheckBox)v.findViewById(R.id.menu2);
mCheckBox2.setOnClickListener(mClickListener);
// Make sure fragments start out with correct visibility.
updateFragmentVisibility();
return v;
}
@Override
public void onViewStateRestored(Bundle savedInstanceState) {
super.onViewStateRestored(savedInstanceState);
// Make sure fragments are updated after check box view state is restored.
updateFragmentVisibility();
}
// Update fragment visibility based on current check box state.
void updateFragmentVisibility() {
FragmentTransaction ft = getChildFragmentManager().beginTransaction();
if (mCheckBox1.isChecked()) ft.show(mFragment1);
else ft.hide(mFragment1);
if (mCheckBox2.isChecked()) ft.show(mFragment2);
else ft.hide(mFragment2);
ft.commit();
}
}

View File

@@ -0,0 +1,116 @@
/*
* Copyright (C) 2012 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.example.android.apis.app;
//BEGIN_INCLUDE(complete)
import android.app.ActionBar;
import android.app.ActionBar.Tab;
import android.app.Activity;
import android.app.Fragment;
import android.app.FragmentTransaction;
import android.os.Bundle;
import android.widget.Toast;
/**
* This demonstrates the use of action bar tabs and how they interact
* with other action bar features.
*/
public class FragmentNestingTabs extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
final ActionBar bar = getActionBar();
bar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
bar.setDisplayOptions(0, ActionBar.DISPLAY_SHOW_TITLE);
bar.addTab(bar.newTab()
.setText("Menus")
.setTabListener(new TabListener<FragmentMenuFragment>(
this, "menus", FragmentMenuFragment.class)));
bar.addTab(bar.newTab()
.setText("Args")
.setTabListener(new TabListener<FragmentArgumentsFragment>(
this, "args", FragmentArgumentsFragment.class)));
bar.addTab(bar.newTab()
.setText("Stack")
.setTabListener(new TabListener<FragmentStackFragment>(
this, "stack", FragmentStackFragment.class)));
bar.addTab(bar.newTab()
.setText("Tabs")
.setTabListener(new TabListener<FragmentTabsFragment>(
this, "tabs", FragmentTabsFragment.class)));
if (savedInstanceState != null) {
bar.setSelectedNavigationItem(savedInstanceState.getInt("tab", 0));
}
}
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putInt("tab", getActionBar().getSelectedNavigationIndex());
}
public static class TabListener<T extends Fragment> implements ActionBar.TabListener {
private final Activity mActivity;
private final String mTag;
private final Class<T> mClass;
private final Bundle mArgs;
private Fragment mFragment;
public TabListener(Activity activity, String tag, Class<T> clz) {
this(activity, tag, clz, null);
}
public TabListener(Activity activity, String tag, Class<T> clz, Bundle args) {
mActivity = activity;
mTag = tag;
mClass = clz;
mArgs = args;
// Check to see if we already have a fragment for this tab, probably
// from a previously saved state. If so, deactivate it, because our
// initial state is that a tab isn't shown.
mFragment = mActivity.getFragmentManager().findFragmentByTag(mTag);
if (mFragment != null && !mFragment.isDetached()) {
FragmentTransaction ft = mActivity.getFragmentManager().beginTransaction();
ft.detach(mFragment);
ft.commit();
}
}
public void onTabSelected(Tab tab, FragmentTransaction ft) {
if (mFragment == null) {
mFragment = Fragment.instantiate(mActivity, mClass.getName(), mArgs);
ft.add(android.R.id.content, mFragment, mTag);
} else {
ft.attach(mFragment);
}
}
public void onTabUnselected(Tab tab, FragmentTransaction ft) {
if (mFragment != null) {
ft.detach(mFragment);
}
}
public void onTabReselected(Tab tab, FragmentTransaction ft) {
Toast.makeText(mActivity, "Reselected!", Toast.LENGTH_SHORT).show();
}
}
}
//END_INCLUDE(complete)

View File

@@ -44,6 +44,12 @@ public class FragmentStack extends Activity {
addFragmentToStack();
}
});
button = (Button)findViewById(R.id.delete_fragment);
button.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
getFragmentManager().popBackStack();
}
});
if (savedInstanceState == null) {
// Do first time initialization -- add initial fragment.

View File

@@ -0,0 +1,89 @@
/*
* Copyright (C) 2012 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.example.android.apis.app;
import com.example.android.apis.R;
import android.app.Fragment;
import android.app.FragmentTransaction;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.View.OnClickListener;
import android.widget.Button;
public class FragmentStackFragment extends Fragment {
int mStackLevel = 1;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (savedInstanceState == null) {
// Do first time initialization -- add initial fragment.
Fragment newFragment = FragmentStack.CountingFragment.newInstance(mStackLevel);
FragmentTransaction ft = getChildFragmentManager().beginTransaction();
ft.add(R.id.simple_fragment, newFragment).commit();
} else {
mStackLevel = savedInstanceState.getInt("level");
}
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.fragment_stack, container, false);
// Watch for button clicks.
Button button = (Button)v.findViewById(R.id.new_fragment);
button.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
addFragmentToStack();
}
});
button = (Button)v.findViewById(R.id.delete_fragment);
button.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
getChildFragmentManager().popBackStack();
}
});
return v;
}
@Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putInt("level", mStackLevel);
}
void addFragmentToStack() {
mStackLevel++;
// Instantiate a new fragment.
Fragment newFragment = FragmentStack.CountingFragment.newInstance(mStackLevel);
// Add the fragment to the activity, pushing this transaction
// on to the back stack.
FragmentTransaction ft = getChildFragmentManager().beginTransaction();
ft.replace(R.id.simple_fragment, newFragment);
ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN);
ft.addToBackStack(null);
ft.commit();
}
}

View File

@@ -0,0 +1,189 @@
/*
* Copyright (C) 2012 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.example.android.apis.app;
import java.util.HashMap;
import com.example.android.apis.R;
import android.app.Fragment;
import android.app.FragmentManager;
import android.app.FragmentTransaction;
import android.content.Context;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TabHost;
public class FragmentTabsFragment extends Fragment {
TabHost mTabHost;
TabManager mTabManager;
String mCurrentTabTag;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.fragment_tabs_fragment, container, false);
mTabHost = (TabHost)v.findViewById(android.R.id.tabhost);
mTabHost.setup();
mTabManager = new TabManager(getActivity(), getChildFragmentManager(),
mTabHost, R.id.realtabcontent);
mTabManager.addTab(mTabHost.newTabSpec("result").setIndicator("Result"),
FragmentReceiveResult.ReceiveResultFragment.class, null);
mTabManager.addTab(mTabHost.newTabSpec("contacts").setIndicator("Contacts"),
LoaderCursor.CursorLoaderListFragment.class, null);
mTabManager.addTab(mTabHost.newTabSpec("apps").setIndicator("Apps"),
LoaderCustom.AppListFragment.class, null);
mTabManager.addTab(mTabHost.newTabSpec("throttle").setIndicator("Throttle"),
LoaderThrottle.ThrottledLoaderListFragment.class, null);
return v;
}
@Override
public void onViewStateRestored(Bundle savedInstanceState) {
super.onViewStateRestored(savedInstanceState);
if (savedInstanceState != null) {
mCurrentTabTag = savedInstanceState.getString("tab");
}
mTabHost.setCurrentTabByTag(mCurrentTabTag);
}
@Override
public void onDestroyView() {
super.onDestroyView();
// Need to remember the selected tab so that we can restore it if
// we later re-create the views.
mCurrentTabTag = mTabHost.getCurrentTabTag();
mTabHost = null;
mTabManager = null;
}
@Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putString("tab", mTabHost != null
? mTabHost.getCurrentTabTag() : mCurrentTabTag);
}
/**
* This is a helper class that implements a generic mechanism for
* associating fragments with the tabs in a tab host. It relies on a
* trick. Normally a tab host has a simple API for supplying a View or
* Intent that each tab will show. This is not sufficient for switching
* between fragments. So instead we make the content part of the tab host
* 0dp high (it is not shown) and the TabManager supplies its own dummy
* view to show as the tab content. It listens to changes in tabs, and takes
* care of switch to the correct fragment shown in a separate content area
* whenever the selected tab changes.
*/
public static class TabManager implements TabHost.OnTabChangeListener {
private final Context mContext;
private final FragmentManager mManager;
private final TabHost mTabHost;
private final int mContainerId;
private final HashMap<String, TabInfo> mTabs = new HashMap<String, TabInfo>();
TabInfo mLastTab;
static final class TabInfo {
private final String tag;
private final Class<?> clss;
private final Bundle args;
private Fragment fragment;
TabInfo(String _tag, Class<?> _class, Bundle _args) {
tag = _tag;
clss = _class;
args = _args;
}
}
static class DummyTabFactory implements TabHost.TabContentFactory {
private final Context mContext;
public DummyTabFactory(Context context) {
mContext = context;
}
@Override
public View createTabContent(String tag) {
View v = new View(mContext);
v.setMinimumWidth(0);
v.setMinimumHeight(0);
return v;
}
}
public TabManager(Context context, FragmentManager manager, TabHost tabHost,
int containerId) {
mContext = context;
mManager = manager;
mTabHost = tabHost;
mContainerId = containerId;
mTabHost.setOnTabChangedListener(this);
}
public void addTab(TabHost.TabSpec tabSpec, Class<?> clss, Bundle args) {
tabSpec.setContent(new DummyTabFactory(mContext));
String tag = tabSpec.getTag();
TabInfo info = new TabInfo(tag, clss, args);
// Check to see if we already have a fragment for this tab, probably
// from a previously saved state. If so, deactivate it, because our
// initial state is that a tab isn't shown.
info.fragment = mManager.findFragmentByTag(tag);
if (info.fragment != null && !info.fragment.isDetached()) {
FragmentTransaction ft = mManager.beginTransaction();
ft.detach(info.fragment);
ft.commit();
}
mTabs.put(tag, info);
mTabHost.addTab(tabSpec);
}
@Override
public void onTabChanged(String tabId) {
TabInfo newTab = mTabs.get(tabId);
if (mLastTab != newTab) {
FragmentTransaction ft = mManager.beginTransaction();
if (mLastTab != null) {
if (mLastTab.fragment != null) {
ft.detach(mLastTab.fragment);
}
}
if (newTab != null) {
if (newTab.fragment == null) {
newTab.fragment = Fragment.instantiate(mContext,
newTab.clss.getName(), newTab.args);
ft.add(mContainerId, newTab.fragment, newTab.tag);
} else {
ft.attach(newTab.fragment);
}
}
mLastTab = newTab;
ft.commit();
mManager.executePendingTransactions();
}
}
}
}
//END_INCLUDE(complete)

View File

@@ -47,6 +47,22 @@
<!-- Fragment Support Samples -->
<activity android:name=".app.FragmentNestingPagerSupport"
android:label="@string/fragment_nesting_pager_support">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="com.example.android.supportv13.SUPPORT13_SAMPLE_CODE" />
</intent-filter>
</activity>
<activity android:name=".app.FragmentNestingStatePagerSupport"
android:label="@string/fragment_nesting_state_pager_support">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="com.example.android.supportv13.SUPPORT13_SAMPLE_CODE" />
</intent-filter>
</activity>
<activity android:name=".app.FragmentPagerSupport"
android:label="@string/fragment_pager_support">
<intent-filter>

View File

@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2011 The Android Open Source Project
<!-- Copyright (C) 2007 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -14,39 +14,24 @@
limitations under the License.
-->
<!-- Demonstrates basic application screen.
See corresponding Java code com.android.sdk.app.HelloWorld.java. -->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@android:drawable/gallery_thumb">
<TextView android:id="@+id/text"
android:layout_width="match_parent" android:layout_height="wrap_content"
android:gravity="center_vertical|center_horizontal"
android:textAppearance="?android:attr/textAppearanceMedium"
android:text="@string/hello_world"/>
<!-- The frame layout is here since we will be showing either
the empty view or the list view. -->
<FrameLayout
android:layout_width="match_parent"
android:layout_height="0dip"
android:layout_weight="1" >
<!-- Here is the list. Since we are using a ListActivity, we
have to call it "@android:id/list" so ListActivity will
find it -->
<ListView android:id="@android:id/list"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:drawSelectorOnTop="false"/>
<!-- Here is the view to show if the list is emtpy -->
<TextView android:id="@android:id/empty"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:textAppearance="?android:attr/textAppearanceMedium"
android:text="No items."/>
</FrameLayout>
<CheckBox android:id="@+id/menu1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:checked="true"
android:text="@string/retained">
</CheckBox>
</LinearLayout>

View File

@@ -0,0 +1,50 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
/* Copyright 2012, The Android Open Source Project
**
** Licensed under the Apache License, Version 2.0 (the "License");
** you may not use this file except in compliance with the License.
** You may obtain a copy of the License at
**
** http://www.apache.org/licenses/LICENSE-2.0
**
** Unless required by applicable law or agreed to in writing, software
** distributed under the License is distributed on an "AS IS" BASIS,
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
** See the License for the specific language governing permissions and
** limitations under the License.
*/
-->
<TabHost
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:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TabWidget
android:id="@android:id/tabs"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="0"/>
<FrameLayout
android:id="@android:id/tabcontent"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_weight="0"/>
<FrameLayout
android:id="@+android:id/realtabcontent"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"/>
</LinearLayout>
</TabHost>

View File

@@ -18,11 +18,17 @@
<string name="activity_sample_code">Support v13 Demos</string>
<string name="hello_world"><b>Hello, <i>World!</i></b></string>
<string name="retained">Retained state</string>
<string name="alert_dialog_two_buttons_title">
Lorem ipsum dolor sit aie consectetur adipiscing\nPlloaso mako nuto
siwuf cakso dodtos anr koop.
</string>
<string name="fragment_nesting_pager_support">Fragment/Nesting Pager</string>
<string name="fragment_nesting_state_pager_support">Fragment/Nesting State Pager</string>
<string name="fragment_pager_support">Fragment/Pager</string>
<string name="first">First</string>
<string name="last">Last</string>

View File

@@ -58,10 +58,9 @@ public class CountingFragment extends Fragment {
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.hello_world, container, false);
View v = inflater.inflate(R.layout.counting, container, false);
View tv = v.findViewById(R.id.text);
((TextView)tv).setText("Fragment #" + mNum);
tv.setBackgroundDrawable(getResources().getDrawable(android.R.drawable.gallery_thumb));
return v;
}
}

View File

@@ -0,0 +1,159 @@
/*
* Copyright (C) 2012 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.example.android.supportv13.app;
import java.util.ArrayList;
import com.example.android.supportv13.R;
import android.app.ActionBar;
import android.app.ActionBar.Tab;
import android.app.Activity;
import android.app.Fragment;
import android.app.FragmentTransaction;
import android.content.Context;
import android.os.Bundle;
import android.support.v13.app.FragmentPagerAdapter;
import android.support.v4.view.ViewPager;
//BEGIN_INCLUDE(complete)
public class FragmentNestingPagerSupport extends Activity {
ViewPager mViewPager;
TabsAdapter mTabsAdapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mViewPager = new ViewPager(this);
mViewPager.setId(R.id.pager);
setContentView(mViewPager);
final ActionBar bar = getActionBar();
bar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
bar.setDisplayOptions(0, ActionBar.DISPLAY_SHOW_TITLE);
mTabsAdapter = new TabsAdapter(this, mViewPager);
mTabsAdapter.addTab(bar.newTab().setText("Simple"),
CountingFragment.class, null);
mTabsAdapter.addTab(bar.newTab().setText("List"),
FragmentPagerSupport.ArrayListFragment.class, null);
mTabsAdapter.addTab(bar.newTab().setText("Cursor"),
CursorFragment.class, null);
mTabsAdapter.addTab(bar.newTab().setText("Tabs"),
FragmentTabsFragment.class, null);
if (savedInstanceState != null) {
bar.setSelectedNavigationItem(savedInstanceState.getInt("tab", 0));
}
}
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putInt("tab", getActionBar().getSelectedNavigationIndex());
}
/**
* This is a helper class that implements the management of tabs and all
* details of connecting a ViewPager with associated TabHost. It relies on a
* trick. Normally a tab host has a simple API for supplying a View or
* Intent that each tab will show. This is not sufficient for switching
* between pages. So instead we make the content part of the tab host
* 0dp high (it is not shown) and the TabsAdapter supplies its own dummy
* view to show as the tab content. It listens to changes in tabs, and takes
* care of switch to the correct paged in the ViewPager whenever the selected
* tab changes.
*/
public static class TabsAdapter extends FragmentPagerAdapter
implements ActionBar.TabListener, ViewPager.OnPageChangeListener {
private final Context mContext;
private final ActionBar mActionBar;
private final ViewPager mViewPager;
private final ArrayList<TabInfo> mTabs = new ArrayList<TabInfo>();
static final class TabInfo {
private final Class<?> clss;
private final Bundle args;
TabInfo(Class<?> _class, Bundle _args) {
clss = _class;
args = _args;
}
}
public TabsAdapter(Activity activity, ViewPager pager) {
super(activity.getFragmentManager());
mContext = activity;
mActionBar = activity.getActionBar();
mViewPager = pager;
mViewPager.setAdapter(this);
mViewPager.setOnPageChangeListener(this);
}
public void addTab(ActionBar.Tab tab, Class<?> clss, Bundle args) {
TabInfo info = new TabInfo(clss, args);
tab.setTag(info);
tab.setTabListener(this);
mTabs.add(info);
mActionBar.addTab(tab);
notifyDataSetChanged();
}
@Override
public int getCount() {
return mTabs.size();
}
@Override
public Fragment getItem(int position) {
TabInfo info = mTabs.get(position);
return Fragment.instantiate(mContext, info.clss.getName(), info.args);
}
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
}
@Override
public void onPageSelected(int position) {
mActionBar.setSelectedNavigationItem(position);
}
@Override
public void onPageScrollStateChanged(int state) {
}
@Override
public void onTabSelected(Tab tab, FragmentTransaction ft) {
Object tag = tab.getTag();
for (int i=0; i<mTabs.size(); i++) {
if (mTabs.get(i) == tag) {
mViewPager.setCurrentItem(i);
}
}
}
@Override
public void onTabUnselected(Tab tab, FragmentTransaction ft) {
}
@Override
public void onTabReselected(Tab tab, FragmentTransaction ft) {
}
}
}
//END_INCLUDE(complete)

View File

@@ -0,0 +1,159 @@
/*
* Copyright (C) 2012 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.example.android.supportv13.app;
import java.util.ArrayList;
import com.example.android.supportv13.R;
import android.app.ActionBar;
import android.app.ActionBar.Tab;
import android.app.Activity;
import android.app.Fragment;
import android.app.FragmentTransaction;
import android.content.Context;
import android.os.Bundle;
import android.support.v13.app.FragmentStatePagerAdapter;
import android.support.v4.view.ViewPager;
//BEGIN_INCLUDE(complete)
public class FragmentNestingStatePagerSupport extends Activity {
ViewPager mViewPager;
TabsAdapter mTabsAdapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mViewPager = new ViewPager(this);
mViewPager.setId(R.id.pager);
setContentView(mViewPager);
final ActionBar bar = getActionBar();
bar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
bar.setDisplayOptions(0, ActionBar.DISPLAY_SHOW_TITLE);
mTabsAdapter = new TabsAdapter(this, mViewPager);
mTabsAdapter.addTab(bar.newTab().setText("Simple"),
CountingFragment.class, null);
mTabsAdapter.addTab(bar.newTab().setText("List"),
FragmentPagerSupport.ArrayListFragment.class, null);
mTabsAdapter.addTab(bar.newTab().setText("Cursor"),
CursorFragment.class, null);
mTabsAdapter.addTab(bar.newTab().setText("Tabs"),
FragmentTabsFragment.class, null);
if (savedInstanceState != null) {
bar.setSelectedNavigationItem(savedInstanceState.getInt("tab", 0));
}
}
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putInt("tab", getActionBar().getSelectedNavigationIndex());
}
/**
* This is a helper class that implements the management of tabs and all
* details of connecting a ViewPager with associated TabHost. It relies on a
* trick. Normally a tab host has a simple API for supplying a View or
* Intent that each tab will show. This is not sufficient for switching
* between pages. So instead we make the content part of the tab host
* 0dp high (it is not shown) and the TabsAdapter supplies its own dummy
* view to show as the tab content. It listens to changes in tabs, and takes
* care of switch to the correct paged in the ViewPager whenever the selected
* tab changes.
*/
public static class TabsAdapter extends FragmentStatePagerAdapter
implements ActionBar.TabListener, ViewPager.OnPageChangeListener {
private final Context mContext;
private final ActionBar mActionBar;
private final ViewPager mViewPager;
private final ArrayList<TabInfo> mTabs = new ArrayList<TabInfo>();
static final class TabInfo {
private final Class<?> clss;
private final Bundle args;
TabInfo(Class<?> _class, Bundle _args) {
clss = _class;
args = _args;
}
}
public TabsAdapter(Activity activity, ViewPager pager) {
super(activity.getFragmentManager());
mContext = activity;
mActionBar = activity.getActionBar();
mViewPager = pager;
mViewPager.setAdapter(this);
mViewPager.setOnPageChangeListener(this);
}
public void addTab(ActionBar.Tab tab, Class<?> clss, Bundle args) {
TabInfo info = new TabInfo(clss, args);
tab.setTag(info);
tab.setTabListener(this);
mTabs.add(info);
mActionBar.addTab(tab);
notifyDataSetChanged();
}
@Override
public int getCount() {
return mTabs.size();
}
@Override
public Fragment getItem(int position) {
TabInfo info = mTabs.get(position);
return Fragment.instantiate(mContext, info.clss.getName(), info.args);
}
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
}
@Override
public void onPageSelected(int position) {
mActionBar.setSelectedNavigationItem(position);
}
@Override
public void onPageScrollStateChanged(int state) {
}
@Override
public void onTabSelected(Tab tab, FragmentTransaction ft) {
Object tag = tab.getTag();
for (int i=0; i<mTabs.size(); i++) {
if (mTabs.get(i) == tag) {
mViewPager.setCurrentItem(i);
}
}
}
@Override
public void onTabUnselected(Tab tab, FragmentTransaction ft) {
}
@Override
public void onTabReselected(Tab tab, FragmentTransaction ft) {
}
}
}
//END_INCLUDE(complete)

View File

@@ -0,0 +1,187 @@
/*
* Copyright (C) 2012 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.example.android.supportv13.app;
import java.util.HashMap;
import com.example.android.supportv13.R;
import android.app.Fragment;
import android.app.FragmentManager;
import android.app.FragmentTransaction;
import android.content.Context;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TabHost;
public class FragmentTabsFragment extends Fragment {
TabHost mTabHost;
TabManager mTabManager;
String mCurrentTabTag;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.fragment_tabs_fragment, container, false);
mTabHost = (TabHost)v.findViewById(android.R.id.tabhost);
mTabHost.setup();
mTabManager = new TabManager(getActivity(), getChildFragmentManager(),
mTabHost, R.id.realtabcontent);
mTabManager.addTab(mTabHost.newTabSpec("simple").setIndicator("Simple"),
CountingFragment.class, null);
mTabManager.addTab(mTabHost.newTabSpec("array").setIndicator("Array"),
FragmentPagerSupport.ArrayListFragment.class, null);
mTabManager.addTab(mTabHost.newTabSpec("cursor").setIndicator("Cursor"),
CursorFragment.class, null);
return v;
}
@Override
public void onViewStateRestored(Bundle savedInstanceState) {
super.onViewStateRestored(savedInstanceState);
if (savedInstanceState != null) {
mCurrentTabTag = savedInstanceState.getString("tab");
}
mTabHost.setCurrentTabByTag(mCurrentTabTag);
}
@Override
public void onDestroyView() {
super.onDestroyView();
// Need to remember the selected tab so that we can restore it if
// we later re-create the views.
mCurrentTabTag = mTabHost.getCurrentTabTag();
mTabHost = null;
mTabManager = null;
}
@Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putString("tab", mTabHost != null
? mTabHost.getCurrentTabTag() : mCurrentTabTag);
}
/**
* This is a helper class that implements a generic mechanism for
* associating fragments with the tabs in a tab host. It relies on a
* trick. Normally a tab host has a simple API for supplying a View or
* Intent that each tab will show. This is not sufficient for switching
* between fragments. So instead we make the content part of the tab host
* 0dp high (it is not shown) and the TabManager supplies its own dummy
* view to show as the tab content. It listens to changes in tabs, and takes
* care of switch to the correct fragment shown in a separate content area
* whenever the selected tab changes.
*/
public static class TabManager implements TabHost.OnTabChangeListener {
private final Context mContext;
private final FragmentManager mManager;
private final TabHost mTabHost;
private final int mContainerId;
private final HashMap<String, TabInfo> mTabs = new HashMap<String, TabInfo>();
TabInfo mLastTab;
static final class TabInfo {
private final String tag;
private final Class<?> clss;
private final Bundle args;
private Fragment fragment;
TabInfo(String _tag, Class<?> _class, Bundle _args) {
tag = _tag;
clss = _class;
args = _args;
}
}
static class DummyTabFactory implements TabHost.TabContentFactory {
private final Context mContext;
public DummyTabFactory(Context context) {
mContext = context;
}
@Override
public View createTabContent(String tag) {
View v = new View(mContext);
v.setMinimumWidth(0);
v.setMinimumHeight(0);
return v;
}
}
public TabManager(Context context, FragmentManager manager, TabHost tabHost,
int containerId) {
mContext = context;
mManager = manager;
mTabHost = tabHost;
mContainerId = containerId;
mTabHost.setOnTabChangedListener(this);
}
public void addTab(TabHost.TabSpec tabSpec, Class<?> clss, Bundle args) {
tabSpec.setContent(new DummyTabFactory(mContext));
String tag = tabSpec.getTag();
TabInfo info = new TabInfo(tag, clss, args);
// Check to see if we already have a fragment for this tab, probably
// from a previously saved state. If so, deactivate it, because our
// initial state is that a tab isn't shown.
info.fragment = mManager.findFragmentByTag(tag);
if (info.fragment != null && !info.fragment.isDetached()) {
FragmentTransaction ft = mManager.beginTransaction();
ft.detach(info.fragment);
ft.commit();
}
mTabs.put(tag, info);
mTabHost.addTab(tabSpec);
}
@Override
public void onTabChanged(String tabId) {
TabInfo newTab = mTabs.get(tabId);
if (mLastTab != newTab) {
FragmentTransaction ft = mManager.beginTransaction();
if (mLastTab != null) {
if (mLastTab.fragment != null) {
ft.detach(mLastTab.fragment);
}
}
if (newTab != null) {
if (newTab.fragment == null) {
newTab.fragment = Fragment.instantiate(mContext,
newTab.clss.getName(), newTab.args);
ft.add(mContainerId, newTab.fragment, newTab.tag);
} else {
ft.attach(newTab.fragment);
}
}
mLastTab = newTab;
ft.commit();
mManager.executePendingTransactions();
}
}
}
}
//END_INCLUDE(complete)