【问题标题】:Actionbarsherlock + tabs + multi fragments?Actionbarsherlock + 选项卡 + 多片段?
【发布时间】:2024-01-15 07:35:02
【问题描述】:

我已经非常努力地让 actionbarsherlock + 选项卡 + 片段正常工作。

我只能让这个设置作为静态工作,我想创建这个像 android 市场应用程序(滑动移动)。

当您需要对包含多个片段的布局进行膨胀时,我会卡住。

在 Support4demos 中,我得到了 FragmentsTabsPager 作为示例。

【问题讨论】:

标签: android tabs android-fragments actionbarsherlock


【解决方案1】:

实际上,除了 ABS 库和支持库之外,我还设法让这个工作正常进行。这是我的代码:

public class ActionBarTabs extends SherlockFragmentActivity {
CustomViewPager mViewPager;
TabsAdapter mTabsAdapter;
TextView tabCenter;
TextView tabText;
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
            WindowManager.LayoutParams.FLAG_FULLSCREEN);

    mViewPager = new CustomViewPager(this);
    mViewPager.setId(R.id.pager);

    setContentView(mViewPager);
    ActionBar bar = getSupportActionBar();
    bar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
    bar.setDisplayOptions(0, ActionBar.DISPLAY_SHOW_TITLE);

    mTabsAdapter = new TabsAdapter(this, mViewPager);

    mTabsAdapter.addTab(bar.newTab().setText("Home"),
            ToolKitFragment.class, null);
    mTabsAdapter.addTab(bar.newTab().setText("FujiSan"),
            FujiFragment.class, null);
}

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(SherlockFragmentActivity activity, ViewPager pager) {
        super(activity.getSupportFragmentManager());
        mContext = activity;
        mActionBar = activity.getSupportActionBar();
        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) {
    }
}
}

您根据以下内容加载标签内容。

mTabsAdapter.addTab(bar.newTab().setText("Home"),
            YOURFRAGMENTHERE.class, null);  

这将为您提供可爱的“滑动标签”效果,正如您所指的那样,带有 ABS、支持库和片段。 ABS 确实使这与使用本机库几乎相同。实际上,我直接从 Google 的分页选项卡示例中复制了这段代码,并为 ABS 稍作修改。

希望这会有所帮助!

【讨论】:

  • 嗯,我可以理解,但我的问题是片段类,它总是崩溃,你能分享或给我一个方法如何创建这个包含 2 个或更多片段的片段类吗?谢谢
  • 太棒了。谢谢你。比 ABS 附带的示例要好得多,因为这为片段提供了可爱的新 ICS 选项卡,而 ABS 示例在使用片段时似乎恢复为旧选项卡
  • 感谢您的示例代码,这正是我想要的!虽然我似乎不明白有一件事,“CustomViewPager”有什么用?它似乎也适用于默认的 ViewPager。
  • 老兄.. 你真是个救命稻草。我一直在用头撞砖墙,试图让 ViewPager、ABS 和 Swipe 正常工作。谢谢!
  • 希望我能多谢你,我一直在使用 tabhost 实现一个较旧但非常相似的版本,导致 2.x 设备上的样式非常糟糕。这只是为我节省了很多时间。谢谢!
【解决方案2】:

您需要正确的库来实现您想要的。

基本上,您缺少的是 ViewPager 库。我的建议:

1. ActionbarSherlock

使用起来非常容易,我不会解释它。

2。 ViewPagerExtensions

您可以找到它here。下载 ZIP 文件并从中创建一个新项目。

我只能让这个设置作为静态工作,我想创建这个像 android 市场应用程序(swype 运动)。

从这个项目中实现com.astuetz.viewpager.extensions.SwipeyTabsView。有一些易于理解的例子。它完全符合您的要求。甚至还有其他选项卡样式可供选择(包括 ICS 附带的新人物选项卡)。此外,它的样式很容易与您的应用标识相匹配。

3. FragmentPagerAdapter

最后,来自支持库 (v4) 的那个类。

祝你好运,如果您需要更多帮助,请随时问我。


如果您使用我的建议,则无需在 FragmentPagerAdapter 中覆盖 instantiateItem。你只需要

  1. 为构造函数提供FragmentManager 并调用超级实现;
  2. 覆盖getCount 以返回寻呼机中的片段数,并且
  3. getItem您将使用它来返回片段以进行创建。

