In this tut, I present a project work like Facebook register account features, user must put data on this screen before "next" to another. Please watch this DEMO VIDEO first:
Customizing a "Disabled" ViewPager
package info.devexchanges.disabledviewpager.fragment; import android.content.Context; import android.support.v4.view.ViewPager; import android.util.AttributeSet; import android.view.MotionEvent; public class NonSwipeableViewPager extends ViewPager { public NonSwipeableViewPager(Context context) { super(context); } public NonSwipeableViewPager(Context context, AttributeSet attrs) { super(context, attrs); } @Override public boolean onInterceptTouchEvent(MotionEvent event) { // Never allow swiping to switch between pages return false; } @Override public boolean onTouchEvent(MotionEvent event) { // Never allow swiping to switch between pages return false; } }
Creating an adapter with customized ViewPager
package info.devexchanges.disabledviewpager.adapter; import android.support.v4.app.Fragment; import android.support.v4.app.FragmentManager; import android.support.v4.app.FragmentStatePagerAdapter; import info.devexchanges.disabledviewpager.fragment.NameEmailFragment; import info.devexchanges.disabledviewpager.fragment.OtherInfoFragment; public class ViewPagerAdapter extends FragmentStatePagerAdapter { public ViewPagerAdapter(FragmentManager fm) { super(fm); } @Override public Fragment getItem(int position) { if (position == 2) { return new OtherInfoFragment(); } else { return NameEmailFragment.getInstance(position); } } @Override public int getCount() { return 3; } }
Building activities and ViewPager Fragments (pages)
After above step, we put this ViewPager object it first activity in xml layout:
In programmatically code (InputActivity.java), initialize ViewPager and set adapter like primitive:
adapter = new ViewPagerAdapter(getSupportFragmentManager()); viewPager.setAdapter(adapter);Because of disabling swipe, we must provide a method to "next" page:
public void goToNextPage() { viewPager.setCurrentItem(viewPager.getCurrentItem() + 1); }In Fragments, the most important problem is communicating with activity (sending data). Like "Android developer docs" say, we use Interface to pass data. With the first two pages, user will put name and email, I use a mutual Fragment and change input type by programmatically code. First, to sending data, declaring in it an Interface and create a variable with this Interface style:
private OnNameEmailChangedListener callback; // Container Activity must implement this interface public interface OnNameEmailChangedListener { public void onNameEmailChanged(int position, String name); }Attach data to activity in onAttach():
@Override public void onAttach(Activity activity) { super.onAttach(activity); // This makes sure that the container activity has implemented // the callback interface. If not, it throws an exception try { callback = (OnNameEmailChangedListener) activity; } catch (ClassCastException e) { throw new ClassCastException(activity.toString()); } }Back to InputActivity above, it must implement OnNameEmailChangedListener and this override onNameChanged() like below:
@Override public void onNameEmailChanged(int position, String s) { if (position == 1) { user.setEmail(s); } else { user.setName(s); } }Over here, we have full code for NameEmailFragment:
> package info.devexchanges.disabledviewpager.fragment; import android.app.Activity; import android.os.Bundle; import android.support.annotation.Nullable; import android.support.design.widget.TextInputLayout; import android.support.v4.app.Fragment; import android.text.InputType; import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.Toast; import info.devexchanges.disabledviewpager.InputActivity; import info.devexchanges.disabledviewpager.R; public class NameEmailFragment extends Fragment { private TextInputLayout inputLayout; private View btnNext; private int position; private OnNameEmailChangedListener callback; // Container Activity must implement this interface public interface OnNameEmailChangedListener { public void onNameEmailChanged(int position, String name); } public static Fragment getInstance(int position) { NameEmailFragment f = new NameEmailFragment(); Bundle args = new Bundle(); args.putInt("POSITION", position); f.setArguments(args); return f; } @Nullable @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { return inflater.inflate(R.layout.fragment_name, null, false); } @Override public void onViewCreated(View view, @Nullable Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); inputLayout = (TextInputLayout) view.findViewById(R.id.username_field); btnNext = view.findViewById(R.id.btn_next); position = getArguments().getInt("POSITION"); Log.i("Fragment", "" + position); if (position == 1) { inputLayout.getEditText().setInputType(InputType.TYPE_TEXT_VARIATION_EMAIL_ADDRESS); inputLayout.setHint("Your Email"); } btnNext.setOnClickListener(onNextListener()); } @Override public void onAttach(Activity activity) { super.onAttach(activity); // This makes sure that the container activity has implemented // the callback interface. If not, it throws an exception try { callback = (OnNameEmailChangedListener) activity; } catch (ClassCastException e) { throw new ClassCastException(activity.toString()); } } private View.OnClickListener onNextListener() { return new View.OnClickListener() { @Override public void onClick(View v) { if (inputLayout.getEditText().getText().toString().trim().equals("")) { Toast.makeText(getActivity(), "Please Input your Name", Toast.LENGTH_SHORT).show(); } else { // Notify the parent activity of selected item callback.onNameEmailChanged(position, inputLayout.getEditText().getText().toString()); //go to next page ((InputActivity) getActivity()).goToNextPage(); } } }; } }And it's layout, use new TextInputLayout widget in Material Design tech :
And after running, this screen will like:
Similar with above steps, creating a Fragment to put age and gender:
As you can see above, in each fragment, after press Button "Next", go to next page by this code:
((InputActivity) getActivity()).goToNextPage();Full code for this page/fragment:
package info.devexchanges.disabledviewpager.fragment; import android.app.Activity; import android.os.Bundle; import android.support.annotation.Nullable; import android.support.design.widget.TextInputLayout; import android.support.v4.app.Fragment; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.AdapterView; import android.widget.ArrayAdapter; import android.widget.Spinner; import android.widget.Toast; import java.util.ArrayList; import info.devexchanges.disabledviewpager.InputActivity; import info.devexchanges.disabledviewpager.R; public class OtherInfoFragment extends Fragment { private Spinner spinner; private TextInputLayout inputLayout; private ArrayAdapter<String> adapter; private ArrayList<String> genders; private View btnNext; private String gender; private OnInfoChangedListener callback; // Container Activity must implement this interface public interface OnInfoChangedListener { public void onInfoChanged(String age, String gender); } @Nullable @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { return inflater.inflate(R.layout.fragment_other_infor, null, false); } @Override public void onAttach(Activity activity) { super.onAttach(activity); // This makes sure that the container activity has implemented // the callback interface. If not, it throws an exception try { callback = (OnInfoChangedListener) activity; } catch (ClassCastException e) { throw new ClassCastException(activity.toString()); } } @Override public void onViewCreated(View view, @Nullable Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); spinner = (Spinner)view.findViewById(R.id.gender); inputLayout = (TextInputLayout)view.findViewById(R.id.age_field); btnNext = view.findViewById(R.id.btn_next); //set spinner adapter genders = new ArrayList<>(); genders.add("Male"); genders.add("Female"); adapter = new ArrayAdapter<>(getActivity(), android.R.layout.simple_spinner_item, genders); spinner.setAdapter(adapter); //set on item spinner selected spinner.setOnItemSelectedListener(onItemSelectedListener()); //set click event for button btnNext.setOnClickListener(onNextListener()); } private View.OnClickListener onNextListener() { return new View.OnClickListener() { @Override public void onClick(View v) { if (inputLayout.getEditText().getText().toString().trim().equals("")) { Toast.makeText(getActivity(), "Please input your age", Toast.LENGTH_SHORT).show(); } else { callback.onInfoChanged(inputLayout.getEditText().getText().toString(), gender); ((InputActivity) getActivity()).goToResultActivity(); } } }; } private AdapterView.OnItemSelectedListener onItemSelectedListener() { return new AdapterView.OnItemSelectedListener() { @Override public void onItemSelected(AdapterView parent, View view, int position, long id) { gender = spinner.getSelectedItem().toString(); } @Override public void onNothingSelected(AdapterView parent) { } }; } }Now, with one more Fragment with OnInfoChangeListener interface, InputActivity must implement it, too. We must override onInforChanged() method in it. Now, we have completed code for this activity (containing ViewPager and "collect data":
package info.devexchanges.disabledviewpager; import android.content.Intent; import android.support.v4.view.ViewPager; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.util.Log; import info.devexchanges.disabledviewpager.adapter.ViewPagerAdapter; import info.devexchanges.disabledviewpager.fragment.NameEmailFragment; import info.devexchanges.disabledviewpager.fragment.OtherInfoFragment; import info.devexchanges.disabledviewpager.pojo.User; public class InputActivity extends AppCompatActivity implements NameEmailFragment.OnNameEmailChangedListener, OtherInfoFragment.OnInfoChangedListener { private ViewPager viewPager; private User user; private ViewPagerAdapter adapter; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); user = new User(); viewPager = (ViewPager)findViewById(R.id.view_pager); adapter = new ViewPagerAdapter(getSupportFragmentManager()); viewPager.setAdapter(adapter); } public void goToNextPage() { viewPager.setCurrentItem(viewPager.getCurrentItem() + 1); } public void goToResultActivity() { Intent intent = new Intent(this, ResultActivity.class); intent.putExtra("USER INFO", user); startActivity(intent); } @Override public void onNameEmailChanged(int position, String s) { if (position == 1) { user.setEmail(s); } else { user.setName(s); } } @Override public void onInfoChanged(String age, String gender) { user.setAge(Integer.valueOf(age)); user.setGender(gender); } }
Coding a data receiption activity
Ouput when running:
Getting data through Intent, and set to view in programmatically code:
package info.devexchanges.disabledviewpager; import android.os.Bundle; import android.support.v7.app.AppCompatActivity; import android.widget.TextView; import info.devexchanges.disabledviewpager.pojo.User; public class ResultActivity extends AppCompatActivity { private TextView name; private TextView email; private TextView age; private TextView gender; private User user; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_result); name = (TextView) findViewById(R.id.name); email = (TextView) findViewById(R.id.email); age = (TextView) findViewById(R.id.age); gender = (TextView) findViewById(R.id.gender); //get Data from Intent user = (User) getIntent().getExtras().getSerializable("USER INFO"); } @Override protected void onStart() { super.onStart(); //set data to View name.setText(user.getName()); email.setText(user.getEmail()); age.setText("" + user.getAge()); gender.setText(user.getGender()); } }Finally, this is POJO for project (User). We must implement Serializable to put this object through Intent:
package info.devexchanges.disabledviewpager.pojo; import java.io.Serializable; public class User implements Serializable { private String name; private String email; private String gender; private int age; public String getName() { return name; } public void setName(String name) { this.name = name; } public String getEmail() { return email; } public void setEmail(String email) { this.email = email; } public String getGender() { return gender; } public void setGender(String gender) { this.gender = gender; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } }
Conclusion
- Read official doc to deep understand passing data in Fragment and Activity.
- Read more tuts about ViewPager by follow this tag link.
- See this post to learn how to use TextInputLayout, a Material Design widget.