Android - One activity multiple fragments for tabs screen - android

I want to create an app. First page is a login page, then second page is a tabbad screen. I use BottomNavigationView to create a tab bar.
I want to give toolbar to each page. So, I put a Toolbar in fragment's layout.
But I have some problems:
If I add bottom navigation view to activity, I cannot use any transition animation from login to tab bar page.
If I add bottom navigation view to fragment and replace fragment by using childFragmentManager when bottom navigation view item is selected, childFragmentManager doesn't hide parent fragment's toolbar.
For second case, parent Fragment toolbar overlays child fragment toolbar.
getChildFragmentManager().beginTransaction().replace(R.id.rootFragmentLayout, fragment).commit();
Fragment layout is below:
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
>
<LinearLayout
android:orientation="vertical"
android:id="#+id/rootFragmentLayout"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.design.widget.AppBarLayout
android:id="#+id/toolBarLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<android.support.v7.widget.Toolbar
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"/>
</android.support.design.widget.AppBarLayout>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_below="#+id/toolBarLayout"
app:layout_behavior="#string/appbar_scrolling_view_behavior">
</FrameLayout>
</LinearLayout>
</RelativeLayout>

If i understood it correctly, one Activity will house multiple fragments with only one toolbar. What you can do is use ViewPager to change between fragments. You'll need a ViewPager on your xml below your toolbar and then you can create a adapter that switches fragments for you.
In this example you supposedly have buttons to switch your fragments, as i call it btn1, btn2 and btn3 on the code
activity.xml
<android.support.design.widget.AppBarLayout
android:id="#+id/appbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="#style/AppTheme.AppBarOverlay">
<include layout="#layout/your_toolbar" />
</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" />
</android.support.design.widget.CoordinatorLayout>
Activity.java
import android.support.v4.view.ViewPager;
import android.support.v7.app.AppCompatActivity;
public class mActivity extends AppCompatActivity implements ViewPager.OnPageChangeListener {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity);
ButterKnife.bind(this);
adapter = new MyPagerAdapter(getSupportFragmentManager());
container.setAdapter(adapter);
container.addOnPageChangeListener(this);
// This means 3 fragments, change the number as you like
container.setOffscreenPageLimit(3);
container.setCurrentItem(1);
}
// Use this method so your toolbar views switch the fragments
#OnClick({R.id.btn1, R.id.btn2, R.id.btn3})
public void onViewClicked(View view) {
switch (view.getId()) {
case R.id.btn1:
container.setCurrentItem(0, true);
break;
case R.id.btn2:
container.setCurrentItem(1, true);
break;
case R.id.btn3:
container.setCurrentItem(2, true);
break;
}
}
}
PagerAdapter.java
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentStatePagerAdapter;
public class MyPagerAdapter extends FragmentStatePagerAdapter {
public MyPagerAdapter(FragmentManager fm) {
super(fm);
}
#Override
public Fragment getItem(int pos) {
switch (pos) {
case 0:
return new YourFragmentClass1();
case 1:
return new YourFragmentClass2();
case 2:
return new YourFragmentClass3();
default:
return new YourFragmentClass1();
}
}
#Override
public int getCount() {
return 3;
}
#Override
public int getItemPosition(Object object) {
return POSITION_NONE;
}
}

Related

Android fragment replacement