这是我这里的代码示例(一个完整的工作示例)。它是实现寻呼机的 Activity 的内部类:

static class MyFragmentPagerAdapter extends FragmentPagerAdapter {

    public MyFragmentPagerAdapter(FragmentManager fm) {
        super(fm);
    }

    @Override
    public int getCount() {
        return 2;
    }

    @Override
    public Fragment getItem(int position) {
        Fragment f;
        switch(position) {
        case 0:
            f= new ItemSalesDataFragment();
            break;
        case 1:
            f= new DepartmentChooserFragment();
            break;
        default:
            throw new IllegalArgumentException("not this many fragments: " + position);
        }
        return f;
    }
}

如您所见,此寻呼机处理两个“页面”,左侧显示销售数据。右边的允许用户选择哪个部门。这些在getItem 方法中返回。正确的片段(您可以使用已有的任何片段,无需修改)。

正如预期的那样,您可以通过以下方式将所有这些结合在一起:1) 创建一个实例化 MyFragmentPagerAdapter 的对象,以及 2) 将适配器设置为您的 ViewPager 对象,使其成为您刚刚实例化的类。如您所见,它的getItem 方法将为寻呼机“提供”您需要的所有片段。示例:

mFragmentPagerAdapter = new MyFragmentPagerAdapter(getSupportFragmentManager());
mViewPager.setAdapter(mFragmentPagerAdapter);

当然,还有其他事情要做,比如自己创建标签按钮并将所有这些加入到交叉通信中。我建议查看从 GitHub 下载的 ViewPagerExtensions ZIP 文件中提供的示例。这只是您评论中问题的答案。如您所见,使用这个库的代码并不多。

【讨论】:

  • 我推荐 ViewPagerExtensions 库,因为我喜欢生成的代码,还因为它提供了几种不同的选项卡类型供您选择,而且非常易于设置样式。如果您发现 Rymnel 方法的功能有限,请务必尝试一下。
  • 谢谢,真的很有帮助。现在我需要学习如何为内部的每个位置添加两个布局:Object instantiateItem(View container, int position),你有教程吗?谢谢
  • 更新了答案,展示了如何使用 FragmentpagerAdapter 返回所需片段的示例。如果您需要任何其他帮助,请随时提出。
  • 我想知道:我们如何将它与布局支持演示结合起来?因为我有一个标签,我也想在其中实现它......
  • @Jeroen,不确定你的意思。如果您更具体地了解我可以帮助您的布局。否则,您总是可以针对您的问题提出更一般的问题。
【解决方案3】:

很多示例在切换回之前选择的选项卡时通常会引发异常 (IllegalStateException: The specified child already has a parent. You must call removeView() on the child's parent first)。

我喜欢用FragmentStatePageAdapter 而不是普通的FragmentPageAdapter 来调整Google 的示例,这将为您替换片段并解决此错误。通常这会破坏它认为可以删除以节省空间的碎片;如果您想始终保留片段​​,请使用空块覆盖 destroyItem(ViewGroup, int, Object)

这是一个例子:

public class ActionBarTabs extends SherlockFragmentActivity {
    CustomViewPager mViewPager;
    TabsAdapter mTabsAdapter;
    TextView tabCenter;
    TextView tabText;
    ActionBar mActionBar;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
            WindowManager.LayoutParams.FLAG_FULLSCREEN);

        mViewPager = new CustomViewPager(this);
        mViewPager.setId(R.id.pager);

        setContentView(mViewPager);
        mActionBar = getSupportActionBar();
        mActionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
        mActionBar.setDisplayOptions(0, ActionBar.DISPLAY_SHOW_TITLE);

        mTabsAdapter = new TabsAdapter(this, mViewPager);

        mTabsAdapter.addTab(mActionBar.newTab().setText("Page 1"), 
            YOURFRAGMENT_A.class, null);
        mTabsAdapter.addTab(mActionBar.newTab().setText("Page 2"), 
            YOURFRAGMENT_B.class, null);
        mTabsAdapter.addTab(mActionBar.newTab().setText("Page 3"), 
            YOURFRAGMENT_C.class, null);
    }

    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(SherlockFragmentActivity activity, ViewPager pager) {
            super(activity.getSupportFragmentManager());
            mContext = activity;
            mActionBar = activity.getSupportActionBar();
            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) {
        }
    }
}

与 ABS 配合良好,实施起来相对简单。

【讨论】: