Android fragment transaction with SlidingTabLayout not working in API level < 21 - android

in my app I have an ActionBarActivity (I'm using support library with AppCompat) that uses the SlidingTabLayout class from Google (taken from here). So this is the XML code of the activity's layout:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/activity_series_details"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".SeriesDetailsActivity">
<com.my.package.SlidingTabLayout
android:id="#+id/series_details_tabs"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:elevation="2dp"
android:background="#color/primary_material_dark" />
<android.support.v4.view.ViewPager
android:id="#+id/series_details_pager"
android:layout_height="0dp"
android:layout_width="match_parent"
android:layout_weight="1" />
</LinearLayout>
In this activty, when user press an option in the action bar, I want to add a Fragment with a custom animation. This is the code that handle menu click:
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
/* ... OTHER CASES ... */
case R.id.menu_voption:
newFragment = MyNewFragment.newInstance();
getSupportFragmentManager().beginTransaction()
.setCustomAnimations(
R.anim.slide_up,
R.anim.slide_down
)
.add(R.id.activity_series_details, newFragment)
.commit();
editing = true;
break;
default:
return super.onOptionsItemSelected(item);
}
return true;
Doing this, my new fragment is correctly added to the activty and replace the currente fragment but not tab layout, tha remains visible. So I've tryed to add this line before start transaction:
tabsHost.setVisibility(View.GONE);
where tabsHost is the SlidingTabLayout. With this modification, the tabs layout disappear and the new fragment is correctly shown, but only in the API Level >= 21. In my Samsung Galaxy S4 (that runs API 19) and in all other emulators with lesser API level than 21 (my target is 11+), the tabs layout disappear but new fragment is not visible. I'm pretty sure is my fault, but I can't figure why. Thanks all for attention.

Since the SlidingTabLayout is not a fragment, it cannot be managed by the FragmentManager. You would have to make it part of a fragment and add it to your Activity. This is possible with getChildFragmentManager.
Move your activity layout to a fragment:
activity_main.xml
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/activity_series_details"
android:layout_width="match_parent"
android:layout_height="match_parent">
</FrameLayout>
fragment_sliding_tab.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/activity_series_details"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<com.my.package.SlidingTabLayout
android:id="#+id/series_details_tabs"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:elevation="2dp"
android:background="#color/primary_material_dark" />
<android.support.v4.view.ViewPager
android:id="#+id/series_details_pager"
android:layout_height="0dp"
android:layout_width="match_parent"
android:layout_weight="1" />
</LinearLayout>
SlidingTabFragment.java
public class SlidingTabFragment extends Fragment {
private PagerAdapter mPagerAdapter;
private ViewPager mViewPager;
public static SlidingTabFragment newInstance() {
SlidingTabFragment fragment = new SlidingTabFragment();
return fragment;
}
public SlidingTabFragment() {
// Required empty public constructor
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
}
#Override
public void onViewCreated(View view, #Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
mPagerAdapter = new PagerAdapter(getChildFragmentManager());
// Set up the ViewPager with the sections adapter.
mViewPager = (ViewPager) view.findViewById(R.id.series_details_pager);
mViewPager.setAdapter(mSectionsPagerAdapter);
SlidingTabLayout tabs = (SlidingTabLayout) view.findViewById(R.id.series_details_tabs);
tabs.setViewPager(mViewPager);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_sliding_tab, container, false);
}
}
Add your fragment in your Activity's onCreate:
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Fragment slidingTabFragment = SlidingTabFragment.newInstance();
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
transaction.replace(R.id.activity_series_details, slidingTabFragment).commit();
}

Related

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();
}

how to call fragment from another fragment in tablayout with viewpager

