Jilberta
Jilberta

Reputation: 2866

ViewPager, Scrolling tabs + Swiping

I have tabs where are some Views like EditText, CheckBox, RadioButton and etc. And using ViewPager i'm swiping between these tabs.

Here 's my code:

activity_main.xml

<android.support.v4.view.ViewPager xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/pager"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <!--
    This title strip will display the currently visible page title, as well as the page
    titles for adjacent pages.
    -->

    <android.support.v4.view.PagerTitleStrip
        android:id="@+id/pager_title_strip"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_gravity="top"
        android:background="#33b5e5"
        android:paddingBottom="4dp"
        android:paddingTop="4dp"
        android:textColor="#fff" />

</android.support.v4.view.ViewPager>

MainActivity.java

public class MainActivity extends FragmentActivity {

    /**
     * The {@link android.support.v4.view.PagerAdapter} that will provide
     * fragments for each of the sections. We use a
     * {@link android.support.v4.app.FragmentPagerAdapter} derivative, which
     * will keep every loaded fragment in memory. If this becomes too memory
     * intensive, it may be best to switch to a
     * {@link android.support.v4.app.FragmentStatePagerAdapter}.
     */
    SectionsPagerAdapter mSectionsPagerAdapter;

    /**
     * The {@link ViewPager} that will host the section contents.
     */
    ViewPager mViewPager;

    private static DBManager dbManager;
    private static SharedPreferences myPrefs;

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

        dbManager = new DBManager();

        try {
            DBManager.init(getApplicationContext());
        } catch (SQLException e) {
            Log.e("SQLException: ", e.toString());
        }

        // Create the adapter that will return a fragment for each of the three
        // primary sections of the app.
        mSectionsPagerAdapter = new SectionsPagerAdapter(getSupportFragmentManager());

        // Set up the ViewPager with the sections adapter.
        mViewPager = (ViewPager) findViewById(R.id.pager);
        mViewPager.setAdapter(mSectionsPagerAdapter);

        mViewPager.setOnPageChangeListener(new ViewPager.OnPageChangeListener() {
            @Override
            public void onPageScrolled(int i, float v, int i2) {

            }

            @Override
            public void onPageSelected(int i) {
                 Log.i("Page", "" + i);
//                Fragment frag = mSectionsPagerAdapter.getPrimaryItem();
//                View v = frag.getView();
//                if(v != null)
//                    Log.i("mda", "haaa");

            }

            @Override
            public void onPageScrollStateChanged(int i) {
                Log.i("mda", "hu");
            }
        });
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.main, menu);
        return true;
    }


    /**
     * A {@link FragmentPagerAdapter} that returns a fragment corresponding to
     * one of the sections/tabs/pages.
     */
    public class SectionsPagerAdapter extends FragmentPagerAdapter {
        private Fragment currentFragment;

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

        public Fragment getPrimaryItem(){
            return currentFragment;
        }


        @Override
        public Fragment getItem(int position) {
            // getItem is called to instantiate the fragment for the given page.
            // Return a DummySectionFragment (defined as a static inner class
            // below) with the page number as its lone argument.
            Fragment fragment = new DummySectionFragment();
            Bundle args = new Bundle();
            args.putInt(DummySectionFragment.ARG_SECTION_NUMBER, position + 1);
            fragment.setArguments(args);
            return fragment;
        }

        @Override
        public int getCount() {
            // Show 3 total pages.
            return 5;
        }

        @Override
        public CharSequence getPageTitle(int position) {
            Locale l = Locale.getDefault();
            switch (position) {
                case 0:
                    return getString(R.string.title_section1).toUpperCase(l);
                case 1:
                    return getString(R.string.title_section2).toUpperCase(l);
                case 2:
                    return getString(R.string.title_section3).toUpperCase(l);
                case 3:
                    return getString(R.string.title_section4).toUpperCase(l);
                case 4:
                    return getString(R.string.title_section5).toUpperCase(l);
            }
            return null;
        }

        @Override
        public void setPrimaryItem(ViewGroup container, int position, Object object) {
            super.setPrimaryItem(container, position, object);
            currentFragment = (Fragment)object;
        }
    }

    /**
     * A dummy fragment representing a section of the app, but that simply
     * displays dummy text.
     */
    public static class DummySectionFragment extends Fragment {
        /**
         * The fragment argument representing the section number for this
         * fragment.
         */
        public static final String ARG_SECTION_NUMBER = "section_number";

        public DummySectionFragment() {
        }

        @Override
        public View onCreateView(LayoutInflater inflater, ViewGroup container,
                                 Bundle savedInstanceState) {
            View rootView = inflater.inflate(R.layout.fragment_main_dummy, container, false);
            TextView dummyTextView = (TextView) rootView.findViewById(R.id.section_label);
            dummyTextView.setText(Integer.toString(getArguments().getInt(ARG_SECTION_NUMBER)));

            return rootView;
        }
    }
}

fragment_main_dummy.xml example of 1 tab xml

