滑块菜单片段中的可交换选项卡

Posted

技术标签:

【中文标题】滑块菜单片段中的可交换选项卡【英文标题】:Swapable tabs in Slider Menu fragment 【发布时间】:2014-07-03 22:00:24 【问题描述】:

我通过引用this tutorial 实现了导航抽屉,现在我想做的是在片段内显示滑动选项卡。即,当我单击导航抽屉中的项目时,假设第一个项目,它应该显示该项目的滑动选项卡。(我的列表视图中有 6 个片段。(同样:- A,B,C,D,E, F). 我的 A 片段上需要 3 个可交换的标签。)

如果 item1 是事件,当我点击它时,它应该显示滑动标签。

但我面临以下问题:-

    如何在片段中实现视图分页器?

    片段可能会扩展片段。

    当 A 片段扩展 FragmentActivity 时,在我的主要活动中,代码显示错误“类型不匹配”,无法从 A 片段转换为片段。

这是我的 Deep.java 文件

    package com.amar.demo;

import info.androidhive.slidingmenu.adapter.NavDrawerListAdapter;
import info.androidhive.slidingmenu.model.NavDrawerItem;

import java.util.ArrayList;

import android.app.Activity;
import android.app.Fragment;
import android.app.FragmentManager;
import android.content.res.Configuration;
import android.content.res.TypedArray;
import android.os.Bundle;
import android.support.v4.app.ActionBarDrawerToggle;
import android.support.v4.widget.DrawerLayout;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ListView;