I have a fragment called ProjectsFragment, that has a constraintLayout, recyclerView and a FloatingActionButton.
I'm trying to make it when I click the button to go to another fragment.
The new fragment is called NewProjectFragment.
The code that I've got so far is below but it's not being replaced. I know the code is being ran as the log is printed
FloatingActionButton fab = view.findViewById(R.id.floatingActionButton);
fab.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
NewProjectFragment npf = new NewProjectFragment();
FragmentTransaction transaction = getActivity().getSupportFragmentManager().beginTransaction();
transaction.replace(R.id.constraintLayout, npf);
transaction.addToBackStack(null);
transaction.commit();
Log.d("swap", "swap");
}
});
The tabs are setup using the below on the MainActivity
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ViewPager viewPager = (ViewPager) findViewById(R.id.viewpager);
SimpleFragmentPagerAdapter adapter = new SimpleFragmentPagerAdapter(this, getSupportFragmentManager());
viewPager.setAdapter(adapter);
TabLayout tabLayout = (TabLayout) findViewById(R.id.sliding_tabs);
tabLayout.setupWithViewPager(viewPager);
}
The SimpleFragmentPageAdapter is below
public class SimpleFragmentPagerAdapter extends FragmentPagerAdapter {
private Context mContext;
public SimpleFragmentPagerAdapter(Context context, FragmentManager fm) {
super(fm);
mContext = context;
}
// This determines the fragment for each tab
#Override
public Fragment getItem(int position) {
if (position == 0) {
return new ProjectsFragment();
} else if (position == 1) {
return new ColoursFragment();
} else if (position == 2) {
return new WishListFragment();
} else if (position == 3) {
return new AboutFragment();
} else {
return new ProjectsFragment();
}
}
// This determines the number of tabs
#Override
public int getCount() {
return 4;
}
// This determines the title for each tab
#Override
public CharSequence getPageTitle(int position) {
// Generate title based on item position
switch (position) {
case 0:
return mContext.getString(R.string.project_tab);
case 1:
return mContext.getString(R.string.colours_tab);
case 2:
return mContext.getString(R.string.wish_list_tab);
case 3:
return mContext.getString(R.string.about_tab);
default:
return null;
}
}
}
The ActivityMain.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<android.support.design.widget.TabLayout
android:id="#+id/sliding_tabs"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:tabMode="fixed" />
<android.support.v4.view.ViewPager
android:id="#+id/viewpager"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#android:color/white" />
</LinearLayout>
And the fragment_projects.xml
<android.support.constraint.ConstraintLayout 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"
tools:context=".ui.main.ProjectsFragment"
android:id="#+id/constraintLayout" >
<android.support.design.widget.FloatingActionButton
android:id="#+id/floatingActionButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="16dp"
android:layout_marginRight="16dp"
android:layout_marginBottom="16dp"
android:clickable="true"
android:src="#drawable/ic_add_black_24dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent" />
<android.support.v7.widget.RecyclerView
android:id="#+id/recyclerView"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="1.0"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="1.0">
</android.support.v7.widget.RecyclerView>
</android.support.constraint.ConstraintLayout>
transaction.replace(R.id.constraintLayout, npf);
Looks like you're trying to replace into a constraint layout, which smells funny to me. Usually you have a FrameLayout that is a simple container for the fragments. Thus, my guess would be that you are moving the new fragment into the existing fragment's layout, without constraints, so it's not showing up and the first one remains in place.
Make sure you're using the ID of the view in the layout that contains the first fragment (again, usually a FrameLayout in the owning Actvity layout).
If that is not your issue, post your XML file.
Update.
Yeah, as I guessed, you're replacing into a ConstraintLayout and that's not a good idea, as you've seen. Your setup is a bit weird because you have a ViewPager that is managing one set of fragments and you want to push a new one over everything?
I'd suggest you just launch a new Activity instead.

BottomNavigation initial setCurrentItem not showing fragment and relaunching fragment fails