<LinearLayout 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"
              android:paddingLeft="@dimen/activity_horizontal_margin"
              android:paddingRight="@dimen/activity_horizontal_margin"
              android:paddingTop="@dimen/activity_vertical_margin"
              android:paddingBottom="@dimen/activity_vertical_margin"
              tools:context=".MainActivity$DummySectionFragment"
              android:orientation="vertical">

    <TextView
            android:id="@+id/section_label"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:tag="Mda"/>

    <EditText
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:id="@+id/field1"
            android:tag="Muda"
            android:text="lalalala"/>

    <CheckBox
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:text="New CheckBox"
            android:id="@+id/checkBox"/>

    <TextView
            android:layout_width="wrap_content"
            android:layout_height="76dp"
            android:text="New Text"
            android:id="@+id/textView"
            android:layout_gravity="left|center_vertical"
            android:layout_marginLeft="158dp"/>

    <RadioButton
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="New RadioButton"
            android:id="@+id/radioButton"
            android:layout_gravity="left|center_vertical"/>

    <RadioButton
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="New RadioButton"
            android:id="@+id/radioButton2"
            android:layout_gravity="left|center_vertical"/>

    <RadioButton
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="New RadioButton"
            android:id="@+id/radioButton3"
            android:layout_gravity="left|center_vertical"/>

</LinearLayout>

Problem:

What i want to do is to collect all input from the Views after changing the Page. When user changes the ViewPage and goes to the second tab, I need to take all the info that he has written in the previous tab.

I can get the view of a current Page Fragment with help of setting primaryItem, but i can't get the view of the previous tab. How can it be done ?

Thanks in advance.

Upvotes: 0

Views: 5420

Answers (1)

DejanRistic
DejanRistic

Reputation: 2039

Few things for you,

Saving the state of a normal view has to be done manually, the only view that has the ability to save state for you is TextView and its children. So since EditText is a TextView it is possible.

The property you want to try:

setFreezesText() or android:freezesText for xml.

(note will only work if the TextView has an ID)

This Controls whether this text view saves its entire text contents when freezing to an icicle, in addition to dynamic state such as cursor position. By default this is false, not saving the text. Set to true if the text in the text view is not being saved somewhere else in persistent storage (such as in a content provider) so that if the view is later thawed the user will not lose their data.

Android Docs Reference: http://developer.android.com/reference/android/widget/TextView.html#setFreezesText%28boolean%29

Something else you can try is changing the limit of how many views the view pager is caching. What this can do is keep more views alive without needing to re-create them, thus the data inside them is not lost.

You can achieve this by using the following method of your view pager:

setOffScreenPageLimit(int)

Android Docs Reference: http://developer.android.com/reference/android/support/v4/view/ViewPager.html#setOffscreenPageLimit(int)

Now saving all the data from all the tabs can be done a ton of different ways, for example you could use the args Bundle in the getItem method to store the data of the first tab and pass it to the second tab.

 @Override
    public Fragment getItem(int position) {

        Fragment fragment = new DummySectionFragment();
        Bundle args = new Bundle();
        args.putString("key",myTextView.getText().toString());
        args.putInt(DummySectionFragment.ARG_SECTION_NUMBER, position + 1);
        fragment.setArguments(args);
        return fragment;
    }

Now the new instance of your dummy fragment will have the text from that TextView stored with the key "key" and you can retrieve it using the getArguments() method of a fragment.

For Example:

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

     //here is your arguments
     Bundle bundle=getArguments(); 

    //here is your list array 
    String myString=bundle.getString("key");   
 }

You could also use SharedPreferences to store the data, then retrieve it when you want to store it in the database.

This may be a bit general but it has some good references to shared prefs.

http://developer.android.com/guide/topics/data/data-storage.html

Let me know if this answer helps, or you need some more help.

EDIT:

Okay I think I found a way you can achieve what you are trying to do, its a bit hackish but it will get the job done until a better solution is found. I may look into it a bit more if I have some time.

But for now, here is what you can do.

The method onPageSelected(int position) is where most of the work will be done.

@Override
public void onPageSelected(int position) {
            //This makes sure we get the previous position in the view pager and also
            //makes sure we don't go to -1 when you swipe back to the 0th position.

            //The problem here is if you are using action bar tabs, the user can also select the third tab, from the first tab and the index will be pointing to the second tab. I did not go out of my way to handle this case. But with a few checks you can handle the cases.

            //Also without proper checks, swiping backwards will be an issue, so adding those cases may also be necessary.
    int index = position == 0 ? position : position - 1;


    View view = mViewPager.getChildAt(index);

            // View at this point is the previous view in your view pager
            // and you can access your textviews in the following way.

    TextView myTextView = (TextView) view.findViewById(R.id.section_label);


            // If using action bar tabs, set the selected tab.
    mActionBar.setSelectedNavigationItem(position);
}

Like I said, its pretty hacky and involves some checking conditions, but it will work. I will look at finding a more elegant way to do this when I have some time and post it back on this thread.

Good Luck

Upvotes: 1

Related Questions