public class Deep extends Activity 
    private DrawerLayout mDrawerLayout;
    private ListView mDrawerList;
    private ActionBarDrawerToggle mDrawerToggle;

    // nav drawer title
    private CharSequence mDrawerTitle;

    // used to store app title
    private CharSequence mTitle;

    // slide menu items
    private String[] navMenuTitles;
    private TypedArray navMenuIcons;

    private ArrayList<NavDrawerItem> navDrawerItems;
    private NavDrawerListAdapter adapter;

    @Override
    protected void onCreate(Bundle savedInstanceState) 
        super.onCreate(savedInstanceState);
        setContentView(R.layout.deep);

        mTitle = mDrawerTitle = getTitle();

        // load slide menu items
        navMenuTitles = getResources().getStringArray(R.array.nav_drawer_items);

        // nav drawer icons from resources
        navMenuIcons = getResources()
                .obtainTypedArray(R.array.nav_drawer_icons);

        mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
        mDrawerList = (ListView) findViewById(R.id.list_slidermenu);

        navDrawerItems = new ArrayList<NavDrawerItem>();

        // adding nav drawer items to array
        // Home
        navDrawerItems.add(new NavDrawerItem(navMenuTitles[0], navMenuIcons
                .getResourceId(0, -1)));
        // Find People
        navDrawerItems.add(new NavDrawerItem(navMenuTitles[1], navMenuIcons
                .getResourceId(1, -1)));
        // Photos
        navDrawerItems.add(new NavDrawerItem(navMenuTitles[2], navMenuIcons
                .getResourceId(2, -1)));
        // Communities, Will add a counter here
        navDrawerItems.add(new NavDrawerItem(navMenuTitles[3], navMenuIcons
                .getResourceId(3, -1), true, "22"));
        // Pages
        navDrawerItems.add(new NavDrawerItem(navMenuTitles[4], navMenuIcons
                .getResourceId(4, -1)));
        // What's hot, We will add a counter here
        navDrawerItems.add(new NavDrawerItem(navMenuTitles[5], navMenuIcons
                .getResourceId(5, -1), true, "50+"));

        // Recycle the typed array
        navMenuIcons.recycle();

        mDrawerList.setOnItemClickListener(new SlideMenuClickListener());

        // setting the nav drawer list adapter
        adapter = new NavDrawerListAdapter(getApplicationContext(),
                navDrawerItems);
        mDrawerList.setAdapter(adapter);

        // enabling action bar app icon and behaving it as toggle button
        getActionBar().setDisplayHomeAsUpEnabled(true);
        getActionBar().setHomeButtonEnabled(true);

        mDrawerToggle = new ActionBarDrawerToggle(this, mDrawerLayout,
                R.drawable.ic_drawer, // nav menu toggle icon
                R.string.app_name, // nav drawer open - description for
                                    // accessibility
                R.string.app_name // nav drawer close - description for
                                    // accessibility
        ) 
            public void onDrawerClosed(View view) 
                getActionBar().setTitle(mTitle);
                // calling onPrepareOptionsMenu() to show action bar icons
                invalidateOptionsMenu();
            

            public void onDrawerOpened(View drawerView) 
                getActionBar().setTitle(mDrawerTitle);
                // calling onPrepareOptionsMenu() to hide action bar icons
                invalidateOptionsMenu();
            
        ;
        mDrawerLayout.setDrawerListener(mDrawerToggle);

        if (savedInstanceState == null) 
            // on first time display view for first nav item
            displayView(0);
        
    

    /**
     * Slide menu item click listener
     * */
    private class SlideMenuClickListener implements
            ListView.OnItemClickListener 
        @Override
        public void onItemClick(AdapterView<?> parent, View view, int position,
                long id) 
            // display view for selected nav drawer item
            displayView(position);
        
    

    @Override
    public boolean onCreateOptionsMenu(Menu menu) 
        getMenuInflater().inflate(R.menu.testmenu, menu);
        return true;
    

    @Override
    public boolean onOptionsItemSelected(MenuItem item) 
        // toggle nav drawer on selecting action bar app icon/title
        if (mDrawerToggle.onOptionsItemSelected(item)) 
            return true;
        
        // Handle action bar actions click
        switch (item.getItemId()) 
        case R.id.a_More:
            return true;
        default:
            return super.onOptionsItemSelected(item);
        
    

    /* *
     * Called when invalidateOptionsMenu() is triggered
     */
    @Override
    public boolean onPrepareOptionsMenu(Menu menu) 
        // if nav drawer is opened, hide the action items
        boolean drawerOpen = mDrawerLayout.isDrawerOpen(mDrawerList);
        menu.findItem(R.id.a_More).setVisible(!drawerOpen);
        return super.onPrepareOptionsMenu(menu);
    

    /**
     * Diplaying fragment view for selected nav drawer list item
     * */
    private void displayView(int position) 
        // update the main content by replacing fragments
        Fragment fragment = null;
        switch (position) 
        case 0:
            fragment = new HomeFragment();
            break;
        case 1:
            fragment = new FindPeopleFragment();
            break;
        case 2:
            fragment = new PhotosFragment();
            break;
        case 3:
            fragment = new CommunityFragment();
            break;
        case 4:
            fragment = new PagesFragment();
            break;
        case 5:
            fragment = new WhatsHotFragment();
            break;

        default:
            break;
        

        if (fragment != null) 
            FragmentManager fragmentManager = getFragmentManager();
            // fragmentManager.beginTransaction()
            // .replace(R.id.frame_container, fragment).commit();

            // update selected item and title, then close the drawer
            mDrawerList.setItemChecked(position, true);
            mDrawerList.setSelection(position);
            setTitle(navMenuTitles[position]);
            mDrawerLayout.closeDrawer(mDrawerList);
         else 
            // error in creating fragment
            Log.e("MainActivity", "Error in creating fragment");
        
    

    @Override
    public void setTitle(CharSequence title) 
        mTitle = title;
        getActionBar().setTitle(mTitle);
    

    /**
     * When using the ActionBarDrawerToggle, you must call it during
     * onPostCreate() and onConfigurationChanged()...
     */

    @Override
    protected void onPostCreate(Bundle savedInstanceState) 
        super.onPostCreate(savedInstanceState);
        // Sync the toggle state after onRestoreInstanceState has occurred.
        mDrawerToggle.syncState();
    

    @Override
    public void onConfigurationChanged(Configuration newConfig) 
        super.onConfigurationChanged(newConfig);
        // Pass any configuration change to the drawer toggls
        mDrawerToggle.onConfigurationChanged(newConfig);
    


在此代码中,我在案例 0 中遇到问题。

这是我的 HomeFragment 代码:- 包 com.amar.demo;

