Search code examples
androidswipeandroid-tabsfragmentpageradapter

FragmentPageAdaptor - swiping views inside tab content


I have created a screen which has some read only data fields on it and at the bottom has a horizontal set of tabs.

Each tab has a fragment representing the tab content and is backed up by an array of data objects for instance one of the tabs is previous addresses, of which there can be 0 to many.

I want the tab content fragment to be swipeable such that it will initally show the most recent previous address and a swipe to the left will pull in the next from an array initially, continued swiping will navigate through the addresses in either direction if appropriate.

I have been looking FragmentPageAdapter but I dont want anything in the title bar and I also want to use the same fragment for each swipe as the only thing that changes is the data that is displayed, the layout would be the same everytime.

I do still want the swipe action that makes it look like the page swiped from one page to another though.

Is this the best way forward for this and are there better options? There are currently 5 tabs and 3 of those tabs will have swipe-able content which will show more data but the view itself will not change.

I thought I would edit this and add some code so it might be easier to see what I want to achieve:

I have a fragment which repsents a vertical tab that was clicked and inside that fragment is a set of horizontal tabs:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="horizontal"
    android:layout_height="wrap_content"
    android:layout_width="match_parent"
    android:layout_marginTop="5dp">

    <TableLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:stretchColumns="1"
        android:id="@+id/name_table">
    </TableLayout>
</LinearLayout>

<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"
    android:background="@color/white"
    android:layout_marginTop="5dp">
    <LinearLayout
        android:orientation="vertical"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:weightSum="20">
        <FrameLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_weight="3"
            android:orientation="horizontal">
            <TabWidget android:id="@android:id/tabs"
                android:layout_width="fill_parent"
                android:layout_height="wrap_content"
                android:visibility="gone"/>
            <LinearLayout
                android:id="@+id/tab_btn_container"
                android:layout_width="fill_parent"
                android:layout_height="wrap_content"
                android:orientation="horizontal">
                <Button
                    android:layout_height="wrap_content"
                    android:layout_width="match_parent"
                    android:layout_weight="1.0"
                    android:background="@color/lightest_grey"
                    android:id="@+id/temp_addr_tab_btn"
                    android:text="Temporary Addresses"
                    android:layout_marginRight="1dp"
                    android:textSize="7sp"
                    android:gravity="bottom|center"
                    android:drawableTop="@mipmap/ic_launcher"
                    android:paddingTop="4dp"
                    />
                <Button
                    android:layout_height="wrap_content"
                    android:layout_width="match_parent"
                    android:layout_weight="1.0"
                    android:background="@color/lightest_grey"
                    android:id="@+id/postal_addr_tab_btn"
                    android:text="Postal Addresses"
                    android:layout_marginRight="1dp"
                    android:textSize="7sp"
                    android:gravity="bottom|center"
                    android:drawableTop="@mipmap/ic_launcher"
                    android:paddingTop="4dp"
                    />
                <Button
                    android:layout_height="wrap_content"
                    android:layout_width="match_parent"
                    android:layout_weight="1.0"
                    android:background="@color/lightest_grey"
                    android:id="@+id/home_addr_tab_btn"
                    android:text="Home Addresses"
                    android:layout_marginRight="1dp"
                    android:textSize="7sp"
                    android:gravity="bottom|center"
                    android:drawableTop="@mipmap/ic_launcher"
                    android:paddingTop="4dp"
                    />
                <Button
                    android:layout_height="wrap_content"
                    android:layout_width="match_parent"
                    android:layout_weight="1.0"
                    android:background="@color/lightest_grey"
                    android:id="@+id/tel_fax_tab_btn"
                    android:text="Telephone / Fax"
                    android:layout_marginRight="1dp"
                    android:textSize="7sp"
                    android:gravity="bottom|center"
                    android:drawableTop="@mipmap/ic_launcher"
                    android:paddingTop="4dp"
                    />
                <Button
                    android:layout_height="wrap_content"
                    android:layout_width="match_parent"
                    android:layout_weight="1.0"
                    android:background="@color/lightest_grey"
                    android:id="@+id/email_other_tab_btn"
                    android:text="Email / Other"
                    android:textSize="7sp"
                    android:gravity="bottom|center"
                    android:drawableTop="@mipmap/ic_launcher"
                    android:paddingTop="4dp"
                    />
            </LinearLayout>
        </FrameLayout>
        <FrameLayout android:id="@android:id/tabcontent"
            android:layout_width="fill_parent"
            android:layout_height="match_parent"
            android:layout_weight="17"
            android:background="@color/white"/>
    </LinearLayout>
