I'm kinda new into android programming, and I couldn't find the answer on the internet.
I have set up a Navigation drawer in Android Studio, and I want to change the content view if that section is selected, for example, if I select a view "Tools" in the navigation drawer, I want that you can see the layout "Tools" but that you also can go back to the navigation drawer. I have tried to put setContentView into the case 1, etc but that gave an error.
I have tried this code for the setContentView:
public class MainActivity extends Activity
implements NavigationDrawerFragment.NavigationDrawerCallbacks {
/**
* Fragment managing the behaviors, interactions and presentation of the navigation drawer.
*/
private NavigationDrawerFragment mNavigationDrawerFragment;
/**
* Used to store the last screen title. For use in {#link #restoreActionBar()}.
*/
private CharSequence mTitle;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mNavigationDrawerFragment = (NavigationDrawerFragment)
getFragmentManager().findFragmentById(R.id.navigation_drawer);
mTitle = getTitle();
// Set up the drawer.
mNavigationDrawerFragment.setUp(
R.id.navigation_drawer,
(DrawerLayout) findViewById(R.id.drawer_layout));
}
#Override
public void onNavigationDrawerItemSelected(int position) {
// update the main content by replacing fragments
FragmentManager fragmentManager = getFragmentManager();
fragmentManager.beginTransaction()
.replace(R.id.container, PlaceholderFragment.newInstance(position + 1))
.commit();
}
public void onSectionAttached(int number) {
switch (number) {
case 1:
//This is where I thought I could implement the setContentView
setContentView(R.layout.activity_tools);
mTitle = "Tools";
break;
case 2:
mTitle = "Weapons";
break;
case 3:
mTitle = "Mobs";
break;
case 4:
mTitle = "Food";
break;
case 5:
mTitle = "Blocks";
break;
}
}
ContentView is not what you want to change on drawer item selection. ContentView sets your activity layout (the one which holds NavigationDrawer view). What you really want is to replace fragments.Lets say you have a different fragment with its own layout for every item in the navigation menu. In this case you could implement something like:
public void onNavigationDrawerItemSelected(int position) {
Fragment fragment;
Bundle args = new Bundle();
String tag;
switch (position) {
case 1:
fragment = new FragmentTools();
tag = "Tools";
args.putString(KEY_FRAGMENT_TITLE, tag);
break;
case 2:
fragment = new FragmentWeapons();
tag = "Weapons";
args.putString(KEY_FRAGMENT_TITLE, tag);
break;
case 3:
...
}
FragmentTransaction transaction = getFragmentManager().beginTransaction();
fragment.setArguments(args);
transaction.replace(R.id.fragment_container, fragment, tag);
transaction.commit();
}
The above is just an example. You select which fragment to show and set its arguments. Of cource it could be the same fragment with different layouts. In that case you could pass layout id as an argument, or select appropriate layout in Fragment itself based on its title.
Related
I'm trying to switch between fragments using a bottom navigation. However, if I switch to other fragments from the map fragment, the map fragment is still in the background while other fragment is being shown on the front.
Please see my code here:
public class MainActivity extends AppCompatActivity {
private FragmentManager fragmentManager;
private Fragment messageFragment = new MessageFragment();
private Fragment mapFragment = new MapsFragment();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
fragmentManager = getSupportFragmentManager();
fragmentManager.beginTransaction().add(R.id.hostFragment, mapFragment, null).commit();
fragmentManager.beginTransaction().add(R.id.hostFragment, messageFragment, null).commit();
BottomNavigationView bottomNavigationView = findViewById(R.id.bottomNavigationView);
//bottomNavigationView.setSelectedItemId(R.id.mapsFragment);
bottomNavigationView.setOnNavigationItemSelectedListener(navListener);
}
private BottomNavigationView.OnNavigationItemSelectedListener navListener = new BottomNavigationView.OnNavigationItemSelectedListener() {
#Override
public boolean onNavigationItemSelected(#NonNull MenuItem item) {
switch (item.getItemId()) {
case R.id.mapsFragment:
fragmentManager.beginTransaction().hide(messageFragment).show(mapFragment).commit();
break;
case R.id.messageFragment:
fragmentManager.beginTransaction().hide(mapFragment).show(messageFragment).commit();
break;
}
return true;
}
};
}
Your Problem
You are adding both fragments to the same container, R.id.hostFragment.
fragmentManager.beginTransaction().add(R.id.hostFragment, mapFragment, null).commit();
fragmentManager.beginTransaction().add(R.id.hostFragment, messageFragment, null).commit();
Per the documentation for hide and show, this means that you are hiding and then showing the same container.
A Solution
Use two different container views:
fragmentManager.beginTransaction().add(R.id.mapContainer, mapFragment, null).commit();
fragmentManager.beginTransaction().add(R.id.messageContainer, messageFragment, null).commit();
Another Solution
Use replace instead of hiding and showing.
fragmentManager.beginTransaction().add(R.id.hostFragment, mapFragment, null).commit();
// Don't add this in `onCreate`
// fragmentManager.beginTransaction().add(R.id.hostFragment, messageFragment, null).commit();
...
// Replace the fragment currently being displayed
switch (item.getItemId()) {
case R.id.mapsFragment:
fragmentManager.beginTransaction().replace(R.id.hostFragment, mapFragment).commit();
break;
case R.id.messageFragment:
fragmentManager.beginTransaction().replace(R.id.hostFragment, messageFragment).commit();
break;
}
I'm confused how to open my different fragments by clicking on one Item in my navigation drawer.
In MainActivity I use the following Code:
#SuppressWarnings("StatementWithEmptyBody")
#Override
public boolean onNavigationItemSelected(MenuItem item) {
Fragment fragment;
int id = item.getItemId();
if (id == R.id.nav_listview) {
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
ft.replace(R.id.fragment, new ListFragment());
ft.commit();
} else if (id == R.id.nav_add_data) {
} else if (id == R.id.nav_settings) {
} else if (id == R.id.nav_legal_information) {
}
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
drawer.closeDrawer(GravityCompat.START);
return true;
}
First of all I want to try to open my ListFragment:
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
public class ListFragment extends Fragment {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_list, container, false);
}
}
In my content main.xml I created the following fragment which should be replaced when clicking on the specific Items in the Navigation Drawer.
<fragment
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/fragment" />
But it isnt working...
Can anyone help me?
Rastaman
To get what you want try this ,I was also held up with this somewhat complex looking code but its more of a easy way to use
Here's detailed explanation and walk through to this issue:
(Its seems Long But You can easily relate your work asap)
When you first create the Navigation Drawer Activity, there are 5 files we’ll look at:
MainActivity.java - this is the code behind for everything in our app.
activity_main.xml - this is the layout for the app including the nav drawer and an include for the app_bar_main.
app_bar_main.xml - this is the layout with the toolbar (at the top), a floating action button (at the bottom right), and an include for content_main.
content_main.xml - this is the layout for the content of the main page.
nav_header_main.xml - this is the UI for the top part of the nav drawer.
Step 1:
open up the app_bar_main.xml, comment out the include and add a new FrameLayout:
<!--<include layout="#layout/content_main" />-->
<FrameLayout
android:id="#+id/Fragment_container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginTop="?attr/actionBarSize"/>
This FrameLayout is what we’ll use to load our fragments into.
Step 2:
Next, you’ll want to add a few fragments
To do so, right click on your project, or go to File –> New and from the Fragment list choose Fragment (Blank) or others
Step 3:
The next step is to load a fragment when the app first launches. Go to the MainActivity’s onCreate method and put the following in after the call to setSupportActionBar:
Fragment fragment = null;
Class fragmentClass = null;
fragmentClass = FragmentOne.class;
try {
fragment = (Fragment) fragmentClass.newInstance();
} catch (Exception e) {
e.printStackTrace();
}
FragmentManager fragmentManager = getSupportFragmentManager();
fragmentManager.beginTransaction().replace(R.id.Fragment_container, fragment).commit();
Step 4:
You’ll then need to add OnFragmentInteractionListener to the interfaces your MainActivity implements and also implement the onFragmentInteraction method.Like this
public class MainActivity extends AppCompatActivity
implements NavigationView.OnNavigationItemSelectedListener, FragmentOne.OnFragmentInteractionListener ,FragmentTwo.OnFragmentInteractionListener,FragmentThree.OnFragmentInteractionListener {
Step 5:
Finally, in the onNavigationItemSelected method, you can add the ability to load different fragments when menu items are tapped:
public boolean onNavigationItemSelected(MenuItem item) {
// Handle navigation view item clicks here.
int id = item.getItemId();
Fragment fragment = null;
Class fragmentClass = null;
if (id == R.id.nav_camera) {
fragmentClass = FragmentOne.class;
} else if (id == R.id.nav_gallery) {
fragmentClass = FragmentTwo.class;
} else if (id == R.id.nav_slideshow) {
fragmentClass = FragmentThree.class;
} else if (id == R.id.nav_manage) {
} else if (id == R.id.nav_share) {
} else if (id == R.id.nav_send) {
}
try {
fragment = (Fragment) fragmentClass.newInstance();
} catch (Exception e) {
e.printStackTrace();
}
FragmentManager fragmentManager = getSupportFragmentManager();
fragmentManager.beginTransaction().replace(R.id.flContent, fragment).commit();
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
drawer.closeDrawer(GravityCompat.START);
return true;
}
Here I’m just loading one of the two fragments I’ve added to my app. Note that because I have two different fragments, I had to implement the interfaces for both FragmentOne.OnFragmentInteractionListener and FragmentTwo.OnFragmentInteractionListener.
That’s all you need to do to implement fragment loading in your Navigation Drawer.
What the user taps a menu item, the drawer will slide back in smoothly and the new fragment will have already started / finished loading. This also prevents any possible jankiness that you could see when launching a new activity.
EXTRA
One last thing to note is that if you switch to a different fragment and then rotate the device or cause another recreation of the activity, the code above will cause the first fragment to be reloaded. One easy way to deal with that is to wrap the fragment block in the onCreate method in a check to see if the savedInstanceState is not null like this:
protected void onCreate(Bundle savedInstanceState) {
...
if (savedInstanceState == null) {
//Fragment load code
}
...
}
Try this Code
#SuppressWarnings("StatementWithEmptyBody")
#Override
public boolean onNavigationItemSelected(MenuItem item) {
Fragment fragment=null;
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
int id = item.getItemId();
if (id == R.id.nav_listview) {
fragment= new ListFragment();
} else if (id == R.id.nav_add_data) {
} else if (id == R.id.nav_settings) {
} else if (id == R.id.nav_legal_information) {
}
ft.replace(R.id.container, fragment);
ft.addToBackStack(null);
ft.commit();
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
drawer.closeDrawer(GravityCompat.START);
return true;
}
<FrameLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/container" />
Please Change The name of your fragment class ListFragment Because ListFragment is already Sub Class of Fragments in android.app package android OS
Mhmm I found an answer. But I am confused.
If I use:
if (id == R.id.nav_listview) {
fragment= new com.thomas.testapp.ListFragment();
It works. But I only have to use the package name if I want to open my ListFragment. Why?
I suggest to Create codes More Dynamic
first of all, if you have custom class to create Navigation Drawer, use listener to call methods from your activity
there is class call HomeFragment extends Fragment, so we have :
if(condition){
fragment = new HomeFragment();
// if there is Listener
if(mListener != null){
mListener.someMethod
}
// Other Settings And Codes
}
public class MainActivity extends AppCompatActivity {
// ...
#Override
protected void onCreate(Bundle savedInstanceState) {
// ...From section above...
// Find our drawer view
nvDrawer = (NavigationView) findViewById(R.id.nvView);
// Setup drawer view
setupDrawerContent(nvDrawer);
}
private void setupDrawerContent(NavigationView navigationView) {
navigationView.setNavigationItemSelectedListener(
new NavigationView.OnNavigationItemSelectedListener() {
#Override
public boolean onNavigationItemSelected(MenuItem menuItem) {
selectDrawerItem(menuItem);
return true;
}
});
}
public void selectDrawerItem(MenuItem menuItem) {
// Create a new fragment and specify the fragment to show based on nav item clicked
Fragment fragment = null;
Class fragmentClass;
switch(menuItem.getItemId()) {
case R.id.nav_first_fragment:
fragmentClass = FirstFragment.class;
break;
case R.id.nav_second_fragment:
fragmentClass = SecondFragment.class;
break;
case R.id.nav_third_fragment:
fragmentClass = ThirdFragment.class;
break;
default:
fragmentClass = FirstFragment.class;
}
try {
fragment = (Fragment) fragmentClass.newInstance();
} catch (Exception e) {
e.printStackTrace();
}
// Insert the fragment by replacing any existing fragment
FragmentManager fragmentManager = getSupportFragmentManager();
fragmentManager.beginTransaction().replace(R.id.flContent, fragment).commit();
// Highlight the selected item has been done by NavigationView
menuItem.setChecked(true);
// Set action bar title
setTitle(menuItem.getTitle());
// Close the navigation drawer
mDrawer.closeDrawers();
}
// ...
}
http://www.androidhive.info/2013/11/android-sliding-menu-using-navigation-drawer/
hi all, I have succeeded apply this Android Sliding Menu in my project.
however, how can i add some activity in diffferent page?
In MainActivity, displayView function controls the fragment which i have selected.you can see it only use in "Fragment fragment = null;",so , the CESDemo class is extends Fragment.But i cannot add my activity in the CESDemo, such as onTouch and so on.If i change it to FragmentActivity, it does not allow me for "ragmentManager.beginTransaction().replace(R.id.frame_container,fragment).commit();"
So, how can i apply some activity in different fragment,even i can design the layout but no any activity i can create.
MainActivity.java
private void displayView(int position) {
// update the main content by replacing fragments
//Fragment fragment = null;
Fragment fragment =null;
switch (position) {
case 0:
fragment = new CESHome();
break;
case 1:
fragment = new CESAll();
break;
case 2:
fragment = new CESPending();
break;
case 3:
fragment = new CESInProgress();
break;
case 4:
fragment = new CESCompleted();
break;
case 5:
fragment = new CESDemo();
break;
default:
break;
}
if (fragment != null) {
FragmentManager fragmentManager = getFragmentManager();
fragmentManager.beginTransaction()
.replace(R.id.frame_container, fragment).commit();
// update selected item and title, then close the drawer
mDrawerList.setItemChecked(position, true);
mDrawerList.setSelection(position);
setTitle(navMenuTitles[position]);
mDrawerLayout.closeDrawer(mDrawerList);
} else {
// error in creating fragment
Log.e("MainActivity", "Error in creating fragment");
}
}
CESDemo.java
public class CESDemo extends Fragment {
public CESDemo(){}
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.activity_cesdemo, container, false);
return rootView;
}
I have setup a new project with the template implementation of Navigation Drawer Fragment and a MainActivity.
It provides me with the following relevant methods:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Intent intent = getIntent();
token = intent.getStringExtra(EXTRA_TOKEN);
mNavigationDrawerFragment = (NavigationDrawerFragment)
getSupportFragmentManager().findFragmentById(R.id.navigation_drawer);
mNavigationDrawerFragment.activityMain = this;
mTitle = getTitle();
// Set up the drawer.
mNavigationDrawerFragment.setUp(
R.id.navigation_drawer,
(DrawerLayout) findViewById(R.id.drawer_layout));
}
My MainActivity is started by a splash activity which gets a saved access token via the EXTRA_TOKEN.
This is the override of the Navigation Drawer item select listener in the MainAcitivity:
#Override
public void onNavigationDrawerItemSelected(int position) {
// update the main content by replacing fragments
FragmentManager fragmentManager = getSupportFragmentManager();
onSectionAttached(position + 1);
switch(position) {
case 0:
fragmentManager.beginTransaction()
.replace(R.id.container, FeedFragment.newInstance(token, ""))
.commit();
break;
case 1:
fragmentManager.beginTransaction()
.replace(R.id.container, PeopleFragment.newInstance("", ""))
.commit();
break;
case 2:
if(qbloggedin) {
fragmentManager.beginTransaction()
.replace(R.id.container, MessagesFragment.newInstance(token, ""))
.commit();
}
break;
default:
break;
}
}
It starts three different fragments depending on which item is selected in the NavDrawer. While instantiating the new fragments, the token string is passed into its constructor, which is saved in the fragment's class for further use.
On the first start of the App however, it seems that onNavigationDrawerItemSelected is called before onCreate! This results me passing a null value token into the fragments, causing them to be all messed up.
How is this possible? As I understand it, the NavigationDrawerFragment should not have been setup yet!
I set breakpoints on both onCreate and on onNavigationDrawerItemSelected switch position = 0. onNavigationDrawerItemSelected is indeed hit before onCreate.
How can I make sure to get the token first before trying to handle the onNavigationDrawerItemSelected?
Any help would be appreciated.
I believe I figured this out as it was happening to me for anyone who searches this and can't find the answer.
If you use the Android Studio DrawerActivity then there is boilerplate code that they create for you. In this code in the activity_main.xml or whichever XML your DrawerActivity sets as its' content view, there is a tag.
When setContentView() is called in onCreate(), this fragment is automatically created and so technically onCreate() is still being called first but then the onNavigationDrawerItemSelected() method is called before anything else in create. Since setContentView is typically kept up top, this causes problems when trying to store the state of the fragments in your drawer.
Simply move any code that checks for savedInstanceBundle above setContentView() and it will fix the problem.
Example with comments:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// THIS IS WHERE YOU CHECK FOR SAVED INSTANCE
// Check for frag
if (savedInstanceState != null) {
Log.i(TAG, "Get QuestionDayFragment");
mQuestionDaysFragment = (QuestionDaysFragment) getSupportFragmentManager().getFragment(savedInstanceState, QUESTION_DAY_FRAGMENT);
}
// View injection
setContentView(R.layout.activity_main);
ButterKnife.inject(this);
// THIS IS WHERE THE CODE WAS BEFORE
// THIS WOULD BE CALLED AFTER onNavigationDrawerItemSelected()
// Singleton injection
LifeboxApplication.graph().inject(this);
// Toolbar
setSupportActionBar(mToolbar);
// FB
uiHelper = new UiLifecycleHelper(this, callback);
uiHelper.onCreate(savedInstanceState);
// Drawer
mNavigationDrawerFragment = (NavigationDrawerFragment) getSupportFragmentManager().findFragmentById(R.id.navigation_drawer);
mTitle = getTitle();
mNavigationDrawerFragment.setUp(R.id.navigation_drawer, (DrawerLayout) findViewById(R.id.drawer_layout));
}
You could move the intent to a constructor and save your tokens there like so:
Intent i;
......
public FragmentConstructor() {
i = getIntent();
token = intent.getStringExtra(EXTRA_TOKEN);
}
What I had to do to make it work was to check if the page has loaded before executing onNavigationDrawerItemSelected
private Boolean loaded=false;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Your code here
this.loaded=true;
}
public void onNavigationDrawerItemSelected(int position) {
if (!this.loaded){
return;
}
I also agree with using a boolean to check if onCreate() has finished loading. My only other suggestions is that for a quick fix you can use onSectionAttached(int number) to process each item selected instead of onNavigationDrawerItemSelected.
I currently have a MainActivity.java which should be the only activity class. Though in that activity class I have a nav-drawer which links to other fragment views.
Currently the main issue Im facing is implementing tabs under a fragment and making them just be available for only that fragment and subfragments. I ran my application and the tabs appeared, but they also appear on other fragments after I visit the TeamsAndDriversFragment.
In my MainActivity.java I have the following function which helps point to the fragments it will generate once someone clicks on them in the nav-drawer:
/**
* Diplaying fragment view for selected nav drawer list item
* */
private void displayView(int position) {
// update the main content by replacing fragments
Fragment fragment = null;
switch (position) {
case 0:
fragment = new TimeAndScoringFragment();
break;
case 1:
fragment = new ScheduleFragment();
break;
case 2:
fragment = new StandingsFragment();
break;
case 3:
fragment = new TeamsAndDriversFragment();
break;
case 4:
fragment = new NewsFragment();
break;
default:
break;
}
if (fragment != null) {
// Create a fragment transaction object to be able to switch fragments
FragmentTransaction transaction = getFragmentManager().beginTransaction();
// Replace whatever is in the fragment container view with this fragment,
// and add the transaction to the back stack
transaction.replace(R.id.frame_container, fragment);
transaction.addToBackStack(null);
// Commit the transaction
transaction.commit();
// update selected item and title, then close the drawer
mDrawerList.setItemChecked(position, true);
mDrawerList.setSelection(position);
setTitle(navMenuTitles[position]);
mDrawerLayout.closeDrawer(mDrawerList);
} else {
// error in creating fragment
Log.e("MainActivity", "Error in creating fragment");
}
}
Here is my current TeamsAndDriversFragment class where I have an actionbar navigation with tabs:
public class TeamsAndDriversFragment extends Fragment implements TabListener {
private List<Fragment> fragList = new ArrayList<Fragment>();
#Override
public void onCreate(Bundle savedInstance) {
super.onCreate(savedInstance);
ActionBar bar = getActivity().getActionBar();
bar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
Tab mTeamsTab = bar.newTab();
mTeamsTab.setText("Teams");
mTeamsTab.setTabListener(this);
bar.addTab(mTeamsTab);
Tab mDriversTab = bar.newTab();
mDriversTab.setText("Drivers");
mDriversTab.setTabListener(this);
bar.addTab(mDriversTab);
}
#Override
public void onTabReselected(Tab tab, FragmentTransaction ft) {
}
#Override
public void onTabSelected(Tab tab, FragmentTransaction ft) {
Fragment f = null;
TabFragment tf = null;
if(fragList.size() > tab.getPosition()) {
fragList.get(tab.getPosition());
}
if(f == null) {
tf = new TabFragment();
Bundle data = new Bundle();
data.putInt("idx", tab.getPosition());
tf.setArguments(data);
fragList.add(tf);
} else {
tf = (TabFragment) f;
}
ft.replace(android.R.id.content, tf);
}
#Override
public void onTabUnselected(Tab tab, FragmentTransaction ft) {
if(fragList.size() > tab.getPosition()) {
ft.remove(fragList.get(tab.getPosition()));
}
}
}
In the displayView() method simply remove all tabs from the ActionBar, this way you'll always have a clean ActionBar with the exception of the TeamsAndDriversFragment fragment:
private void displayView(int position) {
getSupportActionBar().removeAllTabs();
// ...
}