import android.app.ActionBar;
import android.app.ActionBar.Tab;
import android.app.FragmentTransaction;
import android.os.Bundle;
import android.support.v4.app.FragmentActivity;
import android.support.v4.view.ViewPager;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

import com.amar.demo.adapter.TabsPagerAdapter;

public class HomeFragment extends FragmentActivity implements
        ActionBar.TabListener 

    private ViewPager viewPager;
    private TabsPagerAdapter mAdapter;
    private ActionBar actionBar;
    // Tab titles
    private String[] tabs =  "My Restaurant", "Offers", "Search & Book",
            "News & Updates" ;

    public HomeFragment() 
    

    public View onCreateView(LayoutInflater inflater, ViewGroup container,
            Bundle savedInstanceState) 

        View rootView = inflater.inflate(R.layout.fragment_home, container,
                false);
        // code of tabes
        viewPager = (ViewPager) rootView.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) 
            
        );
        return rootView;
    

    @Override
    public void onTabSelected(Tab tab, FragmentTransaction ft) 
        // TODO Auto-generated method stub

    

    @Override
    public void onTabUnselected(Tab tab, FragmentTransaction ft) 
        // TODO Auto-generated method stub

    

    @Override
    public void onTabReselected(Tab tab, FragmentTransaction ft) 
        // TODO Auto-generated method stub

    

这是我的 deep.xml 代码:-

    <!-- Framelayout to display Fragments -->

    <FrameLayout
        android:id="@+id/frame_container"
        android:layout_
        android:layout_ />

    <!-- Listview to display slider menu -->

    <ListView
        android:id="@+id/list_slidermenu"
        android:layout_
        android:layout_
        android:layout_gravity="start"
        android:background="@color/list_background"
        android:choiceMode="singleChoice"
        android:divider="@color/list_divider"
        android:dividerHeight="1dp"
        android:listSelector="@drawable/list_selector" />

</android.support.v4.widget.DrawerLayout>

这是我的 homefragment.xml 代码:-

<android.support.v4.view.ViewPager xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/pager"
android:layout_
android:layout_>
</android.support.v4.view.ViewPager>

【问题讨论】:

是的..我们可以在片段中实现视图寻呼机... 但是..如何在片段中实现视图寻呼机...?? @Amardeep 看到我的答案,我已经用新代码更新了答案。 不确定您需要多长时间才能支持旧版本的 Android,但子类 FragmentActivity 早已被弃用,现在只需要子类普通 Activity(不确定版本截止)。 【参考方案1】:

您必须使用包含 ViewPager 的自定义布局创建片段。

按照这些步骤,它将指导整个过程。

1。创建布局以表示 ViewPager,将其命名为 fragment_main.xml

<TabHost
    android:id="@android:id/tabhost"
    android:layout_
    android:layout_>

    <LinearLayout
        android:orientation="vertical"
        android:layout_
        android:layout_>

        <TabWidget
            android:id="@android:id/tabs"
            android:orientation="horizontal"
            android:layout_
            android:layout_
            android:layout_weight="0"/>

        <FrameLayout
            android:id="@android:id/tabcontent"
            android:layout_
            android:layout_
            android:layout_weight="0"/>

        <android.support.v4.view.ViewPager
            android:id="@+id/pager"
            android:layout_
            android:layout_
            android:layout_weight="1"/>

    </LinearLayout>
</TabHost>

2。创建一个片段来保存上面 XML 上声明的 ViewPager,将其命名为 MyFragment.java

如您所见,我们在上面的 XML 中声明了 TabHostViewPager 和其他元素。同样在这个片段中,我们膨胀了之前创建的布局,并使用TabAdapter 来处理所有选项卡。

import android.content.Context;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.FragmentPagerAdapter;
import android.support.v4.view.ViewPager;
import android.support.v4.app.Fragment;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TabHost;
import android.widget.TabWidget;

import java.util.ArrayList;