</android.support.v4.app.FragmentTabHost>

So when a user clicks the first tab or the page has just rendered it will show another fragment in the android:id="@android:id/tabcontent".

This works and it shows my temporary address fragment:

<FrameLayout 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"
tools:context="com.example.android.mockattempt1.TemporaryAddressesFragment">

<TextView android:layout_width="match_parent" android:layout_height="match_parent"
    android:text="Temp Addresses Fragment that will show address information soon" />

Currently the temporary address fragment is just a hardcoded text view but I want this to be a swipeable set of temporary address fragments that the user is able to swipe through to view the addresses.

I am trying to fit this tutorial http://www.101apps.co.za/articles/swipe-view-tutorial.html into my application but I am unsure of where the ViewPager xml should go, it almost seems like it should be my tabcontent xml in the parent fragment?

I do not think that this is right through because in the parent fragment the tab content is set up like this:

mTabHost = (FragmentTabHost)rootView.findViewById(android.R.id.tabhost);
    mTabHost.setup(getActivity(), getChildFragmentManager(), android.R.id.tabcontent);
    mTabHost.addTab(mTabHost.newTabSpec("temp_addresses").setIndicator("Temporary Addresses"), TemporaryAddressesFragment.class, null);
    mTabHost.setCurrentTab(0);

I almost need to replace that with the page adaptor functionality or somehow get them to work together but I am not sure how to do this.