I have a Main Activity which uses a TabSelectedListener to show fragments for the AHBottomNavigation menu. The fragment called "FirstFragment" contains a FragmentPagerAdapter which allows the user to swipe between two tabs, each of which have its own fragment, called FirstTabInFirstFragmentFragment and SecondTabInFirstFragmentFragment (renamed for simplicity).
My issue is that:
a). When the Main Activity is launched, the "First" Bottom Navigation menu item is selected, however the "FirstFragment" is not launched. So, it shows the proper item selected with a blank screen. It only launches the First Fragment if I tap on the menu item again.
b). Once the FirstFragment has been properly launched and is being shown on screen (by the temporary fix done in a), if I select a different menu item (i.e. to navigate to SecondFragment) and then select the FirstFragment's menu item again, the two tabs within it are blank. Also, the sliding between the fragments for the two tabs does not work and gets "stuck" so you have to pull it all the way to one side or all the way to the other.
Hopefully I have explained my problem clearly - if there is anything I'm missing, I can provide more details.
Note that I am using com.aurelhubert.ahbottomnavigation.AHBottomNavigation
Here are the relevant files:
MainActivity.java:
public class MainActivity extends AppCompatActivity{
private AHBottomNavigationAdapter navigationAdapter;
private AHBottomNavigationViewPager viewPager;
private AHBottomNavigation bottomNavigation;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// Add menu items to bar
bottomNavigation = (AHBottomNavigation) findViewById(R.id.bottom_navigation);
this.createNavItems();
bottomNavigation.setOnTabSelectedListener(new AHBottomNavigation.OnTabSelectedListener() {
#Override
public boolean onTabSelected(int position, boolean wasSelected) {
//show fragment
if (position==0)
{
FirstFragment firstFragment=new FirstFragment();
getSupportFragmentManager().beginTransaction().replace(R.id.content_id,firstFragment).commit();
}else if (position==1)
{
SecondFragment secondFragment=new SecondFragment();
getSupportFragmentManager().beginTransaction().replace(R.id.content_id, secondFragment).commit();
}else if (position==2)
{
ThirdFragment thirdFragment=new ThirdFragment();
getSupportFragmentManager().beginTransaction().replace(R.id.content_id,thirdFragment).commit();
}else{
FourthFragment fourthFragment=new FourthFragment();
getSupportFragmentManager().beginTransaction().replace(R.id.content_id,fourthFragment).commit();
}
return true;
}
});
}
private void createNavItems(){
navigationAdapter = new AHBottomNavigationAdapter(this, R.menu.navigation);
navigationAdapter.setupWithBottomNavigation(bottomNavigation);
// set current item
bottomNavigation.setCurrentItem(0);
}
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/content_id"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.aurelhubert.ahbottomnavigation.AHBottomNavigation
android:id="#+id/bottom_navigation"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="bottom"/>
</android.support.design.widget.CoordinatorLayout>
FirstFragment.java:
public class FirstFragment extends Fragment {
private FragmentActivity mContext;
public FirstFragment() {
// Required empty public constructor
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_first, container, false);
}
#Override
public void onActivityCreated(#Nullable Bundle savedInstanceState){
super.onActivityCreated(savedInstanceState);
// Set the content of the activity to use the activity_main.xml layout file
//setContentView(R.layout.activity_first);
// Find the view pager that will allow the user to swipe between fragments
ViewPager viewPager = (ViewPager) getView().findViewById(R.id.viewpager);
// Create an adapter that knows which fragment should be shown on each page
// using getFragmentManager() will work too
FirstFragmentPagerAdapter adapter = new FirstFragmentPagerAdapter(mContext.getSupportFragmentManager(), mContext);
// Set the adapter onto the view pager
viewPager.setAdapter(adapter);
TabLayout tabLayout = (TabLayout) getView().findViewById(R.id.sliding_tabs);
tabLayout.setupWithViewPager(viewPager);
}
/**
* Override to set context. This context is used for getSupportFragmentManager in onCreateView
* #param activity
*/
#Override
public void onAttach(Activity activity) {
mContext=(FragmentActivity) activity;
super.onAttach(activity);
}
}
fragment_first.xml:
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout 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"
>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<android.support.design.widget.TabLayout
android:id="#+id/sliding_tabs"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:tabMode="fixed"
app:tabBackground="#color/firstTabBackground"
app:tabIndicatorColor="#color/firstTabIndicatorColor"/>
<android.support.v4.view.ViewPager
android:id="#+id/viewpager"
android:layout_width="match_parent"
android:layout_height="0px"
android:layout_weight="1"/>
</LinearLayout>
</android.support.constraint.ConstraintLayout>
FirstFragmentPagerAdapter.java:
public class FirstFragmentPagerAdapter extends FragmentPagerAdapter {
private Context context;
public FirstFragmentPagerAdapter(FragmentManager fm, Context mContext){
super(fm);
context = mContext;
}
/**
* The ViewPager asks the adapter for the fragment at a given position,
* i.e. for the 1st fragment, the ViewPager asks for the fragment at
* position 1.
* #param position
* #return
*/
#Override
public Fragment getItem(int position){
if (position == 0){
return new FirstTabInFirstFragmentFragment();
}
else{
return new SecondTabInFirstFragmentFragment();
}
}
/**
* On launch, the ViewPager asks the adapter how many pages there will be.
* Here, our adapter returns how many pages there will be.
* #return
*/
#Override
public int getCount() {return 2;}
#Override
public CharSequence getPageTitle(int position) {
switch(position){
case 0:
return context.getResources().getString(R.string.first_tab_in_first_fragment_page_title);
case 1:
return context.getResources().getString(R.string.second_tab_in_first_fragment_page_title);
default:
return null;
}
}
}
I was able to solve this in two steps. First, in my Main Activiy method createNavItems, in addition to doing a bottomNavigation.setCurrentItem(0);, I also had to manually update the CoordinatorLayout (which has ID content_id) with the default fragment:
getSupportFragmentManager().beginTransaction().replace(R.id.content_id, new FirstFragment()).commit();
Next, to solve the TabLayout issues I had to change this line:
FirstFragmentPagerAdapter adapter = new FirstFragmentPagerAdapter(mContext.getSupportFragmentManager(), mContext);
to
FirstFragmentPagerAdapter adapter = new FirstFragmentPagerAdapter(getChildFragmentManager(), mContext);
The reason for this is that when nesting Fragments inside of other Fragments with ViewPager, getFragmentManager() is for managing Fragments within a Fragment whereas mContext.getSupportFragmentManager() is used for Activities.
Firstly, Inorder to initially load the frstfragment on startup, u have to define the frstfragments view as default view to mainactivitys view.
Secondly, you need to have a framelayout to load the views for each fragment when selecting bottomnavigation menu.. here you are simply replacing the parent layout of mainactivity, which is a wrong concept, i believe.
So you need to create a child framelayout to load fragment views for each bottomnavigation menu items.
edits:
my layout which contains bottomnavigation,
<?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:id="#+id/content_home"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="#string/appbar_scrolling_view_behavior"
tools:showIn="#layout/app_bar_home"
android:keepScreenOn="false">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="#+id/ll_toolbar_home_search">
<android.support.v7.widget.Toolbar
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?attr/colorPrimary">
<LinearLayout
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="30dp"
android:background="#drawable/btn_style_white"
android:layout_marginRight="10dp">
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="#drawable/ic_search"/>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="10dp"
android:text="Search 18000+ products"
android:id="#+id/tv_search_home"/>
</LinearLayout>
</android.support.v7.widget.Toolbar>
</LinearLayout>
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_below="#id/ll_toolbar_home_search"
android:layout_above="#+id/navigation"
android:id="#+id/frame_layout_fragment"
android:background="#color/white">
</FrameLayout>
<com.aurelhubert.ahbottomnavigation.AHBottomNavigation
android:id="#+id/navigation"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true" />
</RelativeLayout>
and java class for that activity( only method that contains bottomnavigation manipulations) is follows:
private void BottomView1() {
navigation = (AHBottomNavigation) findViewById(R.id.navigation);
AHBottomNavigationItem item1 = new AHBottomNavigationItem("Home", R.drawable.ic_home, R.color.ash);
AHBottomNavigationItem item2 = new AHBottomNavigationItem("Category", R.drawable.ic_category, R.color.ash);
AHBottomNavigationItem item3 = new AHBottomNavigationItem("Search", R.drawable.ic_search, R.color.ash);
AHBottomNavigationItem item4 = new AHBottomNavigationItem("Offers", R.drawable.ic_offers, R.color.ash);
AHBottomNavigationItem item5 = new AHBottomNavigationItem("Cart", R.drawable.ic_cart, R.color.ash);
navigation.addItem(item1);
navigation.addItem(item2);
navigation.addItem(item3);
navigation.addItem(item4);
navigation.addItem(item5);
navigation.setCurrentItem(getResources().getColor(R.color.colorPrimaryDark));
navigation.setTitleState(AHBottomNavigation.TitleState.ALWAYS_SHOW);
setCartNotification();
navigation.setAccentColor(getResources().getColor(R.color.colorPrimaryDark));
navigation.setOnTabSelectedListener(new AHBottomNavigation.OnTabSelectedListener() {
#Override
public boolean onTabSelected(int position, boolean wasSelected) {
Intent ii ;
Fragment selectedFragment = null;
if(position==0){
selectedFragment = HomeFragment.newInstance();
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
transaction.replace(R.id.frame_layout_fragment, selectedFragment);
transaction.commit();
} else if(position==1){
ii = new Intent(HomeActivity.this, ShopByCategoryActivity.class);
startActivity(ii);
} else if(position==2){
ii = new Intent(HomeActivity.this, SearchActivity.class);
startActivity(ii);
} else if(position==3){
ii = new Intent(HomeActivity.this, OffersActivity.class);
startActivity(ii);
} else if(position==4){
ii = new Intent(HomeActivity.this, MyCartActivity.class);
startActivity(ii);
}
return true;
}
});
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
transaction.replace(R.id.frame_layout_fragment, HomeFragment.newInstance());
transaction.commit();
}

