I am developing an app where i am using only 1 Main Activity and Multiple fragment, Including ViewPager , Custom video/Image Gallery, Fullscreen Fragment(Without toolbar or bottom navigation button). I am not sure is it good practice or not but i am facing few issues cause of this.
Image above is actual App hierarchy. Following the issue i am facing.
Toolbar doesn't change title of fragment, when press back button or going forward by clicking button or some link.
Navigation hamburger keep showing if i change into back arrow by using: getSupportActionBar().setDisplayHomeAsUpEnabled(true); then back arrow opens drawers but not going back to last fragment.
Fragment State Loss when pressed back button or jumping directly to some fragment.
Whether is it good practice to doing all task within Fragment with Single Activity.
I am also using single Toolbar whole app.
Toolbar.xml
<android.support.v7.widget.Toolbar
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="#color/primary"
app:contentInsetLeft="0dp"
app:contentInsetStart="0dp"
app:contentInsetStartWithNavigation="0dp"
android:fitsSystemWindows="true"
app:layout_collapseMode="pin"
app:layout_scrollFlags="scroll|exitUntilCollapsed">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/toolbar_connections"
android:visibility="visible"
android:orientation="horizontal">
<ImageView
android:layout_width="35dp"
android:layout_height="match_parent"
android:id="#+id/appLogo"
android:layout_gravity="center_vertical" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical|center_horizontal"
android:textSize="22sp"
android:id="#+id/activityTitle"
android:textColor="#color/primary_text"
/>
</LinearLayout>
<LinearLayout
android:id="#+id/toolbar_chat"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="gone"
android:orientation="horizontal">
<de.hdodenhof.circleimageview.CircleImageView
android:layout_width="50dp"
android:layout_height="50dp"
android:layout_gravity="center_vertical"
android:layout_marginRight="5dp"
android:src="#drawable/baby"
android:id="#+id/User_Image_Toolbar"/>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:id="#+id/User_Name_Toolbar"
android:textSize="17sp"
android:textStyle="bold"
android:layout_marginBottom="5dp"
android:text="My Name"
/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Online"
android:textStyle="italic"
android:id="#+id/User_Online_Status_Toolbar"
android:layout_marginBottom="5dp"
android:layout_below="#+id/User_Name_Toolbar" />
</LinearLayout>
</LinearLayout>
</android.support.v7.widget.Toolbar>
Navigation Drawer (Single Activity which parent of all Fragments)
public class Navigation_Drawer extends AppCompatActivity implements UserData {
Toolbar toolbar;
DrawerLayout drawerLayout;
NavigationView navigationView;
String navTitles[];
TypedArray navIcons;
RecyclerView.Adapter recyclerViewAdapter;
ActionBarDrawerToggle drawerToggle;
public static final String TAG = "###Navigation Drawer###";
boolean nextScreen;
//Header
ImageView headerImage,headerUserImage;
TextView userName,userViews;
Context context = this;
//Setting Tabs
ViewPager viewPager;
TabAdapter tabAdapter;
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.navigation_drawer);
//Initialise Views
drawerLayout = findViewById(R.id.Navigation_Drawer_Main);
navigationView = findViewById(R.id.nvView);
setupToolbar();
navigationView.setItemIconTintList(null);
setupDrawerContent(navigationView);
settingHeaderItems();
drawerToggle = setupDrawerToggle();
getSupportActionBar().setHomeButtonEnabled(true);
drawerLayout.addDrawerListener(drawerToggle);
viewPager = findViewById(R.id.Navigation_Drawer_ViewPager);
tabAdapter = new TabAdapter(getFragmentManager(), this, false);
viewPager.setAdapter(tabAdapter);
}
public void setupToolbar() {
toolbar = findViewById(R.id.Navigation_Drawer_toolbar);
setSupportActionBar(toolbar);
}
private ActionBarDrawerToggle setupDrawerToggle() {
// NOTE: Make sure you pass in a valid toolbar reference. ActionBarDrawToggle() does not require it
// and will not render the hamburger icon without it.
//return new ActionBarDrawerToggle(this, drawerLayout, toolbar, R.string.drawer_open, R.string.drawer_close);
return new ActionBarDrawerToggle(this, drawerLayout,toolbar, R.string.drawer_open, R.string.drawer_close);
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = getMenuInflater();
// inflater.inflate(R.menu.main_menu, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
//Handle Item Selection
return super.onOptionsItemSelected(item);
}
private void setupDrawerContent(NavigationView navigationView) {
navigationView.setNavigationItemSelectedListener(
new NavigationView.OnNavigationItemSelectedListener() {
#Override
public boolean onNavigationItemSelected(MenuItem menuItem) {
selectDrawerItem(menuItem);
return true;
}
});
}
public void ChangeFragment_ViewPager(int position, boolean outside) {
if (outside) {
Log.d(TAG, "Change Fragment Calling From Outside");
tabAdapter = new TabAdapter(getFragmentManager(), this, false);
viewPager.setAdapter(tabAdapter);
}
viewPager.setCurrentItem(position);
}
#Override
public void onBackPressed() {
super.onBackPressed();
showSystemUI();
Log.d(TAG, "On Back Pressed");
}
public void showSystemUI() {
if (getWindow() != null) {
getWindow().clearFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
getWindow().clearFlags(WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS);
getWindow().clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
getSupportActionBar().show();
} else {
return;
}
}
public void selectDrawerItem(MenuItem menuItem) {
// Create a new fragment and specify the fragment to show based on nav item clicked
Fragment fragment = null;
switch (menuItem.getItemId()) {
case R.id.HeaderImageView:
fragment = new EditProfile();
break;
case R.id.home_Fragment:
Log.d(TAG,"Home Fragment Pressed ");
getFragmentManager().popBackStack(null, android.app.FragmentManager.POP_BACK_STACK_INCLUSIVE);
ChangeFragment_ViewPager(0,false);
// Highlight the selected item has been done by NavigationView
menuItem.setChecked(true);
// Set action bar title
setTitle(menuItem.getTitle());
// Close the navigation drawer
drawerLayout.closeDrawers();
return;
case R.id.ppl_Fragment:
Log.d(TAG,"PPL Fragment Pressed ");
ChangeFragment_ViewPager(1,false);
// Highlight the selected item has been done by NavigationView
menuItem.setChecked(true);
// Set action bar title
setTitle(menuItem.getTitle());
// Close the navigation drawer
drawerLayout.closeDrawers();
return;
case R.id.message_Fragment:
Log.d(TAG,"Message Fragment Pressed ");
fragment = new Messages_Fragment();
break;
case R.id.addMedia_Fragment:
Log.d(TAG,"Add Media Fragment Pressed ");
fragment = new UserProfile_Photos();
break;
case R.id.invite_Fragment:
Log.d(TAG,"Invite Fragment Pressed ");
//fragmentClass = fragment_1.class;
onInviteClicked();
// Highlight the selected item has been done by NavigationView
menuItem.setChecked(true);
// Set action bar title
setTitle(menuItem.getTitle());
// Close the navigation drawer
drawerLayout.closeDrawers();
return;
case R.id.setting_Fragment:
Log.d(TAG,"Setting Fragment Pressed ");
fragment = new Setting_NavigationDrawer();
break;
case R.id.help_Fragment:
Log.d(TAG,"Help Fragment Pressed ");
//fragmentClass = fragment_1.class;
fragment=new FullScreen_WebView();
Bundle urlToSend=new Bundle();
urlToSend.putString("webViewURL","http://boysjoys.com/test/Android/Data/help.php");
//urlToSend.putString("webViewURL",chat_wrapper.getGoogleSearch().get(2));
fragment.setArguments(urlToSend);
FragmentTransaction transaction=((Activity)context).getFragmentManager().beginTransaction();
//fragmentTrasaction.replace(R.id.Chat_Screen_Main_Layout,gallery);
//transaction.replace(R.id.Chat_Screen_Main_Layout,fullScreen_webView);
transaction.replace(R.id.Navigation_Main_Layout,fragment);
transaction.addToBackStack(null);
transaction.commit();
// Highlight the selected item has been done by NavigationView
menuItem.setChecked(true);
// Set action bar title
setTitle(menuItem.getTitle());
// Close the navigation drawer
drawerLayout.closeDrawers();
return;
case R.id.signOut_Fragment:
new CheckLoginStatus(this, 0).execute();
new Send_Session_Logout(this).execute();
drawerLayout.closeDrawers();
return;
}
FragmentTransaction fragmentTransaction=getFragmentManager().beginTransaction();
fragmentTransaction.add(R.id.Navigation_Main_Layout, fragment);
fragmentTransaction.setCustomAnimations(R.animator.enter_anim,R.animator.exit_anim);
fragmentTransaction.addToBackStack(null);
fragmentTransaction.commit();
// Highlight the selected item has been done by NavigationView
menuItem.setChecked(true);
// Set action bar title
setTitle(menuItem.getTitle());
// Close the navigation drawer
drawerLayout.closeDrawers();
}
private void settingHeaderItems(){
View HeaderLayout = navigationView.inflateHeaderView(R.layout.navigation_header_image);
//Main Screen Tabs With VIew Pager
headerImage = HeaderLayout.findViewById(R.id.HeaderImageView);
headerImage.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
FragmentTransaction fragmentTransaction=getFragmentManager().beginTransaction();
fragmentTransaction.replace(R.id.Navigation_Main_Layout, new EditProfile());
fragmentTransaction.setCustomAnimations(R.animator.enter_anim,R.animator.exit_anim);
fragmentTransaction.addToBackStack(null);
fragmentTransaction.commit();
drawerLayout.closeDrawers();
}
});
headerUserImage = HeaderLayout.findViewById(R.id.HeaderProfilePicture);
userName = HeaderLayout.findViewById(R.id.myImageViewText);
userViews = HeaderLayout.findViewById(R.id.profileViews);
if (Session.getUserCover().equals("Invalid Image")){
headerImage.setBackgroundResource(R.drawable.cam_icon);
}else {
Log.d(TAG,"Path Of Cover Photo "+Session.getUserCover());
Bitmap coverPhoto= BitmapFactory.decodeFile(Session.getUserCover());
headerImage.setImageBitmap(coverPhoto);
// Glide.with(context).load(Session.getUserCover()).apply(new RequestOptions().skipMemoryCache(true).onlyRetrieveFromCache(false).diskCacheStrategy(DiskCacheStrategy.NONE)).into(holder.HeaderImage);
}
Bitmap bitmap = BitmapFactory.decodeFile(Session.getUserImage());
userName.setText(Session.getUserFname()+" "+Session.getUserLname());
headerUserImage.setImageBitmap(bitmap);
if (Session.getProfileCounter().equals("0")){
userViews.setText("No Profile VIsits");
}
else {
userViews.setText("Profile views: "+ Session.getProfileCounter());
}
}
#Override
protected void onPostCreate(#Nullable Bundle savedInstanceState) {
super.onPostCreate(savedInstanceState);
drawerToggle.syncState();
}
#Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
drawerToggle.onConfigurationChanged(newConfig);
}
}
I tired alot to resolve this issue and after months of googling and stackoverflow i m still stuck in same issue.
Issue example of Point 1:- When navigation drawer load first everything looks good, view pager changes title as per fragment. then if i click on Navigation Drawer's Menu which also open another fragment (For Ex: Recent Message). then title change successfully but when i press back button or trying to press home button which calls viewpager then title remain same as before i.e. Recent Message.
Setting Title in each fragment like this.
toolbar = (Toolbar) getActivity().findViewById(R.id.Navigation_Drawer_toolbar);
ImageView appLogo = toolbar.findViewById(R.id.appLogo);
TextView fragmentTitle = toolbar.findViewById(R.id.activityTitle);
appLogo.setImageResource(DrawableImage);
fragmentTitle.setText(Title);
If application have to use Navigation Drawer which should be present in all views, then Fragment should be used. And its not a bad practice.
Toolbar doesn't change title of fragment, when press back button or
going forward by clicking button or some link.
Create a method in Base Activity
public void setFragmentTitle(String title){
if(!TextUtils.isEmpty(title))
mTitleText.setText(title);
}
Access this method from your individual Fragments in onCreateView
((LandingActivity) getActivity()).setFragmentTitle(getActivity().getString(R.string.fragment_title));
Navigation hamburger keep showing if i change into back arrow by using: getSupportActionBar().setDisplayHomeAsUpEnabled(true); then back arrow opens drawers but not going back to last fragment.
Use onOptionItemSelected on click of android.R.id.home , pop the current Fragment
Fragment State Loss when pressed back button or jumping directly to some fragment
You have to mention the values which needs to be persisted and repopulate it.
public class ActivityABC....{
private String mFName;
private TableSelectFragment mFragment;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
FragmentManager fm = getSupportFragmentManager();
if (savedInstanceState != null) {
mFragment=(TableSelectFragment)fm.getFragment(savedInstanceState,"TABLE_FRAGMENT");
mFName = savedInstanceState.getString("FNAMETAG");
}else{
mFragment = new TableSelectFragment();
fm.beginTransaction().add(R.id.content_frame,mFragment,"TABLE_FRAGMENT").commit();
}
}
#Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
getSupportFragmentManager().putFragment(outState,"TABLE_FRAGMENT",mFragment);
}
}
In your Fragment
TableSelectFragment{
....
private String mFName;
#Override
public void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setRetainInstance(true);
}
#Override
public void onSaveInstanceState(#NonNull Bundle outState) {
outState.putString("FNAMETAG", mFName);
super.onSaveInstanceState(outState);
}
}
EDIT 1: For Fragment Title not getting updated in BackButton press
While adding Fragment to backstack , do the following.
In your parent Activity
FragmentManager fragMan = getSupportFragmentManager();
FragmentTransaction fragTrans = fragMan.beginTransaction();
LandingFrag landingFrag = LandingFrag.newInstance();
fragTrans.replace(R.id.landing_view, landingFrag,"LandingFrag");
fragTrans.addToBackStack(null);
fragTrans.commit();
landingFrag.setUserVisibleHint(true);
Now override onBackPressed in parent Activity
#Override
public void onBackPressed() {
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
if (drawer.isDrawerOpen(GravityCompat.START)) {
drawer.closeDrawer(GravityCompat.START);
} else {
.. POP Fragment Backstack here
Fragment fragment = getActiveFragment();
if(fragment instanceof LandingFrag)
{
LandingFrag landingFrag = (LandingFrag)fragment;
landingFrag.setUserVisibleHint(true);
}
}
public Fragment getActiveFragment() {
if (getSupportFragmentManager().getBackStackEntryCount() == 0) {
return null;
}
Fragment fragment=null;
int trackBackValue = 1;//INCREASE OR DECREASE ACCORDING TO YOUR BACK STACK
try {
fragment = getSupportFragmentManager().getFragments().get(getSupportFragmentManager().getBackStackEntryCount() - trackBackValue);
} catch (Exception e) {
}
return fragment;
}
Now in LandingFrag
public class LandingFrag...
{
#Override
public void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setUserVisibleHint(false);
.....
}
#Override
public void onViewStateRestored(#Nullable Bundle savedInstanceState) {
super.onViewStateRestored(savedInstanceState);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
................
((LandingActivity) getActivity()).setFragmentTitle("Current Fragment Title");
}
#Override
public void setUserVisibleHint(boolean isVisibleToUser) {
super.setUserVisibleHint(isVisibleToUser);
if(isVisibleToUser){
try {
((LandingActivity) getActivity()).setFragmentTitle("Current Fragment Title");
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
Whether is it good practice to doing all task within Fragment with
Single Activity.
It is a good practice to use fragments when you use with navigation drawers, tabs or bottom navigation.
Other than that, fragments are mostly preferred for reusable UI with different data.
You are doing all task within fragment with Single Activity because you are using navigation draw and tabs, so It is a good practice, I'd say.
Toolbar doesn't change title of fragment, when press back button or
going forward by clicking button or some link.
You need to manually set the title for fragment whenever you are adding/replacing new fragment OR
on back press(backstack change), through Fragment only or using OnBackStackChangedListener as mentioned in docs.
You are just setting them while you are clicking through navigation items and not while clicking button or some link
Navigation hamburger keep showing if i change into back arrow by
using: getSupportActionBar().setDisplayHomeAsUpEnabled(true); then
back arrow opens drawers but not going back to last fragment.
That too you'd need to handle manually. using onOptionItemSelected on click of android.R.id.home item.
Like poping fragments out from stack.
The cause of your title persistence on back is setting title from Activity.
ie using this setTitle(menuItem.getTitle()); instead set them through Fragment or if you are setting them trough Fragment remove from selectDrawerItem method.
Also at the end of selectDrawerItem method you are using fragmentTransaction.add instead use fragmentTransaction.replace
Related
When my application is opened Home screen is shown first.On Home screen I have NavigationDrawer which get opened after pressing HamburgerIcon.Later i go to different fragments.When I am in Other fragments other than Home Activity I need to show back button on Toolbar to come to previous fragment.But its every time showing Hamburger icon.How to do this ?
This is code for setting Toolbar in XML
<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"
android:id="#+id/drawerLayout"
tools:context="biz.fyra.myApp.ActivityTwo">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<android.support.v7.widget.Toolbar
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#ccc"
android:minHeight="?attr/actionBarSize">
<ImageView
android:id="#+id/tooImage"
android:src="#drawable/latest"
android:layout_width="match_parent"
android:layout_gravity="center_horizontal"
android:layout_height="40dp" />
</android.support.v7.widget.Toolbar>
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/frame">
</FrameLayout>
</LinearLayout>
<android.support.design.widget.NavigationView
android:layout_width="300dp"
android:layout_height="match_parent"
android:layout_gravity="start"
app:headerLayout="#layout/nav_header"
android:id="#+id/navigationView"
app:menu="#menu/actionmenu"
android:background="#android:color/white">
</android.support.design.widget.NavigationView>
</android.support.v4.widget.DrawerLayout>
How to achieve this ?
If i understand right, you are using one activity with fragments replacing. So, looking at that you would have something like this:
Important: Activity theme should extends Theme.AppCompat.Light.NoActionBar
Activity:
public class MainActivity extends AppCompatActivity
implements NavigationView.OnNavigationItemSelectedListener {
private DrawerLayout drawer;
private Toolbar toolbar;
private ActionBarDrawerToggle toggle;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
drawer = findViewById(R.id.drawer);
toolbar = findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
toggle = new ActionBarDrawerToggle(
this,
drawer,
toolbar,
R.string.navigation_drawer_open,
R.string.navigation_drawer_close
);
drawer.addDrawerListener(toggle);
toggle.syncState();
NavigationView navigationView = findViewById(R.id.nav_view);
navigationView.setNavigationItemSelectedListener(this);
// First creation
if (savedInstanceState == null)
showFragment(StartFragment.newInstance());
}
/**
* Using in Base Fragment
*/
protected ActionBarDrawerToggle getToggle() {
return toggle;
}
#Override
public void onBackPressed() {
Fragment fragment = getSupportFragmentManager().findFragmentById(R.id.frame);
if (drawer.isDrawerOpen(GravityCompat.START)) {
drawer.closeDrawer(GravityCompat.START);
} else if (fragment instanceof OnBackPressedListener) {
((OnBackPressedListener) fragment).onBackPressed();
} else {
super.onBackPressed();
}
}
#Override
public boolean onNavigationItemSelected(#NonNull MenuItem item) {
drawer.closeDrawer(GravityCompat.START);
switch (item.getItemId()) {
case R.id.start: {
showFragment(StartFragment.newInstance());
break;
}
case R.id.orders: {
showFragment(OrdersFragment.newInstance());
break;
}
case R.id.category: {
showFragment(CategoryFragment.newInstance());
break;
}
case R.id.calendar: {
showFragment(CalendarFragment.newInstance());
break;
}
case R.id.settings: {
showFragment(SettingsFragment.newInstance());
break;
}
case R.id.about: {
showFragment(AboutFragment.newInstance());
break;
}
return true;
}
private void showFragment(Fragment fragment) {
getSupportFragmentManager().beginTransaction().replace(R.id.frame, fragment).commit();
}
}
Interface for sending backpress events from activity to fragments:
public interface OnBackPressedListener {
void onBackPressed();
}
And Abstract Base Fragment which you should extends and implement methods:
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.widget.DrawerLayout;
import android.support.v7.app.ActionBar;
import android.support.v7.app.ActionBarDrawerToggle;
import android.support.v7.widget.Toolbar;
import ...
/**
* Abstract fragment with FAB button, Toolbar and 2 interfaces:
OnClick, OnBackPress
*
*/
public abstract class BaseFragment extends Fragment implements
View.OnClickListener, OnBackPressedListener {
protected FloatingActionButton fab;
protected Toolbar toolbar;
protected ActionBar actionBar;
protected ActionBarDrawerToggle toggle;
protected DrawerLayout drawer;
protected boolean mToolBarNavigationListenerIsRegistered = false;
#Override
public void onViewCreated(#NonNull View view, #Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
fab = ((MainActivity)getActivity()).findViewById(R.id.fab);
toolbar = ((MainActivity) getActivity()).findViewById(R.id.toolbar);
actionBar = ((MainActivity) getActivity()).getSupportActionBar();
drawer = ((MainActivity) getActivity()).findViewById(R.id.drawer_layout);
toggle = ((MainActivity) getActivity()).getToggle();
fab.setOnClickListener(this);
}
/**
* Simplify fragment replacing in child fragments
*/
protected void replaceFragment(#NonNull Fragment fragment) {
FragmentManager fm = getActivity().getSupportFragmentManager();
fm.beginTransaction().replace(R.id.container, fragment).commit();
}
// hide FAB button
protected void hideFab() {
fab.hide();
}
//show FAB button
protected void showFab() {
fab.show();
}
/**
* Shows Home button as Back button
* Took from here {#link}https://stackoverflow.com/a/36677279/9381524
* <p>
* To keep states of ActionBar and ActionBarDrawerToggle synchronized,
* when you enable on one, you disable on the other.
* And as you may notice, the order for this operation is disable first, then enable - VERY VERY IMPORTANT!!!
*
* #param show = true to show <showHomeAsUp> or show = false to show <Hamburger> button
*/
protected void showBackButton(boolean show) {
if (show) {
// Remove hamburger
toggle.setDrawerIndicatorEnabled(false);
// Show back button
actionBar.setDisplayHomeAsUpEnabled(true);
// when DrawerToggle is disabled i.e. setDrawerIndicatorEnabled(false), navigation icon
// clicks are disabled i.e. the UP button will not work.
// We need to add a listener, as in below, so DrawerToggle will forward
// click events to this listener.
if (!mToolBarNavigationListenerIsRegistered) {
toggle.setToolbarNavigationClickListener(v -> onBackPressed());
mToolBarNavigationListenerIsRegistered = true;
}
} else {
// Remove back button
actionBar.setDisplayHomeAsUpEnabled(false);
// Show hamburger
toggle.setDrawerIndicatorEnabled(true);
// Remove the/any drawer toggle listener
toggle.setToolbarNavigationClickListener(null);
mToolBarNavigationListenerIsRegistered = false;
}
// So, one may think "Hmm why not simplify to:
// .....
// getSupportActionBar().setDisplayHomeAsUpEnabled(enable);
// mDrawer.setDrawerIndicatorEnabled(!enable);
// ......
// To re-iterate, the order in which you enable and disable views IS important #dontSimplify.
}
/**
* Simplify setTitle in child fragments
*/
protected void setTitle(int resId) {
getActivity().setTitle(getResources().getString(resId));
}
//
#Override
public abstract void onClick(View v);
// Handles BackPress events from MainActivity
#Override
public abstract void onBackPressed();
}
All fragments with Back Button used in MainActivity should extends from this BaseFragment.
You can try something like
#Override
protected void onCreate(Bundle savedInstanceState)
{ super.onCreate(savedInstanceState);
[...]
if (getSupportActionBar() != null)
{ getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setHomeButtonEnabled(true);
}
[...]
}
#Override
public boolean onOptionsItemSelected(MenuItem item)
{ if (getSupportFragmentManager().getBackStackEntryCount() > 0)
{ switch (item.getItemId())
{ case android.R.id.home:
onBackPressed();
return true;
}
}
[...]
}
I have two fragments FragmentHome and FragmentAbout, I have added NavigationDrawer to app when I click Home it opens FragmentHome and About opens FragmentAbout, when I open FragmentAbout I am also adding it to backstack. This is working fine.
Now the problem is when I click on About and press back button it goes to the FragmentHome but the NavigationDrawer still shows the About as selected item, I want to change this selected item to Home when I press back button from FragmentAbout
Home Activity:
public class ActivityHome extends AppCompatActivity implements NavigationView.OnNavigationItemSelectedListener {
Toolbar toolbar;
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_home);
// Toolbar
toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
// Drawer layout
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.nav_drawer_layout);
ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(
this, drawer, toolbar, R.string.nav_drawer_open, R.string.nav_drawer_close);
assert drawer != null;
drawer.setDrawerListener(toggle);
toggle.syncState();
// Navigation view
NavigationView navigationView = (NavigationView) findViewById(R.id.nav_view);
assert navigationView != null;
navigationView.setNavigationItemSelectedListener(this);
// Open first menu item
navigationView.getMenu().performIdentifierAction(R.id.nav_home, 0);
// Set first item checked
navigationView.setCheckedItem(R.id.nav_home);
}
#SuppressWarnings("StatementWithEmptyBody")
#Override
public boolean onNavigationItemSelected(MenuItem item) {
final MenuItem menuItem = item;
// Check if menu item is selected
if (item.isChecked())
item.setChecked(false);
else
item.setChecked(true);
// Handle navigation view item clicks here.
int id = item.getItemId();
if (id == R.id.nav_home) {
// Open home fragment
getSupportFragmentManager().beginTransaction()
.replace(R.id.frame_layout, new FragmentHome())
.commit();
} else if (id == R.id.nav_about) {
toolbar.setTitle("About");
// Open home fragment
getSupportFragmentManager().beginTransaction()
.replace(R.id.frame_layout, new FragmentAbout())
.addToBackStack(null)
.commit();
}
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.nav_drawer_layout);
assert drawer != null;
drawer.closeDrawer(GravityCompat.START);
return true;
}
#Override
public void onBackPressed() {
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.nav_drawer_layout);
assert drawer != null;
if (drawer.isDrawerOpen(GravityCompat.START)) {
drawer.closeDrawer(GravityCompat.START);
} else {
super.onBackPressed();
}
}}
FragmentHome
public class FragmentHome extends Fragment {
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_home, container, false);
}
#Override
public void onResume() {
super.onResume();
((AppCompatActivity)getActivity()).getSupportActionBar().setTitle(R.string.fragment_home_title);
}
}
FragmentAbout code is same as FragmentHome just layout change.
I have searched a lot on stackoverflow but didn't find any solution yet, so if someone know how to do this please tell me.
There is a OnBackStackChangedListener that you can use for this. Tried it and it works great.
public Fragment getCurrentFragment() {
return this.getSupportFragmentManager().findFragmentById(R.id.fragment_container);
}
#Override
protected void onCreate(Bundle savedInstanceState) {
...
this.getSupportFragmentManager().addOnBackStackChangedListener(
new FragmentManager.OnBackStackChangedListener() {
public void onBackStackChanged() {
Fragment current = getCurrentFragment();
if (current instanceof MyFragmentA) {
navigationView.setCheckedItem(R.id.nav_myfragA);
} else {
navigationView.setCheckedItem(R.id.nav_myfragB);
}
}
});
...
}
This might not be a good solution, but at least it is acceptable for me. You need to store fragment's position inside stack variable (ex: List) whenever a fragment menu is clicked from nav drawer. Then override onBackPressed to remove the last value from stack, and set drawer position to the current last value of stack. Here's the example:
private List<Integer> itemPositionStacks = new ArrayList<>();
protected void onCreate(#Nullable Bundle savedInstanceState) {
itemPositionStacks.add(currentSelectedPosition);
}
public void onNavigationViewItemSelected(int itemId) {
Fragment fr = null;
switch (itemId) {
case 0:
fr = new aFragment();
break;
case 1:
fr = new bFragment();
break;
}
getSupportFragmentManager().beginTransaction()
.replace(R.id.container, fr)
.addToBackStack(null)
.commit();
Drawer.getInstance().setDrawerChecked(itemId);
itemPositionStacks.add(itemId);
}
public void onBackPressed() {
if(itemPositionStacks.size() > 1) {
itemPositionStacks.remove(itemPositionStacks.size() - 1);
Drawer.getInstance().setDrawerChecked(itemIdStacks.get(itemIdStacks.size() - 1));
}
super.onBackPressed();
}
In your onBackPressed() function ..
you must choose which item to be selected by using
drawer.setCheckedItem(R.id.nav_home);
and remove the selection of the another item
drawer.getMenu().findItem(R.id.nav_about).setChecked(false);
I am looking for advice on navigation pattern in android. In the current state of the app i am working at, I have a navigation drawer and can access some elements that are mostly dynamically changed. When I click an item from the navigation drawer I show a fragment. So anytime i want i go back to the left menu. Now, i have to move "New screen" activity from picture, in the same pattern, to have access to the drawer. The only way to get to "New screen" activity is from one of the fragments.
Fragment 0 has a list of items. Clicking on it it opens the "New screen". How should i approach this to have the drawer in this activity as well?
I don't want to have too much boiler code.
It already has problems on android 4.2.2, I can only imagine now how this modifications will affect performance.
I need to understand what is best solution, have no experience with this. All I want is ideas and maybe get some know-how on this pattern so i don't cause memory leaks and don't duplicate code.
Thank you for your time.
1-I would suggest to create a Base Activity which will further extends your ActionBarActivity.
2-activity_sliding_drawer layout file for this activity will contains a main_container for adding fragments and DrawerLayout:-
<android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/drawer_layout"
android:layout_width="match_parent"
android:layout_height="match_parent">
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<FrameLayout
android:id="#+id/frame_container"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<FrameLayout
android:layout_gravity="bottom"
android:id="#+id/bottom_container"
android:layout_height="wrap_content"
android:visibility="gone"
android:layout_width="match_parent"
android:background="#color/white">
</FrameLayout>
</FrameLayout>
<fragment
android:id="#+id/slidingMenuFragment"
android:name="om.ooredoo.fragments.SlidingMenuFragment"
android:layout_width="#dimen/slidingmenu__parent_width"
android:layout_height="fill_parent"
android:layout_gravity="start" />
3- Then inside base activity, we will have all basic functions for add and replace fragments and also 2 function which will handle visibility for drawer menu icon, i.e lockDrawerMenu() & unlockDrawerMenu().
4- Put the following code inside your base activity (AbstractActivity in my case):-
public abstract class AbstractActivity extends ActionBarActivity {
public DrawerLayout mDrawerLayout;
private ActionBarDrawerToggle mDrawerToggle;
private boolean bSupportActionBar = true;
private boolean mSlidingMenuLocked = false;
private BackPressListener mBackPressListener;
private String title;
boolean ismSlidingMenuLocked() {
return mSlidingMenuLocked;
}
#Override
protected void onCreate(final Bundle savedInstanceState) {
requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);
requestWindowFeature(Window.FEATURE_PROGRESS);
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_sliding_drawer);
if (bSupportActionBar) {
mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
mDrawerLayout.setScrimColor(getResources().getColor(android.R.color.transparent));
mDrawerToggle = new ActionBarDrawerToggle(this, mDrawerLayout,
R.drawable.ic_navigation_drawer, //nav menu toggle icon
R.string.drawer_open, // nav drawer open - description for accessibility
R.string.drawer_close // nav drawer close - description for accessibility
) {
public void onDrawerClosed(View view) {
if (getSupportActionBar().getTitle().equals(getString(R.string.app_name)))
getSupportActionBar().setTitle(title);
invalidateOptionsMenu();
}
public void onDrawerOpened(View drawerView) {
title = (String) getSupportActionBar().getTitle();
getSupportActionBar().setTitle(getString(R.string.app_name));
// calling onPrepareOptionsMenu() to hide action bar icons
invalidateOptionsMenu();
}
};
mDrawerLayout.setDrawerListener(mDrawerToggle);
mDrawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED);
unlockDrawerMenu();
}
}
#Override
protected void onStart() {
super.onStart();
setSupportProgressBarIndeterminateVisibility(false);
}
#Override
protected void onDestroy() {
super.onDestroy();
if (mHandler != null) {
mHandler.removeCallbacksAndMessages(null);
mHandler = null;
}
}
public void addNewFragmentWithBackStack(Fragment fragment) {
if (fragment != null) {
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.replace(R.id.frame_container, fragment, fragment.getClass().getSimpleName())
.addToBackStack(fragment.getClass().getSimpleName())
.commit();
} else {
Log.e("AbstractActivity", "Error in creating fragment");
}
}
public void addNewFragmentWithBackStack(Fragment fragment, boolean animation) {
if (fragment != null) {
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.setCustomAnimations(R.anim.slide_up_anim, 0);
fragmentTransaction.replace(R.id.frame_container, fragment, fragment.getClass().getSimpleName())
.addToBackStack(fragment.getClass().getSimpleName())
.commit();
} else {
Log.e("AbstractActivity", "Error in creating fragment");
}
}
public void addNewBottomFragmentWithBackStack(Fragment fragment) {
if (fragment != null) {
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.setCustomAnimations(R.anim.slide_up_anim, 0);
fragmentTransaction.replace(R.id.bottom_container, fragment)
.addToBackStack(fragment.getClass().getSimpleName())
.commit();
} else {
Log.e("AbstractActivity", "Error in creating fragment");
}
}
public void replaceAndClearBackStack(Fragment fragment) {
//clear backStack
FragmentManager fm = getSupportFragmentManager();
fm.popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);
FragmentTransaction transaction = fm.beginTransaction();
transaction.replace(R.id.frame_container, fragment)
.addToBackStack(fragment.getClass().getSimpleName());
transaction.commit();
}
#Override
protected void onPostCreate(Bundle savedInstanceState) {
super.onPostCreate(savedInstanceState);
// Sync the toggle state after onRestoreInstanceState has occurred.
if (bSupportActionBar)
mDrawerToggle.syncState();
}
#Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
// Pass any configuration change to the drawer toggles
if (bSupportActionBar)
mDrawerToggle.onConfigurationChanged(newConfig);
}
public void lockDrawerMenu() {
((DrawerLayout) findViewById(R.id.drawer_layout)).setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED);
if (bSupportActionBar) {
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
mDrawerToggle.setDrawerIndicatorEnabled(false);
}
mSlidingMenuLocked = true;
}
public void unlockDrawerMenu() {
((DrawerLayout) findViewById(R.id.drawer_layout)).setDrawerLockMode(DrawerLayout.LOCK_MODE_UNLOCKED);
mSlidingMenuLocked = false;
mDrawerToggle.setDrawerIndicatorEnabled(true);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setHomeButtonEnabled(true);
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
// toggle nav drawer on selecting action bar app icon/title
if (!ismSlidingMenuLocked() && mDrawerToggle.onOptionsItemSelected(item)) {
return true;
}
// Handle action bar actions click
switch (item.getItemId()) {
case android.R.id.home:
if (ismSlidingMenuLocked()) {
onBackPressed();
return true;
}
return true;
default: {
return super.onOptionsItemSelected(item);
}
}
}
public BackPressListener getBackPressListener() {
return mBackPressListener;
}
public void setBackPressListener(BackPressListener mBackPressListener) {
this.mBackPressListener = mBackPressListener;
}
#Override
public void onBackPressed() {
if (getSupportFragmentManager().getFragments().size() > 0) {
for (Fragment frag : getSupportFragmentManager().getFragments()) {
if (frag != null && frag.isAdded() && frag instanceof AbstractParentFragment) {
if (frag.getChildFragmentManager().getBackStackEntryCount() > 0) {
frag.getChildFragmentManager().popBackStack();
return;
}
}
}
}
if (mBackPressListener != null) {
if (mBackPressListener.onBackPress())
return;
} else {
if (getSupportFragmentManager().getBackStackEntryCount() == 1) {
this.finish();
return;
}
super.onBackPressed();
}
}
void supportActionBar(boolean support) {
bSupportActionBar = support;
}}
5- Now create a Sliding drawer activity which extends your base activity and launch your main fragment inside this main fragment open your other fragments basics of item clicked in sliding drawer.
Now you have two function to handle sliding drawer if sliding drawer icon is visible then it works on the basics of item clicked else it will a normal fragment with action bar.
Hope this will help you. !!!
I have created MainActivity with NavigationView. When Activity is opened I want to automatically select the first item in the navigation drawer and open Fragment under that item. I've searched a lot but didn't find any proper solutions.
What is the proper way to do this ?
Main Activity:
public class MainActivity extends AppCompatActivity implements Config {
private NavigationView navigationView;
private DrawerLayout drawerLayout;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
toolbar.setTitleTextColor(getResources().getColor(R.color.colorIcons));
if (null != getSupportActionBar())
getSupportActionBar().setLogo(R.drawable.ic_blogger_white);
//Start PostListFragmentWebView
/*PostListFragmentWebView postListFragmentWebView = new PostListFragmentWebView();
getSupportFragmentManager().beginTransaction()
.replace(R.id.frame, postListFragmentWebView)
.commit();*/
//Initializing NavigationView
navigationView = (NavigationView) findViewById(R.id.navigationView);
//Setting Navigation View Item Selected Listener to handle the item click of the navigation menu
navigationView.setNavigationItemSelectedListener(new NavigationView.OnNavigationItemSelectedListener() {
#Override
public boolean onNavigationItemSelected(MenuItem menuItem) {
//Checking if the item is in checked state or not, if not set it to checked state.
if (menuItem.isChecked()) menuItem.setChecked(false);
else menuItem.setChecked(true);
//Closing drawer on item click
drawerLayout.closeDrawers();
//Check to see which item was clicked and perform the appropriate action.
switch (menuItem.getItemId()) {
case R.id.posts:
PostListFragmentWebView postListFragment = new PostListFragmentWebView();
getSupportFragmentManager().beginTransaction()
.replace(R.id.frame, postListFragment)
.commit();
return true;
case R.id.pages:
PageListFragmentWebView pagetListFragment = new PageListFragmentWebView();
getSupportFragmentManager().beginTransaction()
.replace(R.id.frame, pagetListFragment)
.commit();
return true;
case R.id.blog:
BlogInfoFragmentWebView blogInfoFragment = new BlogInfoFragmentWebView();
getSupportFragmentManager().beginTransaction()
.replace(R.id.frame, blogInfoFragment)
.commit();
return true;
default:
Toast.makeText(getApplicationContext(), getResources().getString(R.string.drawer_error), Toast.LENGTH_SHORT).show();
return true;
}
}
});
// Initializing Drawer Layout and ActionBarToggle
drawerLayout = (DrawerLayout) findViewById(R.id.drawerLayout);
ActionBarDrawerToggle actionBarDrawerToggle = new ActionBarDrawerToggle(this, drawerLayout, toolbar, R.string.open_drawer, R.string.close_drawer) {
#Override
public void onDrawerClosed(View drawerView) {
// Code here will be triggered once the drawer closes as we don't want anything to happen so we leave this blank.
super.onDrawerClosed(drawerView);
}
#Override
public void onDrawerOpened(View drawerView) {
// Code here will be triggered once the drawer open as we dont want anything to happen so we leave this blank.
super.onDrawerOpened(drawerView);
}
};
//Setting the actionbarToggle to drawer layout
drawerLayout.setDrawerListener(actionBarDrawerToggle);
drawerLayout.getChildAt(0).setSelected(true);
//calling sync state is necessary or else your hamburger icon wont show up
actionBarDrawerToggle.syncState();
}
}
In onCreate(), following code will load the first item's fragment upon first start:
if (savedInstanceState == null) {
navigationView.getMenu().performIdentifierAction(R.id.posts, 0);
}
Thanks to calvinfly for this comment.
Add android:checked="true" to your first menu item.
And manually select one item, using
getSupportFragmentManager().beginTransaction().replace(R.id.frame, postListFragment).commit();
to open fragment.
Instead of normal listener ...
navView.setNavigationItemSelected(new Navigation.View.OnNavigationItemSelectedListener() {bla, bla, bla})
Create the listener as an Obj:
NavigationView.OnNavigationItemSelectedListener navViewListener;
navView.setNavigationItemSelectedListener(navViewListener = new NavigationView.OnNavigationItemSelectedListener() {bla, bla, bla})
...and use the Obj to trigger the listener event:
navViewListener.onNavigationItemSelected(navView.getMenu().getItem(0));
...where getItem(0) is the first menu item.
Use a method getItem(0).setChecked(true) or android:checked="true" at its menu item XML definition.
You could also use navigationView.setCheckedItem(R.id.default)(javadoc) after you setup your navigationview.
just add this code in onCreate method:
FragmentTransaction ftrans = getFragmentManager().beginTransaction();
ftrans.replace(R.id.container, <yourfragment>).commit();
Work for me !
This can be done even better while considering orientation and other configuration changes. We could select whatever nav drawer menuitem depending on whether we are coming from a previous state. Check: For the Navigation drawer wielding Activity:-
public static final String SELECTED_NAV_MENU_KEY = "selected_nav_menu_key";
// The selected grid position
private int mSelectedNavMenuIndex = 0;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_demo);
...........................................................
navigationView.setNavigationItemSelectedListener(this);
if (savedInstanceState != null) {
// Recover assets
mSelectedNavMenuIndex = savedInstanceState.getInt(SELECTED_NAV_MENU_KEY);
// Recover menu as selected
MenuItem menuItem = navigationView.getMenu().getItem(mSelectedNavMenuIndex);
toggleNavMenuItemCheck(menuItem);
navigationView.getMenu().performIdentifierAction(menuItem.getItemId(), mSelectedNavMenuIndex);
return;
} else {
MenuItem menuItem = navigationView.getMenu().getItem(mSelectedNavMenuIndex);
toggleNavMenuItemCheck(menuItem);
navigationView.getMenu().performIdentifierAction(menuItem.getItemId(), mSelectedNavMenuIndex);
}
}
The toggle method that helps uncheck or check the menu item
private void toggleNavMenuItemCheck(MenuItem menuItem) {
if (menuItem.isChecked()){
menuItem.setChecked(false);
} else {
menuItem.setChecked(true);
}
}
This is how I save the state of the selected menu item. Check:-
#Override
public boolean onNavigationItemSelected(MenuItem item) {
int id = item.getItemId();
switch (id) {
case R.id.nav_explore:
showExploreFragment(null);
mSelectedNavMenuIndex = 0;
break;
case R.id.nav_orders:
mSelectedNavMenuIndex = 1;
break;
case R.id.nav_settings:
mSelectedNavMenuIndex = 2;
break;
default:
showExploreFragment(null);
mSelectedNavMenuIndex = 0;
}
drawer.closeDrawer(GravityCompat.START);
return true;
}
// Save any important data for recovery
#Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putInt(SELECTED_NAV_MENU_KEY, mSelectedNavMenuIndex);
}
NB: The line with code:
navigationView.getMenu().performIdentifierAction(menuItem.getItemId(), mSelectedNavMenuIndex);
Can be replaced by the code:
onNavigationItemSelected(menuItem);
in menu.xml remember to mention android:checkable="true" for single item and android:checkableBehavior="single" for a group of items.
<item
android:id="#+id/pos_item_help"
android:checkable="true"
android:title="Help" />
<group
android:id="#+id/group"
android:checkableBehavior="single">
<item
android:id="#+id/menu_nav_home"
android:icon="#drawable/ic_home_black_24dp"
android:title="#string/menu_nav_home" />
</group>
then inside NavigationItemSelectedListener use setCheckedItem(R.id.item_id_in_menu) to make it selected.
#Override
public boolean onNavigationItemSelected(#NonNull MenuItem item) {
switch (item.getItemId()) {
case R.id.pos_item_pos:
navigationView.setCheckedItem(R.id.pos_item_pos);
break;
case R.id.pos_item_orders:
navigationView.setCheckedItem(R.id.pos_item_orders);
break;
default:
}
return true;
}
And you do not have to do the dirty task of managing the selected item anymore. navigationView manages it by self.
1.) To land to the HomeFragment initially, use this inside your onCreate() in MainActivity:
Fragment fragment = new HomeFragment();
// replacing the fragment
if (fragment != null) {
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
ft.replace(R.id.content_frame, fragment);
ft.commit();
}
2.) To set the item as selected in navigationDrawer set the item as checked in navigation_menu.xml
android:checked = "true"
I recently started updating my app to use the new Toolbar component introduced in Android 5.0 with navigation drawer. Flow of app is : MainActivity which has a toolbar, navigation drawer with menu 1. Home 2. Cart.
Home Menu navigates to "Home Detail" through a button in it.
Layout of "MainActivity" :
<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"
android:orientation="vertical">
<include
android:id="#+id/toolbar"
layout="#layout/toolbar" />
<android.support.v4.widget.DrawerLayout
android:id="#+id/drawer"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<FrameLayout android:id="#+id/activity_frame"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
<ListView
android:id="#+id/left_drawer"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="start"
android:background="#android:color/white"
android:choiceMode="singleChoice"
android:divider="#android:color/transparent"
android:dividerHeight="0dp"
android:listSelector="#android:color/transparent" />
</android.support.v4.widget.DrawerLayout>
I am adding two fragments HomeFragment,CartFragment on "MainActivity" on menu selected from drawer as below, default selection is position 0 i.e "Home"
class "MainActivity.java" ::
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mTitle = mDrawerTitle = getTitle();
drawer = (DrawerLayout) findViewById(R.id.drawer);
mToolbar = (Toolbar) findViewById(R.id.toolbar);
tvTitle = (TextView) mToolbar.findViewById(R.id.toolbar_title);
if (mToolbar != null) {
setSupportActionBar(mToolbar);
}
mDrawerToggle = new ActionBarDrawerToggle(this, drawer,mToolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close) {
public void onDrawerClosed(View view) {
getSupportActionBar().setTitle(mTitle);
}
public void onDrawerOpened(View drawerView) {
getSupportActionBar().setTitle(mDrawerTitle);
}
};
drawer.setDrawerListener(mDrawerToggle);
mDrawerList = (ListView) findViewById(R.id.left_drawer);
dataList = new ArrayList<DrawerItem>();
dataList.add(new DrawerItem(Constants.V_HOME, R.drawable.ic_launcher));
dataList.add(new DrawerItem(Constants.V_MY_CART, R.drawable.ic_launcher));
mDrawerList.setAdapter(adapterDrawer);
mDrawerList.setOnItemClickListener(new DrawerItemClickListener());
// to show first "Home fragment" on start up of application
if(savedInstanceState==null)
SelectItem(0);
}
public void SelectItem(int position) {
Fragment fragment = null;
switch (position) {
case 0:
fragment = new HomeFragment();
replaceFragment(fragment, Constants.V_TAG_HOME,false,"Home");
break;
case 1:
fragment = new CartFragment();
replaceFragment(fragment, Constants.V_TAG_MY_CART,false,"My Cart");
break;
}
drawer.closeDrawer(mDrawerList);
}
public void replaceFragment(Fragment fragment,String fragment_tag,boolean showHome,String title){
frgManager = this.getSupportFragmentManager();
FragmentTransaction ft = frgManager.beginTransaction();
ft.replace(R.id.activity_frame,fragment,fragment_tag);
if(showHome)
ft.addToBackStack(null);
ft.commit();
shouldDisplayHomeUp(showHome);
}
public void shouldDisplayHomeUp(boolean showHome){
if(showHome){
mDrawerToggle.setDrawerIndicatorEnabled(false);
drawer.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED);
getSupportActionBar().setHomeButtonEnabled(true);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
}else{
mDrawerToggle.setDrawerIndicatorEnabled(true);
drawer.setDrawerLockMode(DrawerLayout.LOCK_MODE_UNLOCKED);
getSupportActionBar().setDisplayHomeAsUpEnabled(false);
getSupportActionBar().setHomeButtonEnabled(false);
}
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId())
{
case android.R.id.home:
Toast.makeText(getApplicationContext(),"main act clicked", Toast.LENGTH_SHORT).show();
return false;
default:
return super.onOptionsItemSelected(item);
}
}
#Override
public void onBackPressed() {
// TODO Auto-generated method stub
if(frgManager.getBackStackEntryCount()>0){
getSupportFragmentManager().popBackStack();
// show the drawer icon when on moving back
shouldDisplayHomeUp(false);
}else{
super.onBackPressed();
}
mDrawerToggle.syncState();
}
My home fragment has button "Detail" on click of button,replaces to other fragment :"HomeDetailFragment"
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<Button
android:id="#+id/btnDetail"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Home detail" />
<FrameLayout
android:id="#+id/home_frame_container"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>
class "HomeFragment.java" btnDetail click event which replace to other fragment "HomeDetailFragment"::
btnDetail.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
Fragment fragment = new HomeDetailFragment();
((MainActivity)getActivity()).showDrawerIndicator(false);
FragmentManager frManager = getActivity().getSupportFragmentManager();
FragmentTransaction ft = frManager.beginTransaction();
ft.addToBackStack(null);
ft.replace(R.id.activity_frame, fragment).commit();
}
});
class "HomeDetailFragment.java" ::
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setHasOptionsMenu(true);
// update the actionbar to show the up carat/affordance
((MainActivity)getActivity()).getSupportActionBar().setDisplayHomeAsUpEnabled(true);
}
#Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
// TODO Auto-generated method stub
super.onCreateOptionsMenu(menu, inflater);
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case android.R.id.home:
// your code for order here
Toast.makeText(getActivity(), "home detail", Toast.LENGTH_LONG).show();
((MainActivity)getActivity()).onBackPressed();
return true;
}
return true;
}
My problems ::
1. In "HomeDetailFragment", I can see the "UP home icon" but cannot get the click event of home icon onOptionsItemSelected not being called, so cant navigate back to HomeFragment
2. When pressing the Phone Back Button, and again navigating to "Home Detail" it is not showing "UP home icon"
Please guide me.
In "HomeDetailFragment", I can see the "UP home icon" but cannot get the click event of home icon onOptionsItemSelected not being called, so cant navigate back to HomeFragment
One way to achieve this is by using the Toolbar from your MainActivity like so:
Toolbar mToolbar= ((MainActivity)getActivity()).mToolbar;
mToolbar.setNavigationIcon(getResources().getDrawable(R.drawable.ic_nav_back));
mToolbar.setNavigationOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Log.d("MrE", "home selected");
}
});
When pressing the Phone Back Button, and again navigating to "Home Detail" it is not showing "UP home icon"
The reason your code isn't getting called is because it is in the onCreate of your Fragment. Move it to the onCreateOptionsMenu instead to have it update.
#Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
// Put toolbar stuff from above here
super.onCreateOptionsMenu(menu, inflater);
}
I had the exact issue.
Use the setToolbarNavigationClickListener method.
In MainActivity.java,
actionBarToggle.setToolbarNavigationClickListener(new View.OnClickListener({
#Override
public void onClick(View v) {
MainActivity.this.onSupportNavigateUp();
}
});
Avoid implementing Up Navigation individually in Fragments.
You called getSupportActionBar().setDisplayHomeAsUpEnabled(true) which shows the button in the toolbar but doesn't activate it.
Calling getSupportActionBar().setHomeButtonEnabled(true); in addition should do the job.
You show the back-button in the toolbar from within the Fragment which is something I would avoid. Try moving this part to your Activity, when you do the FragmentTransaction.