Solution

  • I have managed to do this but not entirely sure its the best way but I will detail my attempts as it works:

    Fragment with horizontal tabs displayed for the first tab content, previous addresses (fragment_record.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"
        android:background="@color/white"
        android:layout_marginTop="5dp">
        <LinearLayout
            android:orientation="vertical"
            android:layout_width="fill_parent"
            android:layout_height="fill_parent"
            android:weightSum="20">
            <FrameLayout
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_weight="3"
                android:orientation="horizontal">
                <TabWidget android:id="@android:id/tabs"
                    android:layout_width="fill_parent"
                    android:layout_height="wrap_content"
                    android:visibility="gone"/>
                <LinearLayout
                    android:id="@+id/tab_btn_container"
                    android:layout_width="fill_parent"
                    android:layout_height="wrap_content"
                    android:orientation="horizontal">
                    <Button
                        android:layout_height="wrap_content"
                        android:layout_width="match_parent"
                        android:layout_weight="1.0"
                        android:background="@color/lightest_grey"
                        android:id="@+id/temp_addr_tab_btn"
                        android:text="Temporary Addresses"
                        android:layout_marginRight="1dp"
                        android:textSize="7sp"
                        android:gravity="bottom|center"
                        android:drawableTop="@mipmap/ic_launcher"
                        android:paddingTop="4dp"
                        />
                    <Button
                        android:layout_height="wrap_content"
                        android:layout_width="match_parent"
                        android:layout_weight="1.0"
                        android:background="@color/lightest_grey"
                        android:id="@+id/postal_addr_tab_btn"
                        android:text="Postal Addresses"
                        android:layout_marginRight="1dp"
                        android:textSize="7sp"
                        android:gravity="bottom|center"
                        android:drawableTop="@mipmap/ic_launcher"
                        android:paddingTop="4dp"
                        />
                    <Button
                        android:layout_height="wrap_content"
                        android:layout_width="match_parent"
                        android:layout_weight="1.0"
                        android:background="@color/lightest_grey"
                        android:id="@+id/home_addr_tab_btn"
                        android:text="Home Addresses"
                        android:layout_marginRight="1dp"
                        android:textSize="7sp"
                        android:gravity="bottom|center"
                        android:drawableTop="@mipmap/ic_launcher"
                        android:paddingTop="4dp"
                        />
                    <Button
                        android:layout_height="wrap_content"
                        android:layout_width="match_parent"
                        android:layout_weight="1.0"
                        android:background="@color/lightest_grey"
                        android:id="@+id/tel_fax_tab_btn"
                        android:text="Telephone / Fax"
                        android:layout_marginRight="1dp"
                        android:textSize="7sp"
                        android:gravity="bottom|center"
                        android:drawableTop="@mipmap/ic_launcher"
                        android:paddingTop="4dp"
                        />
                    <Button
                        android:layout_height="wrap_content"
                        android:layout_width="match_parent"
                        android:layout_weight="1.0"
                        android:background="@color/lightest_grey"
                        android:id="@+id/email_other_tab_btn"
                        android:text="Email / Other"
                        android:textSize="7sp"
                        android:gravity="bottom|center"
                        android:drawableTop="@mipmap/ic_launcher"
                        android:paddingTop="4dp"
                        />
                </LinearLayout>
            </FrameLayout>
            <FrameLayout android:id="@android:id/tabcontent"
                android:layout_width="fill_parent"
                android:layout_height="match_parent"
                android:layout_weight="17"
                android:background="@color/white"/>
        </LinearLayout>
    </android.support.v4.app.FragmentTabHost>
    

    Set up the tabs and an intent for the temporary address fragment detailed below (RecordFragment.java):

    mTabHost = (FragmentTabHost)rootView.findViewById(android.R.id.tabhost);
        mTabHost.setup(getActivity(), getChildFragmentManager(), android.R.id.tabcontent);
        mTabHost.addTab(mTabHost.newTabSpec("temp_addresses").setIndicator("Temporary Addresses"), TemporaryAddressesFragment.class, null);
        mTabHost.setCurrentTab(0);
    

    Placeholder fragment for the ViewPager (fragment_temporary_addresses.xml):

    <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
        <android.support.v4.view.ViewPager xmlns:android="http://schemas.android.com/apk/res/android"
        android:id="@+id/temp_addr_pager"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_weight="1">
    
        </android.support.v4.view.ViewPager>
    

    Class that represents above fragment and also contains inner class (TemporaryAddressesFragment.java):

    private ViewPager temporaryAddressViewPager;
    private TemporaryAddressDetailFragmentStatePageAdapter temporaryAddressStateAdapter;
    
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        // Inflate the layout for this fragment
        View rootView = (View)inflater.inflate(R.layout.fragment_temporary_addresses, container, false);
        temporaryAddressStateAdapter = new TemporaryAddressDetailFragmentStatePageAdapter(getFragmentManager());
        temporaryAddressViewPager = (ViewPager)rootView.findViewById(R.id.temp_addr_pager);
        temporaryAddressViewPager.setAdapter(temporaryAddressStateAdapter);
        return rootView;
    }
    

    The inner class contained in this fragment class which is the adapter, this currently just serves up 3 hardcoded temp address detail fragments:

    public class TemporaryAddressDetailFragmentStatePageAdapter extends FragmentStatePagerAdapter {
    
        public TemporaryAddressDetailFragmentStatePageAdapter(FragmentManager fragmentManager) {
            super(fragmentManager);
        }
    
        @Override
        public int getCount() {
            return 3;
        }
    
        @Override
        public Fragment getItem(int position) {
            Fragment fragment = null;
    
            fragment = new TemporaryAddressDetailFragment();
    
            return fragment;
        }
    }
    

    }

    Another fragment which represents the actual content\detail that I want to have swipeable (fragment_temporary_address_detail.xml):

    <FrameLayout 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"
    tools:context="com.example.android.oxygenmockattempt1.TemporaryAddressDetailFragment">
    
    <!-- TODO: Update blank fragment layout -->
    <TextView android:layout_width="match_parent" android:layout_height="match_parent"
        android:text="This is the temporary address detail fragment screen" />
    

    There is also a class that represents the above fragment (TemporaryAddressDetailFragment.java) which currently doesnt do anything as the fragment xml displays a hardcoded string.

    I also implement the following inerfaces in my actual activity class (MainActivity.java):

    TemporaryAddressesFragment.OnFragmentInteractionListener, TemporaryAddressDetailFragment.OnFragmentInteractionListener
    

    So now when the first tab is displayed on my fragment i have 3 address panes which are swipeable but this does not swipe the tabs in anyway.