Search code examples
androidandroid-fragmentsandroid-viewpagerswipe-gesturefragmentstatepageradapter

Android - disable forward swipe on data not filled correctly


I have an activity that manages instances of some sequential fragments and a ViewPager whose adapter is of type FragmentStatePagerAdapter. This fragments are sequentials because I want to create a sort of wizard that people must follow. All works fine, but I want to disable swipe when user wants to go to the next page (fragment) of the wizard if he has not completed all the fields in the current page.

    package edu.polimi.dima.home121;


import android.net.Uri;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentStatePagerAdapter;
import android.support.v4.view.PagerAdapter;
import android.support.v4.view.ViewPager;
import android.support.v7.app.ActionBarActivity;

import edu.polimi.dima.home121.model.Place;

/**
 * Created by leo on 13/01/2015.
 */
public class NewPlaceActivity extends ActionBarActivity
        implements NewPlaceSummaryFragment.OnFragmentInteractionListener,
        NewPlaceWizardFirstStepFragment.OnFragmentInteractionListener,
        NewPlaceWizardSecondStepFragment.OnFragmentInteractionListener,
        NewPlaceWizardThirdStepFragment.OnFragmentInteractionListener,
        NewPlaceWizardFourthStepFragment.OnFragmentInteractionListener {

    private final String TAG = getClass().getSimpleName();
    private static Place place;

    private static final int NUM_PAGES = 7;
    private ViewPager mPager;
    private PagerAdapter mPagerAdapter;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        place = new Place();
        setContentView(R.layout.activity_new_place);

        mPager = (ViewPager) findViewById(R.id.pager);
        mPagerAdapter = new ScreenSlidePagerAdapter(getSupportFragmentManager(), mPager, place);
        mPager.setAdapter(mPagerAdapter);
        /*if (savedInstanceState == null) {
            getSupportFragmentManager().beginTransaction()
                    .add(R.id.newPlaceContainer, NewPlaceSummaryFragment.newInstance(place))
                    .commit();
        }*/
    }

    @Override
    public void onBackPressed() {
        if (mPager.getCurrentItem() == 0) {
            // If the user is currently looking at the first step, allow the system to handle the
            // Back button. This calls finish() on this activity and pops the back stack.
            super.onBackPressed();
        } else {
            // Otherwise, select the previous step.
            mPager.setCurrentItem(mPager.getCurrentItem() - 1);
        }
    }

    @Override
    public void onFragmentInteraction(Uri uri) {
    }

    private class ScreenSlidePagerAdapter extends FragmentStatePagerAdapter {
        private Place place;
        private ViewPager mPager;

        public ScreenSlidePagerAdapter(FragmentManager fm, ViewPager mPager, Place place) {
            super(fm);
            this.place = place;
            this.mPager = mPager;
        }

        @Override
        public Fragment getItem(int position) {
            switch (position) {
                case 0:
                    return new NewPlace0();
                case 1:
                    NewPlaceWizardFirstStepFragment f1 = new NewPlaceWizardFirstStepFragment().newInstance(place);
                    f1.setPager(mPager);
                    return f1;
                case 2:
                    NewPlaceWizardSecondStepFragment f2 = new NewPlaceWizardSecondStepFragment().newInstance(place);
                    f2.setPager(mPager);
                    return f2;
                case 3:
                    NewPlaceWizardThirdStepFragment f3 = new NewPlaceWizardThirdStepFragment().newInstance(place);
                    f3.setPager(mPager);
                    return f3;
                case 4:
                    NewPlaceWizardFourthStepFragment f4 = new NewPlaceWizardFourthStepFragment().newInstance(place);
                    f4.setPager(mPager);
                    return f4;
                case 5:
                    NewPlace99 f5 = new NewPlace99();
                    return f5;
                case 6:
                    NewPlaceSaving last = NewPlaceSaving.newInstance(place);
                    return last;
                default:
                    return null;
            }

        }

        @Override
        public int getCount() {
            //TODO sistemare il conteggio delle pagine
            return NUM_PAGES;
        }
    }
}