View Pager is calling other fragments on startup and on swiping too

List of components in my app is following :
TabLayout - Tab1, Tab2, Tab3.
Fragments for Tabs - Tab1.xml & class, Tab2.xml & class, Tab3.xml & class.
ViewPager to show Fragments on tabs.
So, when app starts as i debugged the startup process, it works like following :
it calls 'Tab1.class',
then it calls 'Tab2.class',
and when swipe from 'Tab1' to 'Tab2', it calls 'Tab3.class'.
and when swipe from 'Tab2' to 'Tab3', it calls nothing.
on reverse swiping :
when swipe from 'Tab3' to 'Tab2', it calls 'Tab1.class'.
then when swipe from 'Tab2' to 'Tab1', it calls nothing.
Questions :
So, why does it do that?
How can i call ONLY 'tab1.class' when app starts on 'tab1'?
How can i call ONLY 'tab2.class' when i swipe from 'tab1' to 'tab2'?
MainActivity.java
public class MainActivity extends AppCompatActivity {
private TabLayout tabLayout;
private ViewPager viewPager;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
viewPager = (ViewPager) findViewById(R.id.viewPager);
PagerAdapter pagerAdapter = new FixedTabsPagerAdapter(getSupportFragmentManager());
viewPager.setAdapter(pagerAdapter);
tabLayout = (TabLayout) findViewById(R.id.tabLayout);
tabLayout.setupWithViewPager(viewPager);
}
class FixedTabsPagerAdapter extends FragmentPagerAdapter {
public FixedTabsPagerAdapter(FragmentManager manager) {
super(manager);
}
#Override
public Fragment getItem(int position) {
switch (position)
{
case 0:
return new Tab1();
case 1:
return new Tab2();
case 2:
return new Tab3();
default:
return null;
}
}
#Override
public int getCount() {
return 3;
}
#Override
public CharSequence getPageTitle(int position) {
switch (position)
{
case 0:
return getString(R.string.tab1);
case 1:
return getString(R.string.tab2);
case 2:
return getString(R.string.tab3);
default:
return null;
}
}
}
}
activity_main.xml
<?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:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="vwc.com.newconcept.MainActivity">
<android.support.design.widget.AppBarLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.v7.widget.Toolbar
android:id="#+id/main_toolbar"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<android.support.v4.view.ViewPager
android:id="#+id/viewPager"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.design.widget.TabLayout
android:id="#+id/tabLayout"
app:tabMode="scrollable"
app:tabGravity="center"
android:layout_gravity="top"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</android.support.v4.view.ViewPager>
</android.support.design.widget.AppBarLayout>
</android.support.v4.widget.DrawerLayout>
Please Do Tell Solution For This Problem.
setOffscreenPageLimit
Set the number of pages that should be retained to either side of the current page in the view hierarchy in an idle state. Pages beyond this limit will be recreated from the adapter when needed.
Hope this helps.
ViewPager mViewpager = (ViewPager)findView....
mViewPager.setOffscreenPageLimit(3);
ViewPager is intented to work in that way to avoid lag in animations while switching from one fragment to other fragment, it will load atleast one extra fragment alongside your Visible Fragment by which it makes sure there is scope to swipe.
because, while swiping view pager has capability to show two fragments simultaneously hence loads the one extra always, without two pages view pager is useless.
For Refresh Fragment When Fragment Visible
#Override
public void setUserVisibleHint(boolean isVisibleToUser) {
super.setUserVisibleHint(isVisibleToUser);
if (getFragmentManager() != null) {
getFragmentManager()
.beginTransaction()
.detach(this)
.attach(this)
.commit();
}
}

