问题
I\'m working on an Android App and I want to use 3 tabs for navigation using Fragments for each tab, but I don\'t know how to create the structure for doing it.
I want to add each fragment separately because each one is different, but I don\'t know where to add them in FragmentActivity.
I have these files.
tabs_layout.xml
<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"
android:orientation=\"vertical\"
android:layout_height=\"match_parent\"
android:layout_width=\"match_parent\">
<TabHost 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:layout_width=\"match_parent\"
android:layout_height=\"wrap_content\"
/>
<FrameLayout
android:id=\"@android:id/tabcontent\"
android:layout_width=\"match_parent\"
android:layout_height=\"match_parent\"
>
<FrameLayout
android:id=\"@+id/tabRateAPet\"
android:layout_width=\"match_parent\"
android:layout_height=\"match_parent\"
/>
<FrameLayout
android:id=\"@+id/tabViewMyRates\"
android:layout_width=\"match_parent\"
android:layout_height=\"match_parent\"
/>
<FrameLayout
android:id=\"@+id/tabViewGlobalRates\"
android:layout_width=\"match_parent\"
android:layout_height=\"match_parent\"
/>
</FrameLayout>
</LinearLayout>
</TabHost>
</LinearLayout>
TabsMain.java
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentActivity;
public class MainTabsActivity extends FragmentActivity {
public static final String RATE_A_PET = \"Rate a Pet\";
public static final String MY_RATES = \"My Rates\";
public static final String GLOBAL_RATES = \"Global Rates\";
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.tabs_layout);
}
}
Tabs.java
import android.app.Activity;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TabHost;
import android.widget.TabHost.OnTabChangeListener;
import android.widget.TabHost.TabSpec;
import android.widget.TextView;
public class Tabs extends Fragment implements OnTabChangeListener {
private static final String TAG = \"FragmentTabs\";
public static final String RATE_A_PET = \"Rate a Pet\";
public static final String MY_RATES = \"My Rates\";
public static final String GLOBAL_RATES = \"Global Rates\";
private View mRoot;
private TabHost mTabHost;
private int mCurrentTab;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// super.onCreateView(inflater, container, savedInstanceState);
mRoot = inflater.inflate(R.layout.tabs_layout, null);
mTabHost = (TabHost) mRoot.findViewById(android.R.id.tabhost);
setupTabs();
return mRoot;
}
private void setupTabs() {
mTabHost.setup(); // important!
mTabHost.addTab(newTab(RATE_A_PET, R.string.tabRateAPet, R.id.tabRateAPet));
mTabHost.addTab(newTab(MY_RATES, R.string.tabViewMyRates, R.id.tabViewMyRates));
}
private TabSpec newTab(String tag, int labelId, int tabContentId) {
Log.d(TAG, \"buildTab(): tag=\" + tag);
View indicator = LayoutInflater.from(getActivity()).inflate(
R.layout.tab,
(ViewGroup) mRoot.findViewById(android.R.id.tabs), false);
((TextView) indicator.findViewById(R.id.text)).setText(labelId);
TabSpec tabSpec = mTabHost.newTabSpec(tag);
tabSpec.setIndicator(indicator);
tabSpec.setContent(tabContentId);
return tabSpec;
}
@Override
public void onTabChanged(String tabId) {
Log.d(TAG, \"onTabChanged(): tabId=\" + tabId);
if (RATE_A_PET.equals(tabId)) {
updateTab(tabId, R.id.tabRateAPet);
mCurrentTab = 0;
return;
}
if (MY_RATES.equals(tabId)) {
updateTab(tabId, R.id.tabViewMyRates);
mCurrentTab = 1;
return;
}
if (GLOBAL_RATES.equals(tabId)) {
updateTab(tabId, R.id.tabViewGlobalRates);
mCurrentTab = 2;
return;
}
}
private void updateTab(String tabId, int placeholder) {
FragmentManager fm = getFragmentManager();
if (fm.findFragmentByTag(tabId) == null) {
fm.beginTransaction()
.replace(placeholder, new RateMyPetActivity(), tabId)
.commit();
}
}
}
回答1:
I would suggest creating a separate fragment file for each tab. I recently did this as well, so I have outlined my code below:
Layout Files
activity_main.xml
<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: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="@+id/realtabcontent"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"/>
</LinearLayout>
</android.support.v4.app.FragmentTabHost>
tab1_view.xml //add your respective tab layouts using this format (make sure to change string variables)
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".DeviceFragment" >
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/tab1_fragment_string" />
</LinearLayout>
SRC Files
MainActivity.java //notice that in the .addTab process I only used text. You can also add icons using drawables that you would need to add to your hdpi folder. I also only created three tabs in this example.
package com.example.applicationname;
import android.os.Bundle;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.FragmentTabHost;
public class MainActivity extends FragmentActivity {
// Fragment TabHost as mTabHost
private FragmentTabHost mTabHost;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mTabHost = (FragmentTabHost)findViewById(android.R.id.tabhost);
mTabHost.setup(this, getSupportFragmentManager(), R.id.realtabcontent);
mTabHost.addTab(mTabHost.newTabSpec("tab1").setIndicator("Tab1"),
Tab1Fragment.class, null);
mTabHost.addTab(mTabHost.newTabSpec("tab2").setIndicator("Tab2"),
Tab2Fragment.class, null);
mTabHost.addTab(mTabHost.newTabSpec("tab3").setIndicator("Tab3"),
Tab3Fragment.class, null);
}
}
Tab1Fragment.java //once again replicate for desired number of tabs
package com.example.applicationname;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
public class Tab1Fragment extends Fragment {
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View V = inflater.inflate(R.layout.tab1_view, container, false);
return V;
}
}
Make sure that your R.java and strings.xml files are properly set up, and then your tabs should be up and running.
回答2:
TabHost doesn't retains Fragment's states. So why using TabHost?
So use ViewPager with TabLayout instead.
Prons of Viewpager over Tabhost:
- ViewPager retains Fragments states. Mean Fragment will not again recreated if switched.
- Inbuilt swiping feature that gives user smoother experience.
- Less CPU consumption, because Tabhost recreates Fragment/Activity again and again when Tab is switched.
See the difference :
Using Tablayout + ViewPager (Supports swipe, retains Fragments states
Using TabHost (Doesn't support swipe, doesn't retain states)
Small Code for Tablayout + ViewPager
// find views by id
ViewPager viewPager = findViewById(R.id.viewpager);
TabLayout tabLayout = findViewById(R.id.tablayout);
// attach tablayout with viewpager
tabLayout.setupWithViewPager(viewPager);
ViewPagerAdapter adapter = new ViewPagerAdapter(getSupportFragmentManager());
// add your fragments
adapter.addFrag(new SampleFragment(), "Tab1");
adapter.addFrag(new SampleFragment(), "Tab2");
adapter.addFrag(new SampleFragment(), "Tab3");
// set adapter on viewpager
viewPager.setAdapter(adapter);
XML layout
<?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">
<com.google.android.material.tabs.TabLayout
android:id="@+id/tablayout"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<androidx.viewpager.widget.ViewPager
android:id="@+id/viewpager"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1" />
</LinearLayout>
Note If you are not using AndroidX yet, you need to change following in layout.
- Change
com.google.android.material.tabs.TabLayouttoandroid.support.design.widget.TabLayout - Chagne
androidx.viewpager.widget.ViewPagertoandroid.support.v4.view.ViewPager
But I'll strongly recommend to migrate to AndroidX, see @this answer to understand why.
And this is common ViewPagerAdapter for all your Viewpager in app.
public class ViewPagerAdapter extends FragmentStatePagerAdapter {
private final List<Fragment> mFragmentList = new ArrayList<>();
private final List<String> mFragmentTitleList = new ArrayList<>();
public ViewPagerAdapter(FragmentManager manager) {
super(manager);
}
@Override
public Fragment getItem(int position) {
return mFragmentList.get(position);
}
@Override
public int getCount() {
return mFragmentList.size();
}
@Override
public CharSequence getPageTitle(int position) {
return mFragmentTitleList.get(position);
}
public void addFrag(Fragment fragment) {
mFragmentList.add(fragment);
mFragmentTitleList.add("");
}
public void addFrag(Fragment fragment, String title) {
mFragmentList.add(fragment);
mFragmentTitleList.add(title);
}
}
Important Related Links
- Difference between getSupportFragmentManager() and getChildFragmentManager()?
- getSupportFragmentManager() versus getFragmentManager() in android 3.0+
- Difference between FragmentPagerAdapter and FragmentStatePagerAdapter
来源:https://stackoverflow.com/questions/17227855/tabhost-with-fragments-and-fragmentactivity