(ActionBar) Tabs + Pager + detail Fragments inside ViewPager container

前端 未结 4 1458
死守一世寂寞
死守一世寂寞 2020-12-23 18:31

For ActionBarSherlock I would like to have (Action Bar) Tabs + Pager. I use Fragments inside that pager container. I already got the examples of http://actionbarsherlock.com

相关标签:
4条回答
  • 2020-12-23 18:46

    I found the other good example of the same implementation in hear... https://github.com/UweTrottmann/SeriesGuide

    In this example under package com.battlelancer.seriesguide.ui

    you can find UpcomingRecentActivity.java, and UpcomingFragment.java

    and layout upcoming_multipan.xml

    this example works for me...

    I got one problem while adding different content for detail-fragment the different tabs, it gives me class-cast-exception

    so i implemented a common detalFragment class and created separate layout in onCreateView method

    but the only one problem i found is layout is not changing on tab switched, may be need to do it by implementing some listener

    I'll tell you when i found the answer.

    0 讨论(0)
  • 2020-12-23 18:50

    I still did not find a possibility to have a Pager container where fragments should be loaded in and also keep the (ActionBar) Tabs. I have however found a really dirty solution to acomplish this, with starting intens (Main Activity with the Tabs) and finishing the previous ones when the backbutton doesn't need it anymore.

    I adapted the code from ABS: Support Demos - Tabs and Pager. But again it's really dirty:

    LoaderCursorSupport.CursorLoaderListFragment under Tab2

    @Override public void onListItemClick(ListView l, View v, int position, long id) {
            Intent intent = new Intent();
            intent.setClass(getActivity(), ActionBarTabsPager.class);
            intent.putExtra("index", position);
            intent.putExtra("fragment", "details");
            intent.putExtra("tab", 1);
            ActionBarTabsPager.mPreviousActivity = getActivity();
    
            startActivity(intent);
    

    ActionBarTabsPager (Main Activity with Tabs)

    public class ActionBarTabsPager extends FragmentActivity {
    ViewPager mViewPager;
    TabsAdapter mTabsAdapter;
    static Activity mPreviousActivity;
    static Activity mActivity;
    static int mTabPosition = -1;
    static Boolean mTabRefreshed = false;
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
    
        setContentView(R.layout.actionbar_tabs_pager);
        getSupportActionBar().setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
    
        ActionBar.Tab tab1 = getSupportActionBar().newTab().setText("Tab 1");
        ActionBar.Tab tab2 = getSupportActionBar().newTab().setText("Tab 2");
        ActionBar.Tab tab3 = getSupportActionBar().newTab().setText("Tab 3");
        ActionBar.Tab tab4 = getSupportActionBar().newTab().setText("Tab 4");
        String fragment = "";
        try {
            Bundle bundle = this.getIntent().getExtras();
            fragment = bundle.getString("fragment");
            mTabPosition = bundle.getInt("tab");
        } catch (Exception ex) {
        }
    
        mViewPager = (ViewPager) findViewById(R.id.pager);
        mTabsAdapter = new TabsAdapter(this, getSupportActionBar(), mViewPager);
        mTabsAdapter.addTab(tab1, FragmentStackSupport.CountingFragment.class);
        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.ECLAIR) {
            mTabsAdapter.addTab(tab2, FragmentStackSupport.CountingFragment.class);
            mTabsAdapter.addTab(tab3, FragmentStackSupport.CountingFragment.class);
            mTabsAdapter.addTab(tab4, FragmentStackSupport.CountingFragment.class);
        } else {
            if (!fragment.contains("details")) {
                mTabsAdapter.addTab(tab2, LoaderCursorSupport.CursorLoaderListFragment.class);
            } else {
                mTabsAdapter.addTab(tab2, ExampleFragment.class);
            }
            mTabsAdapter.addTab(tab3, LoaderCustomSupport.AppListFragment.class);
            mTabsAdapter.addTab(tab4, LoaderThrottleSupport.ThrottledLoaderListFragment.class);
        }
    
        if (savedInstanceState != null) {
            getSupportActionBar().setSelectedNavigationItem(savedInstanceState.getInt("index"));
        }
    
        if (mTabPosition > -1) {
            mTabsAdapter.setPrimaryItem(mTabPosition);
    
            mActivity = this;
    
        }
    }
    

    Inside this Class there's a TabsAdapter

    public static class TabsAdapter extends FragmentPagerAdapter implements ViewPager.OnPageChangeListener, ActionBar.TabListener {
        private final Context mContext;
        private final ActionBar mActionBar;
        private final ViewPager mViewPager;
        private final ArrayList<String> mTabs = new ArrayList<String>();
    
    
        @Override
        public void onTabSelected(Tab tab, FragmentTransaction ft) {
            if (mTabPosition > -1 && mTabRefreshed) {
                int tabPosition = tab.getPosition();
                if (mTabPosition != tabPosition) {
                    if (mPreviousActivity != null) {
                        mPreviousActivity.finish();
                        mTabRefreshed = false;
                        mPreviousActivity = null;
                        mTabPosition = -1;
                        Intent intent = new Intent();
                        intent.setClass(mContext, ActionBarTabsPager.class);
                        intent.putExtra("fragment", "home");
                        intent.putExtra("tab", tabPosition);
                        mActivity.startActivity(intent);
                        mActivity.finish();
    
                    }
                }
            }
            mViewPager.setCurrentItem(tab.getPosition());
        }
    

    Can this be done simpler? Or should I just give up on having Tabs together with fragment history? This was done before Android 3.0 with ActivityGroups and Activities, but it seems this can't be done with fragments.

    0 讨论(0)
  • 2020-12-23 18:54

    Here is my solution for the (Tabs + Fragment + ViewPager) it is works for me as i wanted, hope that works for you as well

    here is the xml file

     <LinearLayout
            android:id="@+id/linearLayout"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:orientation="horizontal" >
    
            <android.support.v4.view.ViewPager
                android:id="@+id/pager"
                android:layout_width="0dip"
                android:layout_height="match_parent"
                android:layout_weight="5" />
    
            <FrameLayout
                android:id="@+id/fragment_details"
                android:layout_width="0px"
                android:layout_height="match_parent"
                android:layout_weight="4.3" />
        </LinearLayout>
    

    here is the code for MainActivity.java I'll post relevant code only so you'll have to manage it

    public class MainActivity extends FragmentActivity implements
            DialogInterface.OnDismissListener, TabDataResponder {
    
        /** Called when the activity is first created. */
        @Override
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.main);
    
            getSupportActionBar().setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
    
            artistTab = getSupportActionBar().newTab().setText(
                    R.string.tab_name_artist);
            albumTab = getSupportActionBar().newTab().setText(
                    R.string.tab_name_album);
            songTab = getSupportActionBar().newTab().setText(
                    R.string.tab_name_songs);
    
            map = new HashMap<String, Integer>();
            mViewPager = (ViewPager) findViewById(R.id.pager);
            FrameLayout deatil = (FrameLayout) findViewById(R.id.fragment_details);
            mDualPane = (deatil != null) && (deatil.getVisibility() == View.VISIBLE);
            mTabsAdapter = new TabsAdapter(this, getSupportActionBar(), mViewPager);
    
            if (savedInstanceState != null) {
                flag = true;
                index = savedInstanceState.getInt("index");
            }
    
            setUpTabView();
    
        }
    
    
        @Override
        protected void onSaveInstanceState(Bundle outState) {
            super.onSaveInstanceState(outState);
            outState.putInt("index", getSupportActionBar()
                    .getSelectedNavigationIndex());
        }
    
        private void setUpTabView() {
            mTabsAdapter.addTab(artistTab, ArtistFragment.class, null);
            mTabsAdapter.addTab(albumTab, AlbumFragment.class, null);
            mTabsAdapter.addTab(songTab, SongFragment.class, null);
            getSupportActionBar().setSelectedNavigationItem(index);
        }
    
        public static class TabsAdapter extends FragmentPagerAdapter implements
                ViewPager.OnPageChangeListener, ActionBar.TabListener {
    
            private FragmentActivity mContext;
            private ActionBar mActionBar;
            private final ViewPager mViewPager;
    
            private final ArrayList<String> mTabs = new ArrayList<String>();
            private TabDataResponder responder;
    
            public TabsAdapter(FragmentActivity activity, ActionBar actionBar,
                    ViewPager pager) {
    
                super(activity.getSupportFragmentManager());
                mContext = activity;
                mActionBar = actionBar;
                mViewPager = pager;
    
                // TabDataResponder is an interface which is implemented in MainActivity
                // You can find implementation @ the last
    
                responder = (TabDataResponder) activity;
                mViewPager.setAdapter(this);
                mViewPager.setOnPageChangeListener(this);
    
                //I have used map to save state of the fragment
                map.put(SongFragment.TYPE_FRAGMENT.trim(), 0);
                map.put(AlbumFragment.TYPE_FRAGMENT.trim(), 0);
                map.put(ArtistFragment.TYPE_FRAGMENT.trim(), 0);
            }
    
            public void addTab(ActionBar.Tab tab, Class<?> clss, Bundle args) {
                mTabs.add(clss.getName());
                // mArgs.add(args);
                mActionBar.addTab(tab.setTabListener(this));
                notifyDataSetChanged();
            }
    
            @Override
            public int getCount() {
                return mTabs.size();
            }
    
            @Override
            public Fragment getItem(int position) {
                return Fragment
                        .instantiate(mContext, mTabs.get(position), /*
                                                                     * mArgs.get(
                                                                     * position)
                                                                     */null);
            }
    
            @Override
            public void onPageScrolled(int position, float positionOffset,
                    int positionOffsetPixels) {
            }
    
            @Override
            public void onPageSelected(int position) {
                Log.i(TAG, "PageSelected....");
                mActionBar.setSelectedNavigationItem(position);
            }
    
            @Override
            public void onPageScrollStateChanged(int state) {
                Log.i(TAG, "ScrollSateChanged....");
            }
    
            @Override
            public void onTabReselected(Tab tab, FragmentTransaction ft) {
            }
    
            @Override
            public void onTabSelected(Tab tab, FragmentTransaction ft) {
                mViewPager.setCurrentItem(tab.getPosition());
                String a = null;
                if (mDualPane) {
                    a = mTabs.get(tab.getPosition());
                    responder.loadData(a, map.get(a));
                }
            }
    
            @Override
            public void onTabUnselected(Tab tab, FragmentTransaction ft) {
                Log.i(TAG, "Tab is released now....");
            }
        }
    
        @Override
        public void onDismiss(DialogInterface dialog) {
            setUpTabView();
    
        }
    //This interface must be call from fragment class 
    //@ the time of event you want to show detail 
    // pass the class name in the type argument using class.getName() method
        @Override
        public void loadData(String type, int index) {
            DetailFragment viewer = (DetailFragment) getSupportFragmentManager()
                    .findFragmentById(R.id.fragment_details);
            if (mDualPane) {
                if (viewer == null || viewer.getShownIndex() != index
                        || viewer.getTypeFragment() != type) {
    
                    DetailFragment df = DetailFragment.newInstance(index, type);
                    getSupportFragmentManager()
                            .beginTransaction()
                            .replace(R.id.fragment_details, df)
                            .setTransition(
                                    FragmentTransaction.TRANSIT_FRAGMENT_FADE)
                            .commit();
                    map.put(type.trim(), index);
    
                }
    
            } else {
                Intent intent = new Intent();
                intent.setClass(MainActivity.this, DetailActivity.class);
                intent.putExtra("index", index);
                intent.putExtra("type", type);
                startActivity(intent);
            }
        }
    }
    

    and here is how i deal with detail fragment not very efficient but kind of working

    public class DetailFragment extends Fragment{
    
        public static DetailFragment newInstance(int index, String  TYPE_FRAGMENT) {
            DetailFragment f = new DetailFragment();
    
            // Supply index input as an argument.
            Bundle args = new Bundle();
            args.putInt("index", index);
            args.putString("type", TYPE_FRAGMENT);
            f.setArguments(args);
    
            return f;
        }
    
    
    
        public int getShownIndex() {
            return getArguments().getInt("index", 0);
        }
    
        public String getTypeFragment(){
            String a = getArguments().getString("type");
            return a;
        }
    
    
        @Override
        public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    
            //template is blank layout
            View view =  inflater.inflate(R.layout.template, container, false);
            if(getTypeFragment().equals(ArtistFragment.TYPE_FRAGMENT)){
                view = null;
                view = inflater.inflate(R.layout.artist_details, container, false);
                //....
    
            }
            else if(getTypeFragment().equals(AlbumFragment.TYPE_FRAGMENT)){
    
                //do's for album fragment
            }
            else if(getTypeFragment().equals(SongFragment.TYPE_FRAGMENT)){
                //do's for song fragment
            }
            return view;
        }
    
    }
    

    do not save the state of tab in their individual fragment it will conflict, we are already doing it here

    0 讨论(0)
  • 2020-12-23 19:06

    EDIT:
    Cheered too soon. Now the details_container is not a viewpager and I cannot use it to 'swipe tabs'.

    Found it! Just had to define two FrameLayouts, with in the first one the ViewPager and in the second the details fragments can be 'loaded'. This is done by adding fragments dynamically and replace them.

    First the two FrameLayouts:

    <?xml version="1.0" encoding="utf-8"?>
    <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:fadingEdge="none" >
        <FrameLayout
            android:id="@+id/main_container"
            android:layout_width="match_parent"
            android:layout_height="match_parent" >
            <android.support.v4.view.ViewPager
                android:id="@+id/pager"
                android:layout_width="fill_parent"
                android:layout_height="fill_parent" />
        </FrameLayout>
        <FrameLayout
            android:id="@+id/details_container"
            android:layout_width="match_parent"
            android:layout_height="match_parent" />
    </RelativeLayout>
    

    Then replace a fragment dynamically:

    // Create new fragment and transaction
    Fragment detailsFragment = new ExampleFragment();
    FragmentTransaction transaction = getFragmentManager().beginTransaction();
    
    // Replace whatever is in the fragment container view with this fragment
    // and add the transaction to the back stack
    transaction.replace(R.id.details_container, detailsFragment);
    transaction.addToBackStack(null);
    
    // Commit the transaction
    transaction.commit();
    

    Very simple and I don't understand why it took me hours to figure this out..

    0 讨论(0)
提交回复
热议问题