I'm currently creating an app which can handle different screen support and multi-pane view using fragments. Now I used the default navigation drawer and actionbar using android studio and created two fragments to test for this and layouts for portrait: fragment_1 and fragment_2 which just replaces the container on the MainActivity. But now the problem is how can I implement the fragment_1 and fragment_2 in 1 layout? I Tried to research on the multi-pane development on this link but I think to properly implement it I need to use an ActivityFragment but in this case I am limited on using just Fragments which is why I'm lost on what to do. Here's the code so far:
#Override
public void onNavigationDrawerItemSelected(int position) {
// update the main content by replacing fragments
FragmentManager fragmentManager = getSupportFragmentManager();
switch (position) {
case 0:
fragmentManager.beginTransaction()
.replace(R.id.container, FragmentMain.newInstance(position + 1))
.commit();
break;
case 1:
fragmentManager.beginTransaction()
.replace(R.id.container, FragmentAbout.newInstance(position + 1))
.commit();
break;
/*create the other cases here for navigation*/
}
}
fragment_main.xml (the 1st fragment)
<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"
tools:context="com.kahel.main.MainActivity$PlaceholderFragment">
<android.support.v4.widget.SwipeRefreshLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/swipe_container"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ListView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/list_news"
android:choiceMode="singleChoice" />
</android.support.v4.widget.SwipeRefreshLayout>
</RelativeLayout>
fragment_about.xml (2nd fragment)
<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"
tools:context="com.kahel.main.MainActivity$PlaceholderFragment">
<android.support.v4.widget.SwipeRefreshLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/swipe_container"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ListView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/list_news"
android:choiceMode="singleChoice" />
</android.support.v4.widget.SwipeRefreshLayout>
</RelativeLayout>
fragment_main.xml (landscape)
<LinearLayout 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"
tools:context="com.kahel.main.MainActivity$PlaceholderFragment"
android:orientation="horizontal"
android:weightSum="1">
<android.support.v4.widget.SwipeRefreshLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/swipe_container"
android:layout_width="#dimen/land_scoop_feed"
android:layout_height="match_parent">
<ListView
android:layout_width="150dp"
android:layout_height="match_parent"
android:id="#+id/list_news"
android:choiceMode="singleChoice" />
</android.support.v4.widget.SwipeRefreshLayout>
</LinearLayout>
When I tried to change the layout it just force close my app. :/
Please let me know what to do or what to search for. Thanks! :)
Well, I ran into the exact same problem and after doing a lot of research I was surprised on the lack of documentation for this, in my opinion, common situation. But, after trying a few things I came up with a solution.
My first approach was to replace the Navigation Drawer container with a "root fragment" that at the same time would have two layouts available containing the fragments that I want. The problem was that nested fragments declared on the layout are not permitted.
To overcome this other issue, in my "final layouts" I replaced the Fragment definitions for FrameLayouts and then load the fragments programatically on the "root fragment".
To summarize: You have your Navigation Drawer and upon clicking what you want, you replace your fragment container with a "root fragment". This "Root fragment" has two layouts: a default one and another for landscape. These layouts contain FrameLayout elements arranged as we want that upon initialization are replaced by our "final fragments".
I doubt that this is the best way to achieve the goal of having Multi-pane layouts with a Navigation Drawer but is what I was able to do that best suited my needs. I welcome any suggestions!.
I illustrate the solution with some code.
MainActivity.java (The one with the navigation drawer)
...
void drawerOptionSelected(String option) {
if(option.equals(XXXX)) {
Fragment fragment = new RootFragment();
final FragmentTransaction transaction = getFragmentManager().beginTransaction();
transaction.replace(R.id.content_frame, fragment);
transaction.commit();
drawerList.setItemChecked(menuOptions.indexOf(option), true);
drawerLayout.closeDrawer(drawerList);
}
}
...
root_fragment_layout.xml (Default)
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/entries_list_single"
android:layout_width="match_parent"
android:layout_weight="1"
android:layout_height="match_parent" />
root_fragment_layout.xml (Landscape)
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:baselineAligned="false"
android:layout_width="match_parent"
android:layout_height="match_parent">
<FrameLayout android:id="#+id/entries_list"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="match_parent" />
<FrameLayout android:id="#+id/entries_post"
android:layout_width="0dp"
android:layout_weight="2"
android:layout_height="match_parent" />
</LinearLayout>
RootFragment.java
public class RootFragment extends Fragment {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.root_fragment_layout);
if(savedInstanceState != null) { //Fragments already loaded, avoid replacing them again
return;
}
ListFragment listFragment = new ListFragment();
final FragmentTransaction transaction = getChildFragmentManager().beginTransaction(); //IMPORTANT! Use child fragment manager
if (findViewById(R.id.entries_list_single) == null) { //We are loading the landscape layout
PostFragment postFragment = new PostFragment();
transaction.replace(R.id.entries_list, listFragment);
transaction.replace(R.id.entries_post, postFragment);
transaction.commit();
} else { //We are loading the default layout
transaction.replace(R.id.entries_list_single, listFragment);
transaction.commit();
}
}
}
Related
I have looked all over on here and pretty much tried everything. I have my main activity which contains my Toolbar and TabLayout, this loads a fragment known as ActiveThreadFragment. I then replace ActiveThreadFragment with another called PostFragment. Here is the issue that's happening:
PostFragment Overlapping ActiveThreadFragment
Here's my code for replacing ActiveThreadFragment with PostFragment
private void showItemSelectedAtPosition(int position) {
Threads selectedThread = mData.getItem(position);
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.replace(R.id.content_thread,
PostFragment.newInstance(selectedThread.getThreadItem()));
fragmentTransaction.addToBackStack(null);
fragmentTransaction.commitAllowingStateLoss();
}
Here is the layout for ActiveThreadFragment where the FrameLayout 'content_thread' is to replace with it.
<android.support.design.widget.CoordinatorLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:weightSum="2"
android:background="#color/primaryColor">
<FrameLayout
android:id="#+id/content_thread"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<android.support.v7.widget.RecyclerView
android:padding="15dp"
android:id="#+id/threadRecyclerView"
android:layout_height="0dp"
android:layout_width="match_parent"
android:layout_weight="1.7"/>
</LinearLayout>
Is there anything I'm doing wrong and can't figure out? Am I just being really silly? I can provide more code or anything else if needed.
In one of my fragment I have the below layout:
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<FrameLayout
android:id="#+id/email_container"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:weightSum="3">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1">
<ImageView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="matrix"
android:src="#drawable/banner_dashboard" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="2"
android:orientation="vertical">
<include layout="#layout/settings_nested" />
</LinearLayout>
</LinearLayout>
</FrameLayout>
</android.support.design.widget.CoordinatorLayout>
Now the following:
<include layout="#layout/settings_nested" />
Consists of some buttons, on click of one such button I want to replace the framelayout with new contents - new fragment which has a different layout. Here is how I do it:
Fragment fragment = null;
fragment = new FragmentEmails();
FragmentManager fragmentManager = getActivity().getSupportFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.replace(R.id.email_container, fragment);
fragmentTransaction.commit();
Now I can see the optionsMenu change when I click the button (As I have defined a different menu file for this new Fragment) However the contents remain the same. Advice any? I think I am doing something wrong the way I am defining the framlayout as the parent of my views, but what exactly, beats me.
According to my Thoughts and Views, You should Do as below
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<FrameLayout
android:id="#+id/email_container"
android:layout_width="match_parent"
android:layout_height="match_parent">
</FrameLayout>
</android.support.design.widget.CoordinatorLayout>
This is the Parent Layout of all fragment and email_container will be used for the transactions of other fragments.
then Create another layout that consists of the inner elements that i have erased.
on startup what you want to display , Change this email_container inneer elements with another fragment like
Fragment fragmentStartPage = null;
fragmentStartPage = new FragmentEmails();
FragmentManager fragmentManager = getActivity().getSupportFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.replace(R.id.email_container, fragmentStartPage);
fragmentTransaction.commit();
then change it with another fragment by replacing the fragmentStartPage with another fragment.
I have an activity that holds a ViewPager, set up as the template Swipe ViewPager. I have attached two fragments to that ViewPager via an adapter. I am now trying to open a new fragment but I am having great trouble getting it to work. I don't fully understand this idea of changing fragments with FragmentTransaction (I tried reading the Android docs to no avail) so I pieced the FragmentTransaction code together from places over the web.
This is my activity_main.xml
<android.support.v4.view.ViewPager
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/pager"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity"/>
This is the code I used to try to open the fragment
private void openVolumeSettingsFragment() {
Activity activity = getActivity();
FragmentTransaction transaction = activity.getSupportFragmentManager().beginTransaction();
transaction.replace(R.id.pager, new VolumeSettingsFragment());
transaction.addToBackStack(null);
transaction.commit();
}
This is the blank xml file for my new fragment fragment_volume_settings.xml
<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"
tools:context="com.velixo.bitchtalkandroid.fragments.VolumeSettingsFragment">
<ListView
android:id="#+id/volume_settings_list_view"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</FrameLayout>
The only thing this does is freezes my current fragment from being swipeable. Does anybody have any idea of what I should be doing?
Posted the same question on reddit, x-posting the answer from jeffinmadison in case anyone reading this question will need it:
If you want to replace the pager fragment with your settings fragment you should make the activity_main be a FrameLayout with a #+id/content and within the FrameLayout put the ViewPager with #+id/pager and then call the replaceFragment on the R.id.content
<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/content">
<android.support.v4.view.ViewPager
android:id="#+id/pager"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity"/>
</FrameLayout>
I have several activities which extend my class DrawerActivity, so they will have a navigation drawer. Only one of these activities requires a ViewPager.
Question: How can I add a ViewPager to only one of the activities, ActivityA?
I am somewhat familiar with creating a ViewPager, but in this situation I'm unsure of where to put the ViewPager code, and what layouts to use. I've seen a few examples including the official tutorial on Google's developer site, but I'm not sure how to best implement it into my application.
I've provided some relevant code below, but please let me know if you need to see more. Any advice is appreciated, thanks!
In DrawerActivity's onCreate:
setContentView(R.layout.activity_fragment);
if (fragment == null)
{
fragment = createFragment();
fm.beginTransaction()
.add(R.id.fragmentContainer, fragment)
.commit();
}
Layout activity_fragment.xml:
<?xml version="1.0" encoding="utf-8"?>
<android.support.v4.widget.DrawerLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/drawerLayout"
android:layout_width="match_parent"
android:layout_height="match_parent">
<RelativeLayout
android:id="#+id/fragmentContainer"
android:layout_width="match_parent"
android:layout_height="match_parent">
</RelativeLayout>
<ListView android:id="#+id/leftDrawer"
android:layout_width="240dp"
android:layout_height="match_parent"
android:layout_gravity="left"
android:choiceMode="singleChoice"
android:divider="#android:color/transparent"
android:dividerHeight="0dp"
android:background="#111"/>
</android.support.v4.widget.DrawerLayout>
In ActivityA:
public class ActivityA extends DrawerActivity
{
//this is all I do in this activity
#Override
protected Fragment createFragment()
{
UUID id = (UUID) getIntent().getSerializableExtra(FragmentA.EXTRA_ID);
return FragmentA.newInstance(id);
}
}
In FragmentA's onCreateView:
View v = inflater.inflate(R.layout.fragment_a, parent, false);
Layout fragment_a.xml is a simple LinearLayout with a few Button and TableLayout children.
fragment_a.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" >
<android.support.v4.view.ViewPager
android:id="#+id/pager"
android:layout_width="match_parent"
android:layout_height="wrap_content"
/>
</RelativeLayout>
and create an adapter for example FragmentStatePagerAdapter and fill it with what you want to show in viewpager. notice that because you are using viewpager inside a fragment you should pass ChildFragmentManaget instead of activity FragmentManager.
I have main activity with only ViewPager on it. The first tab page fragment contains:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/llEventsTabPage"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<ListView
android:id="#+id/lvEvents"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>
I want to show details fragment when user taps item in ListView:
lvEvents.setAdapter(adapter);
lvEvents.setOnItemClickListener(
new OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> adapter, View view, int position, long id) {
Fragment eventFragment = new EventFragment();
FragmentTransaction fragmentTransaction = getChildFragmentManager().beginTransaction();
fragmentTransaction.addToBackStack(null);
fragmentTransaction.replace(R.id.llEventsTabPage, eventFragment);
fragmentTransaction.commit();
}
}
);
Code 'fragmentTransaction.commit();' is called, onCreateView of EventFragment is called, but after 'fragmentTransaction.commit();' nothing happens. No errors, no result. Just list view is still displaying and working.
What am I doing wrong? I've found a few examples, my code looks the same, but not working and I can do nothing with that.
Thank you!
When you do a replace or add, all it's going to do is add the Fragment's View to the container that you specify. The only difference is this:
replace will remove the first existing Fragment inside the container previously that is handled by the FragmentManager specified.
add will simply add the Fragment to the container.
In your case, you have a LinearLayout container which holds a ListView that is of size match_parent. What this means is, when the ChildFragmentManager adds your Fragment to the container, it will add it to a LinearLayout. The fragment is actually below the ListView outside the scope of the View.
Change LinearLayout to FrameLayout and your Fragment will appear over the ListView.
I'm not be sure. but I use two layout structures.
first layout structure
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<FrameLayout android:id="#+id/fragment_container"
android:layout_width="match_parent"
android:layout_height="match_parent"
/>
</FrameLayout>
in this case, you need two fragment.
one is a EventFragment and other one is a Fragment for ListView.
so you should additionally create fragment for ListView.
second layout structure
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ListView android:id="#+id/listview"
android:layout_width="match_parent"
android:layout_height="match_parent"
/>
<FrameLayout android:id="#+id/fragment_container"
android:layout_width="match_parent"
android:layout_height="match_parent"
/>
</FrameLayout>
in this case, you commit R.id.fragment_container instead R.id.llEventsTabPage.
I think it would operate....