Search code examples
androidandroid-layoutandroid-viewpagertablelayoutswipe-gesture

Android: How to swipe columns in a TableLayout?


I'm trying to make a TableLayout within a Fragment that supports column swiping.

As the image in the link below shows, the first column ("Header 1") should be fixed, whereas the other columns ("Header 2", "Header 3", and "Header 4" ) should be swipeable.

Depending on which column it is, the header should also show one or two arow icons. On clicking these arrow icons, the columns should also change.

Any ideas how to best implement this? Thanks in advance.

Show image


Solution

  • First of all, thanks to everyone. Seems like i didn't see the obvious.

    The solution for me was to use a fixed ListView for the first column and a ViewPager with a ListView for the slideable columns.

    In my main layout file, I have therefore declared a ListView and a ViewPager with layout weights set to 0.5 on both of them. This makes sure that both the fixed column and the slideable column have the same width:

    my_main_layout.xml

    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="horizontal"
    android:padding="16dp">
    
    <LinearLayout
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_weight="0.5"
        android:orientation="vertical">
    
        <TextView
            android:id="@+id/firstColumnHeader"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:gravity="center"
            android:paddingRight="@dimen/padding_horizontal_small"
            android:textAppearance="?android:textAppearanceMedium"
            android:textStyle="bold" />
    
        <View
            android:layout_width="match_parent"
            android:layout_height="1dp"
            android:background="@color/gray" />
    
    
        <ListView
            android:id="@+id/firstColumnList"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:divider="@null"
            android:dividerHeight="0dp"
            android:scrollbars="none"
            />
    </LinearLayout>
    
    
    <android.support.v4.view.ViewPager
        android:id="@+id/pager"
        android:layout_width="0dp"
        android:layout_height="match_parent"
        android:listSelector="@android:color/transparent"
        android:layout_weight="0.5" />
    

    For the slideable column, I made a second custom layout file with the ListView and with a horizontal LinearLayout containing the column name and the two arrows:

    slideable_column_layout.xml

    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="vertical">
    
    <LinearLayout
        android:id="@+id/viewpagerHeader"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:gravity="center"
        android:orientation="horizontal">
    
        <ImageView
            android:id="@+id/leftPagerArrow"
            android:layout_width="wrap_content"
            android:layout_height="15dp"
            android:layout_gravity="center_vertical"
            android:layout_marginRight="10dp"
            android:adjustViewBounds="true"
            android:src="@drawable/arrow_left" />
    
        <TextView
            android:id="@+id/headerText"
            android:textAppearance="?android:textAppearanceMedium"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:gravity="center"
            android:textStyle="bold" />
    
        <ImageView
            android:id="@+id/rightPagerArrow"
            android:layout_width="wrap_content"
            android:layout_height="15dp"
            android:layout_gravity="center_vertical"
            android:layout_marginLeft="10dp"
            android:adjustViewBounds="true"
            android:src="@drawable/arrow_right" />
    
    </LinearLayout>
    
    <View
        android:layout_width="match_parent"
        android:layout_height="1dp"
        android:background="@color/gray" />
    
    <ListView
        android:id="@android:id/list"
        android:layout_width="match_parent"
        android:layout_height="200dp"
        android:divider="@null"
        android:dividerHeight="0dp"
        android:listSelector="@android:color/transparent"
        android:scrollbars="none" />
    

    Then, in my Fragment where I want to use the slideable columns, I implemented the ViewPager, a PagerAdapter and the ListViews:

    import android.app.Fragment;
    import android.app.FragmentManager;
    import android.app.ListFragment;
    import android.os.Bundle;
    import android.support.v13.app.FragmentStatePagerAdapter;
    import android.support.v4.view.PagerAdapter;
    import android.support.v4.view.ViewPager;
    import android.view.LayoutInflater;
    import android.view.View;
    import android.view.ViewGroup;
    import android.widget.ArrayAdapter;
    import android.widget.ImageView;
    import android.widget.ListView;
    import android.widget.TextView;
    
    
    public class MyFragment extends Fragment {
    
        private static final int NUM_PAGES = 4;
        private static final String[] titles = {"Column2", "Column3", "Column4", "Column5"};
        private final String[] column_one = {"Data 1.0", "Data 1.1", "Data 1.2", "Data 1.3"};
    
        public static final String[] column_two = {"Data 2.0", "Data 2.1", "Data 2.2", "Data 2.3"};
    
        public static final String[] column_three = {"Data 3.0", "Data 3.1", "Data 3.2", "Data 3.3"};
    
        public static final String[] column_four = {"Data 4.0", "Data 4.1", "Data 4.2", "Data 4.3"};
    
        public static final String[] column_five = {"Data 5.0", "Data 5.1", "Data 5.2", "Data 5.3"};
    
    
        public static ViewPager mViewPager;
        private PagerAdapter mAdapter;
        private ListView mListView;
    
        @Override
        public View onCreateView(LayoutInflater inflater, ViewGroup container,
                                 Bundle savedInstanceState) {
            View view = inflater.inflate(R.layout.my_main_layout,
                    container, false);
    
            //Set ListView and its adapter
            mListView = (ListView) view.findViewById(R.id.firstColumnList);
            ArrayAdapter<String> sAdapter = new ArrayAdapter<String>(getActivity(), android.R.layout.simple_list_item_1, column_one);
            mListView.setAdapter(sAdapter);
    
            //Set ViewPager and its adapter
            mViewPager = (ViewPager) view.findViewById(R.id.pager);
            mAdapter = new ViewPagerAdapter(getFragmentManager());
            mViewPager.setAdapter(mAdapter);
    
            return view;
        }
    
        public static class ViewPagerAdapter extends FragmentStatePagerAdapter {
            public ViewPagerAdapter(FragmentManager fm) {
                super(fm);
            }
    
            @Override
            public int getCount() {
                return NUM_PAGES;
            }
    
            @Override
            public CharSequence getPageTitle(int position) {
                return titles[position];
            }
    
            @Override
            public Fragment getItem(int position) {
                return SlidingListFragment.newInstance(position);
            }
    
    
        }
    
        public static class SlidingListFragment extends ListFragment {
    
            private int mNum;
            private ImageView leftArrow;
            private ImageView rightArrow;
    
            @Override
            public void onCreate(Bundle savedInstanceState) {
                super.onCreate(savedInstanceState);
                if (getArguments() != null) {
                    mNum = getArguments().getInt("num");
    
                } else {
                    mNum = 1;
                }
            }
    
            @Override
            public View onCreateView(LayoutInflater inflater, ViewGroup container,
                                     Bundle savedInstanceState) {
                View view = inflater.inflate(R.layout.sliding_column_layout,
                        container, false);
    
                ListView slidingList = (ListView) view.findViewById(android.R.id.list);
                TextView header = (TextView) view.findViewById(R.id.headerText);
                header.setText(getHeader());
                leftArrow = (ImageView) view.findViewById(R.id.leftPagerArrow);
                rightArrow = (ImageView) view.findViewById(R.id.rightPagerArrow);
                if (leftArrow.getVisibility() == View.VISIBLE) {
                    leftArrow.setOnClickListener(new View.OnClickListener() {
                        @Override
                        public void onClick(View v) {
                            mViewPager.setCurrentItem(mNum - 1);
                        }
                    });
                }
                if (rightArrow.getVisibility() == View.VISIBLE) {
                    rightArrow.setOnClickListener(new View.OnClickListener() {
                        @Override
                        public void onClick(View v) {
                            mViewPager.setCurrentItem(mNum + 1);
                        }
                    });
                }
                setArrows();
    
                slidingList.setAdapter(new ArrayAdapter<String>(getActivity(), android.R.layout.simple_list_item_1, getMyListArray()));
    
                return view;
            }
    
            private String getHeader() {
                String header = "";
                switch (mNum) {
                    case 0:
                        header = titles[0];
                        break;
                    case 1:
                        header = titles[1];
                        break;
                    case 2:
                        header = titles[2];
                        break;
                    case 3:
                        header = titles[3];
                        break;
                }
                return header;
            }
    
            private void setArrows() {
                switch (mNum) {
                    case 0:
                        leftArrow.setVisibility(View.INVISIBLE);
                        break;
                    case 1:
                        break;
                    case 2:
                        break;
                    case 3:
                        rightArrow.setVisibility(View.INVISIBLE);
                        break;
                }
            }
    
            private String[] getMyListArray() {
                String[] returnArray = {"no lists"};
                switch (mNum) {
                    case 0:
                        returnArray = column_two;
                        break;
                    case 1:
                        returnArray = column_three;
                        break;
                    case 2:
                        returnArray = column_four;
                        break;
                    case 3:
                        returnArray = column_five;
                        break;
                }
                return returnArray;
            }
    
    
            /**
             * Create a new instance of SlidingFragment, providing "num"
             * as an argument.
             */
            static SlidingListFragment newInstance(int num) {
                SlidingListFragment f = new SlidingListFragment();
    
                // Supply num input as an argument.
                Bundle args = new Bundle();
                args.putInt("num", num);
                f.setArguments(args);
    
                return f;
            }
    
        }
    
    }
    

    I don't know whether this is the most efficient solution, but it is working :-)