I have a button on MainActivity which opens SecondActivity. My SecondActivity is a ViewPager, and I also have 2 fragment classes (fragment1, fragment2) and 2 fragment xml, each with a TextView inside. I cannot work out how to put the two fragment inside the ViewPage using FragmentPagerAdapter so i can slide from one fragment to another. Can somebody please show/help me?
mainActivity
Button button1 = (Button) findViewById(R.id.buttonCreateWorkout);
button1.setOnClickListener(new View.OnClickListener() {
public void onClick(View arg0) {
startActivity(new Intent(MainActivity.this, SecondActivity.class));
}
second_activity.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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/pager"
android:layout_width="match_parent"
android:layout_height="match_parent">
//
//how do i add the two fragments here?
//if this is even the right place
//
</android.support.v4.view.ViewPager>
</LinearLayout>
also, are you able to show me how to use FragmentPagerAdapter to switch between 2 fragments?
Dont add the fragments inside de viewpager xml tag, you add the fragments by code.FragmentPagerAdapter handle this. You should follow this tutorial for correct implementation:
Create Swype Viewa
The PagerFragmentAdapter should look like this, this adapter handle the fragment creation and switch Fragment:
public class DemoCollectionPagerAdapter extends FragmentStatePagerAdapter {
public DemoCollectionPagerAdapter(FragmentManager fm) {
super(fm);
}
#Override
public Fragment getItem(int i) {
Fragment fragment = new DemoObjectFragment();
Bundle args = new Bundle();
// Our object is just an integer :-P
args.putInt(DemoObjectFragment.ARG_OBJECT, i + 1);
fragment.setArguments(args);
return fragment;
}
#Override
public int getCount() {
return 100;
}
#Override
public CharSequence getPageTitle(int position) {
return "OBJECT " + (position + 1);
}
}
Inside getItem method, you create the fragment depending on the value of the index.
Related
I am new to this Fragment theory and I can't seem to understand where we get the R.id.container So I want to start a fragment once a button is clicked. Here is my method
My main Method, I have not added any code to start my Fragment class.
callCenter.setOnClickListener(view -> openCallCenter());
//on clicked open call center which should start a fragment
private void openCallCenter() {
}
My Fragment Class: empty for now;
public class CallCenterFragment extends Fragment {
public static final String TAG = CallCenterFragment.class.getSimpleName();
public CallCenterFragment() {
// Required empty public constructor
}
#Override
public View onCreateView(#NonNull LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_call_center, container, false);
}
}
My Fragment Layout Empty for now:
<?xml version="1.0" encoding="utf-8"?>
<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"
android:id="#+id/fragment_container"
tools:context=".fragment.CallCenterFragment">
<!-- TODO: Update blank fragment layout -->
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:text="#string/hello_blank_fragment" />
</FrameLayout>
SO: my biggest question is on my mainActivity class what code should I add to start this fragment and can someone explain to me since I have seen several example where do we get transaction.replace(R.id.container)
Thanks in advance.
So I will refer you here for more details
On the container Purpose of Container in Fragments for Android
And if you want to display your fragment on the Main activity as your question says try this code.
Add the code on the method.
CallCenterFragment fragment = new
CallCenterFragment();
FragmentTransaction trans = getSupportFragmentManager().beginTransaction();
trans.replace(R.id.container, fragment);
trans.commit();
Note. On your main xml you need to add the container id eg.
<FrameLayout
android:id="#+id/container"
Add width and height />
You will display the text given on your fragment which is string hello blank fragment.
Set the ViewPager in activity xml file where you want show fragment. Create a sub class PageAdapter for super class for super class FragmentPagerAdapter. Complete abstract methods in Subclass.
public class PageAdapter extends FragmentPagerAdapter {
public PageAdapter(FragmentManager fm) {
super(fm);
}
#Override
public Fragment getI tem(int position) {
Fragment fragment = null;
switch (position){
case 0:{
fragment = new ContactFragment();
break;
}
case 1:{
fragment = new RecentFragment();
break;
}
}
return fragment;
}
#Override
public int getCount() {
// 2 is no of fragments
return 2;
}
}
Then After
//--write this code in base activity of fragment
contactview_f = (ViewPager) findViewById(R.id.fragment_layout);
pageAdapter = new PageAdapter(getSupportFragmentManager());
contactview_f.setAdapter(pageAdapter);
I basically have everything set up already and I don't why it's not working. The only problem I have is that the Vertical won't work when I set it up together. Look at the code down below.
My Main Acitvity
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//HorizontalViewPagerAdapter
View background = findViewById(R.id.am_background_view);
ViewPager viewPager = findViewById(R.id.am_view_pager);
HorizontalViewPagerAdapter adapter = new HorizontalViewPagerAdapter(getSupportFragmentManager());
viewPager.setAdapter(adapter);
viewPager.setCurrentItem(1);
}
My Controller Fragment
public class ControllerFragment extends Fragment {
public static ControllerFragment create() {
return new ControllerFragment();
}
VerticalViewPager verticalViewPager;
VerticalViewPagerAdapter verticalPageAdapter;
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.vertical, null);
verticalViewPager = view.findViewById(R.id.am_scrollView);
verticalPageAdapter = new VerticalViewPagerAdapter(getChildFragmentManager());
verticalViewPager.setAdapter(verticalPageAdapter);
return inflater.inflate(R.layout.vertical, null);
}
public class VerticalViewPagerAdapter extends FragmentPagerAdapter {
public VerticalViewPagerAdapter(FragmentManager fm) {
super(fm);
}
#Override
public Fragment getItem(int position) {
switch (position) {
case 0:
return SettingsFragment.create();
case 1:
return EmptyFragment.create();
case 2:
return ExtrasFragment.create();
}
return null;
}
#Override
public int getCount() {
return 3;
}
}
}
This is my HorizontalAdapter
public class HorizontalViewPagerAdapter extends FragmentPagerAdapter {
public HorizontalViewPagerAdapter(FragmentManager fm) {
super(fm);
}
#Override
public Fragment getItem(int position) {
switch (position) {
case 0:
return ChatFragment.create();
case 1:
return ControllerFragment.create();
case 2:
return StoryFragment.create();
}
return null;
}
#Override
public int getCount() {
return 3;
}
Its like the whole code is completely ignoring the VerticalView Pager because it doesnt show at all in my app and its completely the same as a normal ViewPager
Having understood what you want to achieve, here's how you'd achieve it!
There are 6 fragments in total.
Home
Left
Right
Top
Botton
Controller
Update
The previous method overrides and prevents horizontal gestures from being captured. I've searched a bit and found an alternative.
First of all, you need a different vertical pager library. I tried the one here and it works perfectly.
So what you wanna do is, get that java file on your project and change your controller's XML like this
<?xml version="1.0" encoding="utf-8"?>
<c.kristofer.jax2.VerticalPager xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/am_scrollView"
android:layout_width="match_parent"
android:layout_height="match_parent">
<fragment
android:id="#+id/top"
class="c.kristofer.jax2.Fragments.SettingsFragment"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<fragment
android:id="#+id/home"
class="c.kristofer.jax2.Fragments.HomeFragment"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<fragment
android:id="#+id/bottom"
class="c.kristofer.jax2.Fragments.SettingsFragment"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</c.kristofer.jax2.VerticalPager>
This ViewPager does not take an adapter, rather it takes <fragment> tags for its child views. The Controller's java code will also change a bit
VerticalPager verticalViewPager = view.findViewById(R.id.am_scrollView);
verticalViewPager.snapToPage(1);
The result can be seen here. You can play around with the code and see what suits you best.
Previous Method
The activity will have one of the ViewPagers, either the Horizontal one or the Vertical one. The middle fragment of that ViewPager will be the Controller. Controller will be responsible for the second ViewPager. The middle fragment of this ViewPager will be Home.
This way, you will have 2 degrees of freedom from the Activity, and 2 degrees of freedom from the Controller.
My application consists of an ActivityHome using TabLayout and SectionsPagerAdapter extends FragmentPagerAdapter to insert placeholder in two internal fragment (FragmentLeft and FragmentRight).
The ActivityHome loads data from the database and passes them through bundle in the two fragment using the method getItem from the SectionsPagerAdapter (pretty much a base SectionsPagerAdapter)
The FragmentRight creates a popup that contains within it another fragment (FragmentPopup). This fragment give at the user the possibility to make change and save all to the database through UPDATE query
This data is displayed in FragmentLeft and FragmentRight, I would like update them when the database is updated via FragmentPopup.
For this I defined a interface in the FragmentPopup (interfaceDataFragmentPopUpToActivity), that interface is implemented in the HomeActivity. Through this interface the ActivityHome sees that the data has been modified and updates the datas that will then be passed at the two fragment. This update of the datas is performed in ActivityHome with the implementation of the method of my interface.
In addition I have overwritten the notifyDataSetChanged() method of my SectionsPagerAdapter class for try to update the two fragment.
The problem is that I can not recharge the fragments (I'm interested above all the FragmentLeft) properly.
This is a little part of the code of the MainActivity
public class ActivityHome extends AppCompatActivity InterfaceDataFragmentPopUpToActivity {
private SectionsPagerAdapter mSectionsPagerAdapter;
private ViewPager mViewPager;
private Bundle bundle;
private FragmentLeft fragmentLeft;
private FragmentRight fragmentRight;
#Override
protected void onCreate(Bundle savedInstanceState) {
...
// Set up the ViewPager with the sections adapter.
mSectionsPagerAdapter = new SectionsPagerAdapter(getSupportFragmentManager());
mViewPager = (ViewPager) findViewById(R.id.container);
mViewPager.setAdapter(mSectionsPagerAdapter);
TabLayout tabLayout = (TabLayout) findViewById(R.id.tabs);
tabLayout.setupWithViewPager(mViewPager);
...
}
//method from my interface
#Override
public void updateData(Boolean changeData) {
if (changeData) {
...
Load data from database;
...
bundle = new Bundle();
bundle.putParcelable("dataPass", dataPass);
mViewPager.getAdapter().notifyDataSetChanged();
}
}
//My SectionsPagerAdapter inside the java file of the ActivityHome
public class SectionsPagerAdapter extends FragmentPagerAdapter {
private Bundle bundleAdapter;
#Override
public int getItemPosition(Object object) {
return POSITION_NONE;
}
public SectionsPagerAdapter(FragmentManager fm, Bundle bundleAdapter) {
super(fm);
this.bundleAdapter = bundleAdapter;
}
//this is one of the latest tests carried out to update the Fragment
#Override
public void notifyDataSetChanged(){
this.bundleAdapter = bundle;
fragmentLeft = new FragmentLeft();
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
fragmentLeft.setArguments(bundle);
ft.replace(R.id.your_placeholder, fragmentLeft);
ft.commit();
}
#Override
public Fragment getItem(int position) {
fragmentLeft = new FragmentLeft();
fragmentRight = new FragmentRight();
fragmentLeft.setArguments(bundleAdapter);
fragmentRight.setArguments(bundleAdapter);
switch (position) {
case 0:
return fragmentLeft;
case 1:
return fragmentRight;
default:
return fragmentLeft;
}
}
#Override
public int getCount() {
// Show 2 total pages.
return 2;
}
#Override
public CharSequence getPageTitle(int position) {
// Replace blank spaces with image icon
SpannableString sb = new SpannableString(tabTitles[position]);
return sb;
}
}
The ActivityHome layout:
<?xml version="1.0" encoding="utf-8"?>
<android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/drawer_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
tools:openDrawer="start">
<android.support.design.widget.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="#style/AppTheme.AppBarOverlay">
<android.support.v7.widget.Toolbar
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
app:popupTheme="#style/AppTheme.PopupOverlay" />
<android.support.design.widget.TabLayout
android:id="#+id/tabs"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</android.support.design.widget.AppBarLayout>
<android.support.v4.view.ViewPager
android:id="#+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="#string/appbar_scrolling_view_behavior" />
<FrameLayout
android:id="#+id/your_placeholder"
android:layout_width="match_parent"
android:layout_height="match_parent"></FrameLayout>
<android.support.design.widget.NavigationView
android:id="#+id/nav_view"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="start"
android:fitsSystemWindows="true"
app:menu="#menu/activity_home_drawer" />
</android.support.v4.widget.DrawerLayout>
SOLVED
i have find the solution in this post Remove Fragment Page from ViewPager in Android
I have change FragmentPageAdapter with `FragmentStatePageAdapater
and Override this method:
#Override
public int getItemPosition(Object object) {
//FragmentLeft is the class for the first fragment in the view
//recreate only FragmentLeft
if (object instanceof FragmentLeft) {
return POSITION_NONE;
}
return 1;
}
I propose again the explanation
Why this solution works
Overriding getItemPosition():
When notifyDataSetChanged() is called, the adapter calls the notifyChanged() method of the ViewPager which it is attached to. The ViewPager then checks the value returned by the adapter's getItemPosition() for each item, removing those items which return POSITION_NONE (see the source code) and then repopulating.
1.How you are sending new data to your view pager adapter(i.e SectionsPagerAdapter ).I think you are not sending new data to refresh the adapter
My Suggestion: Please try like this
Please create one function(Ex: refreshData(Bundle bundleAdapter)) in adapter(SectionsPagerAdapter) class .
so by using that function you can send the new data to adpater from your updateData() method
mSectionsPagerAdapter .refreshData(bundleAdapter)
mSectionsPagerAdapter .notifyDataSetChanged();
Please keep my old logic and now remove the default case from getItem() switch case: change the logi like below
public Fragment getItem(int position) {
switch (position) {
case 0:
FragmentLeft fragmentLeft = new FragmentLeft();
fragmentLeft.setArguments(bundleAdapter);
return fragmentLeft;
case 1:
FragmentRight fragmentRight = new FragmentRight();
fragmentRight.setArguments(bundleAdapter);
return fragmentRight;
}
}
SOLVED
i have find the solution in this post Remove Fragment Page from ViewPager in Android
I have change FragmentPageAdapter with `FragmentStatePageAdapater
and Override this method:
#Override
public int getItemPosition(Object object) {
//FragmentLeft is the class for the first fragment in the view
//recreate only FragmentLeft
if (object instanceof FragmentLeft) {
return POSITION_NONE;
}
return 1;
}
I propose again the explanation
Why this solution works
Overriding getItemPosition():
When notifyDataSetChanged() is called, the adapter calls the notifyChanged() method of the ViewPager which it is attached to. The ViewPager then checks the value returned by the adapter's getItemPosition() for each item, removing those items which return POSITION_NONE (see the source code) and then repopulating.
I have a FragmentActivity with the following xml:
<?xml version="1.0" encoding="utf-8"?>
<android.support.v4.view.ViewPager
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/pager"
android:layout_width="match_parent"
android:layout_height="match_parent" />
and the view pager class is as follows:
public class MyPagerAdapter extends FragmentStatePagerAdapter {
public MyPagerAdapter(FragmentManager fm) {
super(fm);
}
#Override
public Fragment getItem(int i) {
switch (i) {
case 0:
// profile fragment activity
Fragment f = new ProfileFragment();
return new ProfileFragment();
case 1:
// radar fragment activity
return new RadarFragment();
case 2:
// matches fragment activity
return new MatchesFragment();
}
return null;
}
#Override
public int getCount() {
return 3;
}
}
I also have a BroadcastReceiver class that has an instance variable of my custom FragmentActivity. Through this instance variable I would like to obtain any of the fragments above. I understand there are FragmentManager.findFragmentById() and findFragmentByTag() methods but I cant seem to find a way of using that in this case.
Since you only have 3 pages (3 fragments), I recommend that you use the FragmentPagerAdapter rather than the FragmentStatePagerAdapter. Then, you can use findFragmentByTag to find your fragments - read more about that in This SO question.
I got 3 navigation tabs with 3 different fragments in them.
How to add swipe between the fragments?
Android made something for this exact reason called ViewPager!
in your onCreate method, do something like this:
pager = (ViewPager) findViewById(R.id.pager);
adapter = new MyPagerAdapter(getSupportFragmentManager());
pager.setAdapter(adapter);
then,
Include the following into your MainActivity:
public class MyPagerAdapter extends FragmentStatePagerAdapter {
SparseArray<Fragment> registeredFragments = new SparseArray<Fragment>();
private final String[] TITLES = getResources().getStringArray(R.array.tabs);
public MyPagerAdapter(FragmentManager fm) {
super(fm);
}
#Override
public CharSequence getPageTitle(int position) {
return TITLES[position];
}
#Override
public int getCount() {
return TITLES.length;
}
#Override
public Fragment getItem(int position) {
switch(position) {
case 0: return OneFragment.newInstance(position);
case 1: return TwoFragment.newInstance(position);
case 2: return ThreeFragment.newInstance(position);
}
return null;
}
#Override
public Object instantiateItem(ViewGroup container, int position) {
Fragment fragment = (Fragment) super.instantiateItem(container, position);
registeredFragments.put(position, fragment);
return fragment;
}
#Override
public void destroyItem(ViewGroup container, int position, Object object) {
registeredFragments.remove(position);
super.destroyItem(container, position, object);
}
public Fragment getRegisteredFragment(int position) {
return registeredFragments.get(position);
}
}
The code I posted is code I use. It is more sophisticated than usual. It keeps track of the Fragments (each tab), allowing you to access Fragments from one another. So if you were in OneFragment, and wanted access to TwoFragment, you'd do something like:
in OneFragment
private void getTwoFragmentData() {
data = (MainActivity) getActivity.getTwoFragmentData();
}
in MainActivity
public Data getTwoFragmentData() {
TwoFragment twoFragment = (TwoFragment) adapter.getRegisteredFragment(1);
return twoFragment.getData();
}
Data above is just a placeholder for however you would interface with it, but the above code is the general structure of how you'd do it.
Also, you would edit the getItem method. And make the switch, case accordingly.
As an extra, you could do pager.setOffScreenPageLimit(x), to also load the content x tabs away from your current tab, which is useful for retaining information. For 3 tabs, I would use x = 2, but ultimately, be wary because that is extra memory used.
Finally, the last little extra is that I use a library called com.astuetz.PagerSlidingTabStrip which is awesome for getting the bar underneath the tabs to swipe with you and make it look really clean. Adding it is very simple and you'll find more details here
My activity_main.xml looks like this:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<!-- <com.astuetz.PagerSlidingTabStrip -->
<!-- android:id="#+id/tabs" -->
<!-- android:layout_width="match_parent" -->
<!-- android:layout_height="48dip" /> -->
<android.support.v4.view.ViewPager
android:id="#+id/pager"
android:layout_width="match_parent"
android:layout_height="wrap_content"
<!-- android:layout_below="#+id/tabs" -->
tools:context=".MainActivity" />
</RelativeLayout>
Ignore the commented out stuff. That is what I use in addition to get the library I stated above integrated.