I want to call a fragment on button click which is a fragment. I tried this code but it's not working. with this code when I click on the button it shows next fragment but not its designing. I see only a blank page.
This is my main xml :-
<LinearLayout
android:id="#+id/main_layout"
android:orientation="vertical"
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=".MainActivity">
<!-- our toolbar -->
<!-- our tablayout to display tabs -->
<android.support.design.widget.TabLayout
android:id="#+id/tabLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:tabMode="scrollable"
app:tabGravity="fill"
android:background="#fa4022"
android:minHeight="?attr/actionBarSize"
android:theme="#style/ThemeOverlay.AppCompat.Dark.ActionBar"/>
<!-- View pager to swipe views -->
<android.support.v4.view.ViewPager
android:id="#+id/pager"
android:layout_width="match_parent"
android:layout_height="fill_parent"/>
I have an dashboard tab in this TabLayout. In this dashboard tab i have an button which id is userprofile. after click on this button i want to go on user_profile.xml
public class Dashboard extends Fragment implements View.OnClickListener {
Button userprofile;
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.dashboard, container, false);
userprofile=(Button)rootView.findViewById(R.id.userprofile);
userprofile.setOnClickListener(this);
return rootView;
}
#Override
public void onClick(View view) {
Fragment fragment = null;
switch (view.getId()) {
case R.id.userprofile:
fragment = new User_Profile();
replaceFragment(fragment);
break;
}
}
private void replaceFragment(Fragment fragment) {
User_Profile user_profile = new User_Profile();
FragmentTransaction transaction = getFragmentManager().beginTransaction();
transaction.replace(R.id.pager, fragment);
transaction.addToBackStack(null);
transaction.commit();
}
User_Profile class code is :-
public class User_Profile extends Fragment {
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
View rooView=inflater.inflate(R.layout.user_profile, container, false);
return rooView;
}
}
user_profile.xml is :-
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="User Profile"
android:textSize="30dp"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true"/>
If you can see fragment on button click but not designing then its may error in your fragment .xml file. By using proper view problem can be solve. If there is also a problem with same post their .xml file code.
Can you show us some more data please? What's the XML for the pager fragment you're trying to replace the current fragment with?
Could you check that you're referring to the layout of that XML file, and not the individual pager element too?
(Since transaction.replace requires a fragment container as it's first argument)

fragments: onCreateView is not called after fragment was added

I have simple app with fragments.
At the beginning list of fragments is empty.
And there are 2 buttons:
ADD FRAGMENT
REMOVE FRAGMENT
And following use-case:
Add fragment
Add fragment
Remove first fragment
Add fragment
As result onCreateView() on 4th step is not executed.
If I add fragment again on 5th step - onCreateView is executed again.
Why is it so? I didn't find right answer in google.
Source code:
public class MyActivity extends FragmentActivity {
private ViewPager pager;
private FragmentAdapter adapter;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
pager = (ViewPager) findViewById(R.id.pager);
final Button addButton = (Button) findViewById(R.id.add_button);
addButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
adapter.addFragment(new MyFragment());
adapter.notifyDataSetChanged();
}
});
final Button removeButton = (Button) findViewById(R.id.remove_button);
removeButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
adapter.removeFragment(0);
adapter.notifyDataSetChanged();
}
});
adapter = new FragmentAdapter(getSupportFragmentManager());
pager.setAdapter(adapter);
pager.setOffscreenPageLimit(10);
}
private class FragmentAdapter extends FragmentStatePagerAdapter {
final List<MyFragment> fragments = new ArrayList<MyFragment>();
public FragmentAdapter(FragmentManager fm) {
super(fm);
}
#Override
public Fragment getItem(int i) {
return fragments.get(i);
}
#Override
public int getCount() {
return fragments.size();
}
public void addFragment(MyFragment fragment) {
fragments.add(fragment);
}
public void removeFragment(int index) {
fragments.remove(index);
}
}
private class MyFragment extends Fragment {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment, container, false);
}
}
}
main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Add"
android:id="#+id/add_button"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Remove first"
android:id="#+id/remove_button"/>
<android.support.v4.view.ViewPager
android:id="#+id/pager"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</LinearLayout>
fragment.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="New Text"
android:id="#+id/textView"
android:layout_gravity="center_horizontal"/>
</LinearLayout>
OnCreateView() is only called when the actual Fragment is being drawn on the screen. Since you have removed a fragment at the beginning the pager no longer looks at the same fragment.
To better understand what is going on put a visible number on each of the fragments and then try adding and removing the fragments.
The issue is 'FragmentStatePagerAdapter' and the way it's implemented. The way to fix it is this:
Go to googlesource and grab the source for 'FragmentStatePagerAdapter'.
refactor (name, package,etc) to make it your own implementation.
Extend from your NEW version of 'FragmentStatePagerAdapter'
Modify your NEW version of 'FragmentStatePagerAdapter' using these steps below:
a) Change the mFragments.set(index, object) command to mFragments.add(index, object), in the the 'instantiateItem()' function.
b) Change the mFragments.set(index, object) command to mFragments.remove(index), in the 'destroyItem' function.
All of this assumes that you are using an ArrayList to hold fragments in your 'extends' class and that they are synced to match the ViewPager.
You will need to add a 'pageIndex' to each fragment, so that you can tell ViewPager when your item has 'moved' (due to deleting an item, that is NOT the LAST item).
This took several days to run down...hope it helps someone :-)