public static class MyFragment extends Fragment


    private TabHost mTabHost;
    private ViewPager mViewPager;
    private TabsAdapter mTabsAdapter;

    public MyFragment() 
    

    @Override
    public void onCreate(Bundle instance)
    
        super.onCreate(instance);

    

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
            Bundle savedInstanceState) 
        View v = inflater.inflate(R.layout.fragment_main, container, false);

        mTabHost = (TabHost) v.findViewById(android.R.id.tabhost);
        mTabHost.setup();

        mViewPager = (ViewPager) v.findViewById(R.id.pager);
        mTabsAdapter = new TabsAdapter(getActivity(), mTabHost, mViewPager);

        // Here we load the content for each tab. 
        mTabsAdapter.addTab(mTabHost.newTabSpec("one").setIndicator("One"), PageOneFragment.class, null);
        mTabsAdapter.addTab(mTabHost.newTabSpec("two").setIndicator("Two"), PageTwoFragment.class, null);

        return v;
    

    public static class TabsAdapter extends FragmentPagerAdapter implements TabHost.OnTabChangeListener, ViewPager.OnPageChangeListener
    
        private final Context mContext;
        private final TabHost mTabHost;
        private final ViewPager mViewPager;
        private final ArrayList<TabInfo> mTabs = new ArrayList<TabInfo>();

        static final class TabInfo
        
            private final String tag;
            private final Class<?> clss;
            private final Bundle args;

            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;
            

            public View createTabContent(String tag)
            
                View v = new View(mContext);
                v.setMinimumWidth(0);
                v.setMinimumHeight(0);
                return v;
            
        

        public TabsAdapter(FragmentActivity activity, TabHost tabHost, ViewPager pager)
        
            super(activity.getSupportFragmentManager());
            mContext = activity;
            mTabHost = tabHost;
            mViewPager = pager;
            mTabHost.setOnTabChangedListener(this);
            mViewPager.setAdapter(this);
            mViewPager.setOnPageChangeListener(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);
            mTabs.add(info);
            mTabHost.addTab(tabSpec);
            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);

        

        public void onTabChanged(String tabId)
        
            int position = mTabHost.getCurrentTab();
            mViewPager.setCurrentItem(position);
        

        public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels)
        
        

        public void onPageSelected(int position)
        
            // Unfortunately when TabHost changes the current tab, it kindly
            // also takes care of putting focus on it when not in touch mode.
            // The jerk.
            // This hack tries to prevent this from pulling focus out of our
            // ViewPager.
            TabWidget widget = mTabHost.getTabWidget();
            int oldFocusability = widget.getDescendantFocusability();
            widget.setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS);
            mTabHost.setCurrentTab(position);
            widget.setDescendantFocusability(oldFocusability);
        

        public void onPageScrollStateChanged(int state)
        
        
    

如您所见,每个选项卡调用一个特定的片段。这些片段代表每个选项卡的内容。所以让我们创建它们,它们非常简单,并且只包含一个TextView

3。为第一个选项卡内容创建一个片段,将其命名为 PageOneFragment.java

此片段将保存第一个选项卡的内容。您可以在此片段中放置任何内容,它将与其他片段和其他选项卡分开。

这里我们在onCreateView 方法中扩充了xml 布局pageone_fragment.xml。我们将在下一步中创建这个 xml 布局。

import android.app.Activity;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

public class PageOneFragment extends Fragment

    @Override
    public void onCreate(Bundle savedInstanceState)
    
        super.onCreate(savedInstanceState);
    

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
    
        return inflater.inflate(R.layout.pageone_fragment, container, false);
    

    @Override
    public void onActivityCreated(Bundle savedInstanceState)
    
        super.onActivityCreated(savedInstanceState);
    

    @Override
    public void onAttach(Activity activity)
    
        super.onAttach(activity);
    

    @Override
    public void onStart()
    
        super.onStart();
    

    @Override
    public void onResume()
    
        super.onResume();
    

如前所述,我们必须为这个片段创建布局。

4。为 PageOneFragment 创建布局,将其命名为 pageone_fragment.xml