How to handle drawer toggle and toolbar up when having toolbar for each fragment

I am using single activity and many fragments approach in my app
Now since in my some fragments I have custom view in toolbar I decided to have separate toolbar for each fragment.
How to implement separate toolbar for each fragment also the drawer layout is in my activity
I have the same problem, I will add custom toolbar view for each fragment.
My Utility method is:
public static View addRemoveViewFromToolbar(FragmentActivity fragmentActivity, int resourceId) {
Toolbar toolbar = removeViewFromToolbar(fragmentActivity);
if (resourceId == 0) {
return null;
} else {
View view = LayoutInflater.from(fragmentActivity).inflate(resourceId, toolbar, false);
toolbar.addView(view);
return view;
}
}
public static Toolbar removeViewFromToolbar(FragmentActivity fragmentActivity) {
Toolbar toolbar = (Toolbar) fragmentActivity.findViewById(R.id.toolbar);
if (toolbar.getChildCount() > 1) {
for (int i = 1; i <= toolbar.getChildCount(); i++) {
toolbar.removeViewAt(1);
}
}
return toolbar;
}
In my each fragment
//Create your custom view based on requirement
View view = Utility.addRemoveViewFromToolbar(getActivity(), R.layout.toolbar_search_view);
if (view != null) {
edtCategory1 = (EditText) view.findViewById(R.id.edtCategory1);
edtCategory1.setOnClickListener(this);
}
Hope this explanation help you :)
I'm not sure if I understood your description of the your app correctly, but I recently did what I think you described.
My activity layout was a DrawerLayout with an included CoordinatorLayout/AppBar layout with a single toolbar and a FrameLayout below. The menu.xml contained all the items I needed in my toolbar for all the fragments. Items clicked in the nav menu would swap out fragments in the FrameLayout. My onNavigationItemSelected() called on this method to swap out the fragments and handle the backstack:
public void switchView(int id, int optArg) {
if (currentView != id) {
currentView = id; //currentView keeps track of which fragment is loaded
FragmentTransaction transaction = getFragmentManager().beginTransaction();
//Fragment contentFragment is the current fragment in the FrameLayout
switch (id) {
case 0: //menu item 1
contentFragment = new Nav_Item1_Fragment();
transaction.replace(R.id.fragment_container, contentFragment, "");
break;
case 1: //menu item 2
contentFragment = new Nav_Item2_Fragment();
transaction.replace(R.id.fragment_container, contentFragment, "");
break;
case 2: //menu item 3
contentFragment = new Nav_Item3_Fragment();
transaction.replace(R.id.fragment_container, contentFragment, "");
break;
}
// Replace whatever is in the fragment_container view with this fragment,
// and add the transaction to the back stack
// transaction.replace(R.id.fragment_container, contentFragment);
transaction.addToBackStack(null);
// Commit the transaction
transaction.commit();
}
}
and in each fragment's onPrepareOptionsMenu() I setVisible() hid/showed the menu items in the toolbar related to that fragment. Each item had an method in the activity pointed to by the menu item's onClick attribute that knew what fragment it was from and what views were passed to it.
The drawer was setup in the onCreate() of the activity with a ActionBarDrawerToggle like so:
drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(
this, drawer, toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close);
drawer.addDrawerListener(toggle);
toggle.syncState();
activity xml:
<android.support.v4.widget.DrawerLayout
android:id="#+id/drawer_layout"
...>
<include
layout="#layout/app_bar_main"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
<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"
.../>
</android.support.v4.widget.DrawerLayout>
app_bar_main.xml
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout
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"
...>
<android.support.design.widget.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
...>
<android.support.v7.widget.Toolbar
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:gravity="top"
.../>
</android.support.design.widget.AppBarLayout>
<FrameLayout
android:id="#+id/fragment_container"
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="#string/appbar_scrolling_view_behavior">
</FrameLayout>
</android.support.design.widget.CoordinatorLayout>
So...One Nav menu, one App/Tool Bar, multiple fragments
Why do you specifically want a separate toolbar for each fragment?
You can easily change the toolbar view for each fragment.
In your function to switch fragments -
public void selectDrawerItem(MenuItem item) {
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction fragmentTransaction;
switch (item.getItemId()) {
case R.id.nav_home :
getSupportActionBar().setCustomView(R.layout.home_nav_bar);
fragmentClass = HomeFragment.class;
break;
case R.id.nav_settings :
getSupportActionBar().setCustomView(R.layout.settings_nav_bar);
fragmentClass = SettingsFragment.class;
break;
}
fragment = (Fragment) fragmentClass.newInstance();
fragmentManager.popBackStack(null,
FragmentManager.POP_BACK_STACK_INCLUSIVE);
fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.replace(R.id.fragment_container, fragment);
fragmentTransaction.addToBackStack(null);
fragmentTransaction.commit();
}
So you can easily use the same toolbar and customize it according to your requirements for each fragment.
It can be done in a quite straightforward way.
First create an activity with a drawerlayout.
Second create a container viewpager inside the activity to hold
the fragments
Third implement a listener on your viewpager that will set the
relevant toolbar based on the fragment on display.
Let me illustrate by relevant XMLs and code
First the Drawerlayout XML for the main activity
<?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">
<include
layout="#layout/app_bar_landing_page"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<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:headerLayout="#layout/nav_header_landing_page"
app:menu="#menu/activity_landing_page_drawer" />
</android.support.v4.widget.DrawerLayout>
Please note the container layout app_bar_landing_page. Now the XML for this
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout 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"
tools:context="me.veganbuddy.veganbuddy.ui.LandingPage">
<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"
android:elevation="4dp"
app:logo="#drawable/vegan_buddy_menu_icon"
app:popupTheme="#style/AppTheme.PopupOverlay" />
</android.support.design.widget.AppBarLayout>
<android.support.v4.view.ViewPager
android:id="#+id/container_for_fragments"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="#string/appbar_scrolling_view_behavior" />
</android.support.design.widget.CoordinatorLayout>
Note the viewpager which will act as container for fragments. Now the OnPageChangeListener on the viewpager.
mViewPager = (ViewPager) findViewById(R.id.container_for_fragments);
mViewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
#Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
}
#Override
public void onPageSelected(int position) {
switch (position+1){
case 0:setSupportActionBar(aToolbar);
break;
case 1:setSupportActionBar(bToolbar);
break;
case 2:setSupportActionBar(cToolbar);;
break;
case 3:setSupportActionBar(dToolbar);
break;
default:
break;
}
}
Let me know if any further clarification is needed
The simplest approach I would suggest is to use callbacks to activity. Whenever each fragment loads in the activity, arrange a callback to the activity and load the appropriate toolbar in the activity.
Have separate toolbar xmls in your layout folder. Use the include tag to put the toolbars in your activity. Keep only 1 toolbar visible at a time. When the fragment callbacks come to your activity make the necessary one visible.
It's very simple. Besides the onclick action for the Category fragment is taking you into a new activity, not a Fragment. Now, since drawer layout is in parent activity with navigation view and without toolbar then in the first drawer fragment is a tablayout having four tabs with viewpager and a toolbar on the top and inside one tab i.e HOME is the TOP CHARTS, CATEGORIES, EDITORS. Each toolbar must be implemented in each fragment layout and not in the activity layout since you want different toolbars for each fragment. Note that Toolbar is not a property of Fragment but it's a property of ActionBarActivity or AppCompatActivity, then in the onCreateView, of the fragment that's holding the HOME, GAMES, MOVIES, MUSIC, put down these codes.
public class Drawer1Fragment extends Fragment{
public Drawer1Fragment () {}
TabLayout tabLayout;
Toolbar toolbar;
DrawerLayout drawerLayout;
ViewPager viewPager;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState){
View myChildRoot = inflater.inflate(R.layout.child_fragment_attachment, container, false);
tabLayout = myChildRoot.findViewById(R.id.tab_layout);
viewPager= myChildRoot.findViewById(R.id.container_viewPager);
toolbar = myChildRoot.findViewById(R.id.toolbar);
drawerLayout = getActivity().findViewById(R.id.drawer_layout);
((AppCompatActivity)requireActivity()).setSupportActionBar(toolbar);
((AppCompatActivity)requireActivity()).getSupportActionBar().setTitle(getActivity().getResources().getString(R.string.app_name));
((AppCompatActivity)requireActivity()).getSupportActionBar().setHomeButtonEnabled(true);
((AppCompatActivity)getParentFragment().requireActivity()).getSupportActionBar().setDisplayHomeAsUpEnabled(true);
ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(getActivity(),drawerLayout,toolbar,R.drawable.icons,R.string.app_name);
drawerLayout.addDrawerListener(toggle);
toggle.syncState();
// The back arrow of a toolbar in fragment is implemented below
toolbar.setNavigationOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view)
{
if(!drawerLayout.isDrawerOpen(GravityCompat.START)) {
drawerLayout.openDrawer(GravityCompat.START);
} else {
getActivity().finish();
}
}
});
return myChildRoot;
}
}