Navigate among fragments within one activity

I would like to use one Activity which holds several fragments and navigate among the fragments. For example, in the activity, there is a list view which is a fragment, when user select one item from the list, the view will navigate to another fragment, How could this be implemented?
I know there is a nice tutorial on the developer site, but it handles the tablet screen in which two pane layout with one list fragment and one detailed fragment showing in one screen. I only want to navigate among fragments without show two fragments in one screen.
Are there tutorials can teach me how to do it?
In the nutshell the answer to your question is to notify your host activity and then have your host activity replace your current fragment container using FragmentManager.
One of the approach is to make an interface in your first fragment, have your host activity register/listen (implement) to this interface and then have your FragmentManager to replace the container content with the second fragment on listener callback.
I'm not sure about tutorial but here is my snippet:
First Fragment
public class First extends Fragment{
private static onMySignalListener listener;
//call this function from whatever you like i.e button onClickListener
public void switchWindow() {
if(listener != null){
listener.onMySignal();
}
}
public interface onMySignalListener {
//customize this to your liking
//plain without argument
void onMySignal();
//with argument
void onMySignalWithNum(int mNum);
}
public static void setOnMySignalListener(onMySignalListener listener) {
First.listener = listener;
}}
Host Activity
public class HostActivity extends FragmentActivity implements onMySignalListener{
private final String ADD_TAG_IF_NECESSARY = "mTag";
#Override
public void onCreate(Bundle ssi) {
setContentLayout(R.layout.main);
FirstFragment.setOnMySignalListener(this);
}
#Override
public void onMySignal() {
//if you're using compat library
FragmentManager manager = getSupportFragmentManager();
FragmentTransaction transaction = manager.beginTransaction();
//initialize your second fragment
sfragment = SecondFragment.newInstance(null);
//replace your current container being most of the time as FrameLayout
transaction.replace(R.id.container, fragment, ADD_TAG_IF_NECESSARY);
transaction.commit();
}
#Override
public void onMySignalWithNum(int mNum) {
//you can do the same like the above probably with your own customization
}}
This is only an example on how you'd implement interface, kindly tidy it up by yourself. And please be noted though that this is not effective if you have a lot of fragment wanting to notify your host activity about something. doing so will lead you to implement various listener to your host activity.
I think this will be useful for you. It is example of two fragments in one screen works independently.
MainActivity :
public class MainActivity extends Activity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main_activity);
Fragment newFragment = new Test();
FragmentTransaction transaction = getFragmentManager().beginTransaction();
transaction.add(R.id.UprLayout, newFragment);
// transaction.addToBackStack(null);
transaction.commit();
Fragment newFragment2 = new TestRight();
FragmentTransaction transaction2 = getFragmentManager().beginTransaction();
transaction2.add(R.id.dwnLayout, newFragment2);
// transaction.addToBackStack(null);
transaction2.commit();
}
}
main_activity.xml :
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/LinearLayout2"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center|center_horizontal"
android:orientation="vertical" >
<LinearLayout
android:id="#+id/UprLayout"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:orientation="vertical" />
<LinearLayout
android:id="#+id/dwnLayout"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:orientation="vertical" />
</LinearLayout>
Fragment Test :
public class Test extends Fragment {
TextView tv;
#Override
public void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
}
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.test, container, false);
return view;
}
}
Fragment TestRight :
public class TestRight extends Fragment {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.test_right, container, false);
return view;
}
#Override
public void onStart() {
super.onStart();
Button button = (Button)getActivity().findViewById(R.id.button1);
button.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
Fragment newFragment = new Right2nd();
FragmentTransaction transaction = getFragmentManager()
.beginTransaction();
transaction.replace(R.id.dwnLayout, newFragment);
transaction.addToBackStack("aa");
transaction.commit();
//transaction.add(R.id.frag, newFragment).commit();
}
});
}
}
test.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:gravity="center"
android:orientation="vertical" >
<TextView
android:id="#+id/textView1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_horizontal"
android:text="test"
android:textAppearance="?android:attr/textAppearanceLarge"
android:textSize="50sp" />
</LinearLayout>
test_right.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:gravity="center"
android:orientation="vertical" >
<Button
android:id="#+id/button1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Click" />
<TextView
android:id="#+id/textView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Test right"
android:textAppearance="?android:attr/textAppearanceLarge"
android:textSize="45sp" />
</LinearLayout>
Fragment Right2nd :
public class Right2nd extends Fragment{
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View vw = inflater.inflate(R.layout.right_2nd, container, false);
return vw;
}
}
right_2nd.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:gravity="center"
android:orientation="vertical" >
<TextView
android:id="#+id/textView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Right 2nd"
android:textAppearance="?android:attr/textAppearanceLarge"
android:textSize="50sp" />
</LinearLayout>
I know this is quite old question but this is currently implemented in Navigation Component https://developer.android.com/guide/navigation/
Here is a very nice tutorial about it. MULTIPLE FRAGMENTS STACK IN EACH VIEWPAGER TAB
I think ChildFragment
would do the job for you. Ignore the Tab ViewPager. It's performing the same thing in multiple tabs. Hope this helps a bit.

