TabHost с фрагментами и FragmentActivity

Я работаю над приложением для Android и хочу использовать 3 вкладки для навигации, используя фрагменты для каждой вкладки, но я не знаю, как создать структуру для этого.

Я хочу добавить каждый фрагмент отдельно, потому что каждый из них отличается, но я не знаю, куда их добавить в FragmentActivity.

У меня есть эти файлы.

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>

ВкладкиMain.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);
 }
}

Вкладки.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();
        }
    }

}

person imarban    schedule 21.06.2013    source источник
comment
посмотрите этот учебник, и если вы обнаружите какие-либо трудности. вы можете спросить меня ... manishkpr.webheavens .com/android-viewpager-пример   -  person TheFlash    schedule 21.06.2013
comment
Вы также можете сослаться на это. .in/блог/   -  person Shadow    schedule 21.06.2013


Ответы (2)


Я бы предложил создать отдельный файл фрагмента для каждой вкладки. Недавно я тоже это сделал, поэтому я обрисовал свой код ниже:

Файлы макетов

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 //добавьте соответствующие макеты вкладок, используя этот формат (не забудьте изменить строковые переменные)

<?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

MainActivity.java //обратите внимание, что в процессе .addTab я использовал только текст. Вы также можете добавить значки с помощью рисунков, которые вам нужно будет добавить в папку hdpi. Я также создал только три вкладки в этом примере.

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 //еще раз реплицируем желаемое количество вкладок

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;
    }
}

Убедитесь, что ваши файлы R.java и strings.xml правильно настроены, а затем ваши вкладки должны работать.

person Kylie Moden    schedule 21.06.2013
comment
В порядке. Я пойду проверю. Спасибо. Я скажу вам позже, если это сработает для меня :) - person imarban; 21.06.2013
comment
Можем ли мы перемещать вкладки вниз, как в iOS? - person Dharmendra; 03.10.2013
comment
@Dharmendra - я не верю, что вы можете, но более того, вы не должны пытаться, поскольку документы Android говорят о том, что они не хотят, чтобы разработчики имитировали пользовательский интерфейс iOS. - person Kylie Moden; 29.10.2013
comment
@KylieModen, хороший урок. Я пытаюсь изменить это, если один из моих фрагментов содержит EditText. Однако, как только я пытаюсь ввести EditText, фокус возвращается на вкладку (выделяет текущую вкладку). Какие-либо предложения? Спасибо - person Yehuda Gutstein; 31.01.2014
comment
@gotguts Я не совсем уверен - я знаю, что использовал EditText на одной из своих вкладок, поэтому я могу взглянуть на него и вернуться к вам, однако у меня, вероятно, не будет возможности сделать это до следующей недели. - person Kylie Moden; 03.02.2014
comment
Я пытаюсь сделать это в диалоговом окне «Фрагмент» вместо фрагментации, но получаю сообщение об ошибке «Не могу найти R.id.realTabContent». Что я должен указать в качестве контейнера в tabHost.setup? - person SohailAziz; 26.02.2014
comment
Понятно, вам нужно использовать getChildFragmentManager() в tabhost.setup в случае фрагмента. - person SohailAziz; 27.02.2014
comment
Привет, Моден, я не хочу обновляться, когда снова нажимаю те же вкладки. возможно ли это во фрагменттабхосте. как обычный табхост. ты можешь помочь мне с этим ..Спасибо - person harikrishnan; 21.05.2014
comment
Пожалуйста, объясните причину использования tabcontent и realtabcontent, то есть двух макетов фреймов. - person TechSpellBound; 07.04.2015
comment
Как установить тег для Tab1Fragment, Tab2Fragment и Tab3Fragment, чтобы позже я мог найти эти фрагменты, используя их тег? - person techierishi; 07.05.2015
comment
Если вы пропустите все дочерние теги в activity_main.xml, хост фрагмента создаст их для вас, однако вам придется создать и использовать R.id.realtabcontent, пытаясь использовать android.R.id.tabcontent, потерпит неудачу. - person Arran Ubels; 03.09.2015
comment
как мне найти фрагмент, я имею в виду, если он добавлен диспетчером фрагментов, я найду его с помощью findFragmentByTag(), аналогично, как я могу найти фрагмент из tabhost? - person kashyap jimuliya; 09.02.2017

TabHost не сохраняет фрагмент состояния. Так зачем использовать TabHost?

Поэтому используйте ViewPager с TabLayout.

Плюсы Viewpager по сравнению с Tabhost:

  • ViewPager сохраняет состояния фрагментов. Средний фрагмент не будет воссоздан снова при переключении.
  • Встроенная функция прокрутки, которая делает работу пользователя более плавной.
  • Меньше потребления ЦП, потому что Tabhost снова и снова воссоздает фрагмент/активность при переключении Tab.

Почувствуйте разницу :

Использование Tablayout + ViewPager (поддерживает пролистывание, сохраняет состояния фрагментов

Вкладка + ViewPager

Использование TabHost (не поддерживает пролистывание, не сохраняет состояния)

TabHost

Небольшой код для 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

<?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>

Примечание. Если вы еще не используете AndroidX, вам необходимо изменить следующее в макете.

  • Изменить com.google.android.material.tabs.TabLayout на android.support.design.widget.TabLayout
  • Шань с androidx.viewpager.widget.ViewPager по android.support.v4.view.ViewPager

Но я настоятельно рекомендую перейти на AndroidX, см. @this answer, чтобы понять, почему.

И это общее ViewPagerAdapter для всех ваших Viewpager в приложении.

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);
    }
}

Важные ссылки по теме

person Khemraj Sharma    schedule 16.11.2018