这只是一个简单的布局,用TextView 表示选项卡的内容。你可以在这个布局中构建任何你想要的东西,它将与其他片段和选项卡分开。

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/first_fragment"
    android:layout_
    android:layout_
    android:orientation="vertical"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:background="#ff4063ff">

    <TextView
        android:layout_
        android:layout_
        android:textAppearance="?android:attr/textAppearanceMedium"
        android:text="First Page"
        android:textColor="#FFFFFF"
        android:textStyle="bold"
        android:id="@+id/firstFragmentTextView"
        android:layout_gravity="center_horizontal|top" />

</LinearLayout>

因为我们有两个选项卡,所以我们有两个片段,每个选项卡一个。所以让我们为第二个标签内容创建第二个片段。

5。为第二个标签内容创建片段,将其命名为 PageTwoFragment.java

如您所见,我们在 onCreateView 方法上扩展了不同的布局,称为 pagetwo_fragment.xml。我们将在下一步创建它。

import android.app.Activity;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

public class PageTwoFragment extends Fragment

    @Override
    public void onCreate(Bundle savedInstanceState)
    
        super.onCreate(savedInstanceState);
    

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
    
        return inflater.inflate(R.layout.pagetwo_fragment, container, false);
    

    @Override
    public void onActivityCreated(Bundle savedInstanceState)
    
        super.onActivityCreated(savedInstanceState);
    

    @Override
    public void onAttach(Activity activity)
    
        super.onAttach(activity);
    

    @Override
    public void onStart()
    
        super.onStart();
    

    @Override
    public void onResume()
    
        super.onResume();
    

正如我们之前为 PageOneFragment 所做的那样,让我们​​也为第二个片段创建布局,正如我们之前提到的。

6。为 PageTwoFragment 创建布局,将其命名为 pagetwo_fragment.xml

这是一个简单的布局,只有一个TextView,只是为了表示内容。你可以在这里构建任何你想要的东西,它将与其他片段和选项卡分开。

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/first_fragment"
    android:layout_
    android:layout_
    android:orientation="vertical"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:background="#ff4063ff">

    <TextView
        android:layout_
        android:layout_
        android:textAppearance="?android:attr/textAppearanceMedium"
        android:text="Second Page"
        android:textColor="#FFFFFF"
        android:textStyle="bold"
        android:id="@+id/firstFragmentTextView"
        android:layout_gravity="center_horizontal|top" />

</LinearLayout>

7。从您的NavigationDrawer 调用此片段

如果你想从你的NavigationDrawer 调用这个片段,在你活动的displayView(int position) 方法的switch 语句中,你应该在你的case 语句之一中执行此操作,例如。

case 0:
    fragment = new MyFragment();
    break;

这是最终结果

ViewPager 在片段上运行,有两个选项卡,每个选项卡都包含一个具有独特内容的独特片段。

就是这样。

希望对你有所帮助。

【讨论】:

这是一个建议...我希望..,您知道在哪里写答案以及在哪里写建议 @GVSharma 我正在更新我的答案。 我在第 7 步中发现了错误“类型不匹配:无法从 HomeFragment 转换为 Fragment” private void displayView(int position) // 通过替换片段来更新主要内容 Fragment fragment = null; switch (position) case 0: fragment = new HomeFragment();休息; 不。你必须打电话给MyFragment,而不是HomeFragment。您创建的片段类的名称是什么?【参考方案2】:

关于第 7 步“类型不匹配”中的错误

制作:

replace **import android.app.Fragment** to **import android.support.v4.app.Fragment**

万一:

android.support.v4.app.FragmentManager fragmentManager = getSupportFragmentManager();
fragmentManager.beginTransaction().replace(R.id.frame_container, fragment).commit();

【讨论】:

【参考方案3】:
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);
            mTabs.add(info);
            mTabHost.addTab(tabSpec);
            notifyDataSetChanged();
        

mTabs 变量的声明位置

谢谢

【讨论】:

以上是关于滑块菜单片段中的可交换选项卡的主要内容,如果未能解决你的问题,请参考以下文章

选项卡单击应打开滑块菜单目标 c

扩展片段的类中的选项卡

根据范围输入显示/隐藏引导选项卡/药丸

如何在选项卡 Activity 的片段中使用 onCreateOptionsMenu? (夏洛克动作条)

使用片段在可Swipable选项卡中加载首选项设置

选项卡内的片段