Android Fragment Duplicate Objects in Layout

I'm trying to build an Android 4.0 App with the new fragments and action bar.
I'm doing well but I have a little problem now.
When I put a fragment inside a tab, and for example, a time picker in the fragment layout, in the emulator it will appear twice, one on top of the other.
Here is my code:
public class NetworksActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.networks);
// setup Action Bar for tabs
ActionBar actionBar = getActionBar();
actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
// instantiate fragment for the tab
Fragment networksFragment = new NetworksFragment();
// add a new tab and set its title text and tab listener
actionBar.addTab(actionBar.newTab().setText("Sensors")
.setTabListener(new ActionTabListener(networksFragment)));
}}
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<fragment
android:id="#+id/net_frag"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:name="my.package.test.NetworksFragment" />
</FrameLayout>
public class NetworksFragment extends Fragment {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
return inflater.inflate(R.layout.networks_fragment, container, false);
}
}
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<TimePicker
android:id="#+id/timePicker1"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</FrameLayout>
public class ActionTabListener implements ActionBar.TabListener {
private NetworksFragment frag;
// Called to create an instance of the listener when adding a new tab
public ActionTabListener(NetworksFragment fragment) {
frag = fragment;
}
#Override
public void onTabReselected(Tab arg0, FragmentTransaction arg1) {
// TODO Auto-generated method stub
}
#Override
public void onTabSelected(Tab tab, FragmentTransaction ft) {
ft.add(R.id.net_frag, frag, null);
}
#Override
public void onTabUnselected(Tab tab, FragmentTransaction ft) {
ft.remove(frag);
}
}
It seems like its putting two fragments (two copies) in the same activity.
Do you know what are causing this?
Thanks in advance.
It looks like you are defining a fragment in XML, which will instantiate it when that layout is inflated (from NetworksActivity.setContentView(R.layout.networks)) then you are creating another instance of it just below that.
Unless I am missing something, that is your problem. No need to define it in XML if you are going to instantiate it manually and add it yourself in code.
I had a similar problem. The way i solved it was to remove this code from my Fragment-class:
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
CameraFragment cameraFragment = new CameraFragment();
fragmentTransaction.add(R.id.spinnerFragment, spinnerFragment);
fragmentTransaction.commit();
And left this code from my fragment-XML:
<fragment
android:id="#+id/spinnerFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1"
class="com.example.SpinnerFragment" />
I guess you can do it the oposite way also :)

Categories

Resources