Update A ListView In One Fragment From A Second Fragment

I have a ViewPager that shows the user 2 fragments.
Fragment 1 contains a button with an onClickListener that adds an entry to the ListView contents in fragment 2. The new entry is a number generated by a random number generator.
Fragment 2 contains a ListView with some random numbers in.
I cannot find a way to refresh the list in fragment 2 from the button listener in fragment 1. How do i do this?
I have tried:
initializing and setting the list adapter in an onResume in
fragment 2.
Calling myViewPager.notifyDataSetChanged from fragment 1.
Neither of the above methods have worked. Any ideas?
Edit: Here is my code:
layout_main.xml
<android.support.v4.view.ViewPager
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/mainpager"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
layout_frag_one.xml
<RelativeLayout
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" >
<Button
android:id="#+id/main_button"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:text="Add Number" />
</RelativeLayout>
layout_frag_two
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<ListView
android:id="#+id/list"
android:layout_width="match_parent"
android:layout_height="wrap_content">
</ListView>
</LinearLayout>
MainActivity
public class SlideActivity extends FragmentActivity {
private final static int FRAGMENT_NUMBER = 2;
private ViewPager pager;
protected void onCreate(Bundle savedInstanceState) {
setContentView(R.layout.activity_mainpager);
pager = (ViewPager) findViewById(R.id.mainpager);
pager.setAdapter(new ViewPagerAdapter(getSupportFragmentManager()));
super.onCreate(savedInstanceState);
}
private class ViewPagerAdapter extends FragmentStatePagerAdapter {
public ViewPagerAdapter(FragmentManager fm) {
super(fm);
}
public Fragment getItem(int index) {
switch(index){
case 0:
return new Fragment1();
case 1:
return new Fragment2();
default:
return new Fragment1();
}
}
public int getCount() {
return FRAGMENT_NUMBER;
}
}
}
You may need to implement some of this to get it working right:
http://developer.android.com/training/basics/fragments/communicating.html
And some more reading here:
http://developer.android.com/guide/components/fragments.html#CommunicatingWithActivity

Categories

Resources