For example the first fragment I have is:

    public class NewPlaceWizardFirstStepFragment extends Fragment implements View.OnClickListener,
        DialogInterface.OnClickListener {

    private final String TAG = this.getClass().getSimpleName();

    private static Place place;
    private OnFragmentInteractionListener mListener;
    private static View view;
    private ViewPager pager;

    public NewPlaceWizardFirstStepFragment() {
    }

    private TextView lblAvailableFrom;
    private Button btnSingleRoom;
    private Button btnDoubleRoom;
    private Button btnStudioFlat;
    private Button btnApartment;
    private Button btnChangeDate;
    private Button btnNext;
    private EditText tfStreet;
    private EditText tfCivic;
    private EditText tfStair;
    private EditText tfFloor;
    private EditText tfCity;
    private EditText tfPostalCode;

    public static NewPlaceWizardFirstStepFragment newInstance(Place place) {
        NewPlaceWizardFirstStepFragment fragment = new NewPlaceWizardFirstStepFragment();
        fragment.place = place;
        return fragment;
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        view = inflater.inflate(R.layout.fragment_new_place_wizard_first_step, container, false);
        setupUI();
        return view;
    }

    public void setupUI() {
        btnNext = (Button) view.findViewById(R.id.btnNext);
        btnNext.setOnClickListener(this);
        btnSingleRoom = (Button) view.findViewById(R.id.btnSingleRoom);
        btnSingleRoom.setOnClickListener(this);
        btnDoubleRoom = (Button) view.findViewById(R.id.btnDoubleRoom);
        btnDoubleRoom.setOnClickListener(this);
        btnStudioFlat = (Button) view.findViewById(R.id.btnStudioFlat);
        btnStudioFlat.setOnClickListener(this);
        btnApartment = (Button) view.findViewById(R.id.btnApartment);
        btnApartment.setOnClickListener(this);
        btnChangeDate = (Button) view.findViewById(R.id.changeDate);
        btnChangeDate.setOnClickListener(this);
        lblAvailableFrom = (TextView) view.findViewById(R.id.lblAvailableFrom);
        tfStreet = (EditText) view.findViewById(R.id.tfStreet);
        tfCivic = (EditText) view.findViewById(R.id.tfCivic);
        tfStair = (EditText) view.findViewById(R.id.tfStair);
        tfFloor = (EditText) view.findViewById(R.id.tfFloor);
        tfCity = (EditText) view.findViewById(R.id.tfCity);
        tfPostalCode = (EditText) view.findViewById(R.id.tfPostalAddress);
    }

    AlertDialog availableFromDialog;

    private boolean enoughDataToContinue() {
        boolean ret = true;
        ret &= tfStreet.getText().length() != 0;
        ret &= tfCivic.getText().length() != 0;
        ret &= tfCity.getText().length() != 0;
        return ret;
    }

    private void collectUserData() {
        Address a = new Address();
        a.setStreet(String.valueOf(tfStreet.getText()));
        a.setNumber(String.valueOf(tfCivic.getText()));
        a.setFloor(String.valueOf(tfFloor.getText()));
        a.setStair(String.valueOf(tfStair.getText()));
        a.setCity(String.valueOf(tfCity.getText()));
        a.setPostalCode(String.valueOf(tfPostalCode.getText()));
        place.setApartment(new Apartment());
        place.getApartment().setAddress(a);
        MiscServices.setCoordinates(place.getApartment());
        Log.d(TAG, "first step done:" + new ObjectMapper().convertValue(place, Map.class).toString());
    }

    //TODO aggionare il toast
    private void notifyUserOfInputIssues() {
        Toast.makeText(getActivity().getApplicationContext(), "Complete all the fields to continue",
                Toast.LENGTH_LONG).show();
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.btnNext:
                if (enoughDataToContinue()) {
                    collectUserData();
                    pager.setCurrentItem(pager.getCurrentItem() + 1, true);
                }
                else
                    notifyUserOfInputIssues();
                break;
            case R.id.changeDate:
                AvailableFromDialogBuilder availableFromDialogBuilder = new AvailableFromDialogBuilder(getActivity());
                if (place.getAvailableFrom() != null)
                    availableFromDialogBuilder.setValue(place.getAvailableFrom());
                availableFromDialogBuilder.setPositiveButton(R.string.my_continue, this);
                availableFromDialog = availableFromDialogBuilder.show();
                break;
            case R.id.btnSingleRoom:
                Log.v(TAG, "SingleRoom pressed");
                clearSelection();
                btnSingleRoom.setSelected(true);
                place.setAccomodationType(Place.SINGLE_ROOM);
                break;
            case R.id.btnDoubleRoom:
                Log.v(TAG, "DoubleRoom pressed");
                clearSelection();
                btnDoubleRoom.setSelected(true);
                place.setAccomodationType(Place.DOUBLE_ROOM);
                break;
            case R.id.btnApartment:
                Log.v(TAG, "Apartment pressed");
                clearSelection();
                btnApartment.setSelected(true);
                place.setAccomodationType(Place.STANDARD_RENT);
                break;
            case R.id.btnStudioFlat:
                Log.v(TAG, "StudioFlat pressed");
                clearSelection();
                btnStudioFlat.setSelected(true);
                place.setAccomodationType(Place.STUDIO_FLAT);
                break;
            default:
                Log.e(TAG, getResources().getString(R.string.error_ID) + v.getId());
        }
    }

    public void clearSelection() {
        btnApartment.setSelected(false);
        btnSingleRoom.setSelected(false);
        btnDoubleRoom.setSelected(false);
        btnStudioFlat.setSelected(false);
    }

    ;

    @Override
    public void onClick(DialogInterface dialog, int which) {
        if (dialog == availableFromDialog) {
            DatePicker datePicker = (DatePicker) availableFromDialog.findViewById(R.id.dpAvailableFrom);
            Calendar cal = Calendar.getInstance();
            cal.set(Calendar.DAY_OF_MONTH, datePicker.getDayOfMonth());
            cal.set(Calendar.MONTH, datePicker.getMonth());
            cal.set(Calendar.YEAR, datePicker.getYear());
            place.setAvailableFrom(cal.getTime());
            lblAvailableFrom.setText(datePicker.getDayOfMonth() + " - " + cal.getDisplayName(Calendar.MONTH, Calendar.SHORT, getResources().getConfiguration().locale) + " - " + datePicker.getYear());
        } else Log.e(TAG, getResources().getString(R.string.error_dialog));
    }

    @Override
    public void onAttach(Activity activity) {
        super.onAttach(activity);
        try {
            mListener = (OnFragmentInteractionListener) activity;
        } catch (ClassCastException e) {
            throw new ClassCastException(activity.toString()
                    + " must implement OnFragmentInteractionListener");
        }
    }

    @Override
    public void onDetach() {
        super.onDetach();
        mListener = null;
    }

    public void setPager(ViewPager pager) {
        this.pager = pager;
    }

    public ViewPager getPager() {
        return pager;
    }

    public interface OnFragmentInteractionListener {
        // TODO: valutare se serve
        public void onFragmentInteraction(Uri uri);
    }
}

How can I disable the swipe to the next fragment (right to left) even if the backward swipe (left to right) must be always enabled?


Solution

  • First, a little advice; For each of the following lines, there is no need to new since the method is static:

    NewPlaceWizardFirstStepFragment f1 = NewPlaceWizardFirstStepFragment.newInstance(place);
    

    That said, I'd probably just add some logic to your pager adapter to limit the count by the number of completed pages. i.e. If you're on step 4, count is 4. Upon completing step 4, increment the count to allow the user to swipe to the next fragment.

    See this stack overflow post for an example:

    ViewPager disable swiping to a certain direction