I am working on android Navigation Drawer and through their documentation it looks like, the drawer can only extend Fragment Activity, so that to open drawer from all my activities, I need to make all my activities a fragment, which is not a feasible solution.
Is there a way I can open a drawer that extends FragmentActivity from an Activity?
When I try to extend my drawer activity from Activity class, and another activity that will open the drawer extending the draweractivity class (here SlideMenuActivity), the app crashes giving NullPointerException.
Below is the code for opening a drawer layout but once the first activity launches, I am unable to access the drawer.
App is crashing on syncState point in onPostCreate method
#Override
protected void onPostCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onPostCreate(savedInstanceState);
getActionDrawerToggle().syncState();
}
public class SlideMenuActivity extends FragmentActivity implements OnItemClickListener
{
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
setDrawerLayout();
setDrawerList();
if (savedInstanceState == null)
{
getDrawerListView().setSelectionAfterHeaderView();
getDrawerListView().setSelection(1);
selectItem(1);
}
}
//
// #Override
// public void setContentView(int layoutResID) {
// // TODO Auto-generated method stub
// super.setContentView(layoutResID);
// }
private DrawerLayout getDrawerView()
{
return (DrawerLayout)findViewById(R.id.drawer_layout);
}
private ListView getDrawerListView()
{
return (ListView) findViewById(R.id.left_drawer);
}
private ActionBarDrawerToggle getActionDrawerToggle()
{
ActionBarDrawerToggle drawerToggle=new ActionBarDrawerToggle(
this, /* host Activity */
getDrawerView(), /* DrawerLayout object */
R.drawable.ic_drawer, /* nav drawer image to replace 'Up' caret */
R.string.drawer_open, /* "open drawer" description for accessibility */
R.string.drawer_close /* "close drawer" description for accessibility */
) {
#Override
public void onDrawerClosed(View view) {
super.onDrawerClosed(view);
}
#Override
public void onDrawerOpened(View view) {
super.onDrawerOpened(view);
}
};
return drawerToggle;
}
private void setDrawerLayout(){
// set a custom shadow that overlays the main content when the drawer opens
getDrawerView().setDrawerShadow(R.drawable.drawer_shadow, GravityCompat.RELATIVE_HORIZONTAL_GRAVITY_MASK);
// enable ActionBar app icon to behave as action to toggle navigation drawer
getDrawerView().setDrawerListener(getActionDrawerToggle());
}
/**
* Set up the drawer's list view with items and click listener
*/
private void setDrawerList()
{
ImageView imageView=new ImageView(this);
imageView.setImageDrawable(getResources().getDrawable(R.drawable.precision_logo));
CustomBaseAdapter adapter=new CustomBaseAdapter();
adapter.list=getListViewData();
adapter.context=this;
ListView drawerList=getDrawerListView();
drawerList.setHeaderDividersEnabled(true);
drawerList.addHeaderView(imageView, null, false);
drawerList.setScrollingCacheEnabled(false);
drawerList.setAdapter(adapter);
drawerList.setOnItemClickListener(this);
}
private void selectItem(int position){
// update the main content by replacing fragments
// Fragment fragment=null;
// FragmentManager manager=getSupportFragmentManager();
switch (position) {
case 1:
this.startActivity(new Intent(this,SavedTankListActivity.class));
// fragment = new SavedMixesFragment();
// fragment = new SavedTankListActivity();
// manager.beginTransaction().replace(R.id.content_frame, fragment).commit();
break;
case 2:
// fragment=new MixGuideFragment();
// manager.beginTransaction().replace(R.id.content_frame, fragment).commit();
break;
default:
// fragment = new SavedMixesFragment();
// manager.beginTransaction().replace(R.id.content_frame, fragment).commit();
break;
}
getDrawerView().closeDrawer(getDrawerListView());
}
#Override
protected void onPostCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onPostCreate(savedInstanceState);
getActionDrawerToggle().syncState();
}
#Override
public void onConfigurationChanged(Configuration newConfig) {
// TODO Auto-generated method stub
super.onConfigurationChanged(newConfig);
getActionDrawerToggle().onConfigurationChanged(newConfig);
}
private ArrayList<DrawerListModel> getListViewData()
{
ArrayList<DrawerListModel> listViewData=new ArrayList<DrawerListModel>();
String[] listItemArray=getResources().getStringArray(R.array.slide_bar_list_item_array);
for(int index=0;index<listItemArray.length;index++)
{
DrawerListModel model=new DrawerListModel();
model.listItem=listItemArray[index];
listViewData.add(model);
}
return listViewData;
}
#Override
public void onItemClick(AdapterView<?> parent, View view, int position,long id)
{
view.setSelected(true);
selectItem(position);
}
public void openDrawerList(View view){
getDrawerView().openDrawer(getDrawerListView());
}
}
I too was looking through the documentation and thought that I had to switch all my activities into fragments. Just to clear it up, this is simply not the case. You can have as many elements under the linear layout or whatever as needed.
For example if your base activity without the appdrawer is:
<RelativeLayout>
<TextView>
</TextView>
<Button>
<Button>
</RelativeLayout>
Simply do
<android.support.v4.widget.DrawerLayout>
<RelativeLayout>
<TextView>
</TextView>
<Button>
<Button>
</RelativeLayout>
<ListView>
</ListView>
</android.support.v4.widget.DrawerLayout>
Supposedly you can have a main activity where you put the navigation drawer and all sub activity classes get to use the drawer, but what i don't understand is how do you avoid repeating the layout containing the drawerfor all sub activities.
Navigation Drawers do NOT need to be in a fragment. You can create a class that will then be extended from all of your activities (as you were attempting to do).
public class SlideMenuActivity extends Activity{..}
your main activity would look like
public class MainActivity extends SlideMenuActivity{..}
The SlideMenuActivity can be implemented in the same way as described in creating a navigation activity.
All of your XML pages would include this:
<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"
android:background="#FFFFFF" >
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
</LinearLayout>
<ListView
android:id="#+id/left_drawer"
android:layout_width="240dp"
android:layout_height="match_parent"
android:layout_gravity="start"
android:background="#111"
android:choiceMode="singleChoice"
android:divider="#CCCCCC"
android:dividerHeight="1dp" />
</android.support.v4.widget.DrawerLayout>
Without seeing your logcat output, I am not sure why you are receiving an error, but hopefully this can help you get through a bit more of the navigation drawer code.
Related
My requirement is shown in the picture below My navigation drawer should be opened from the right side. I have implemented this. My navigation drawer open from right to left. But the problem is toggle icon is always on the left side. How can I set toggle icon to the right?
I have checked the following SO questions, but none of them came to any help:
Change toggle button image Icon In Navigation Drawer right to left
Drawer Toggle in right Drawer
enter link description here
Here is what I have tried:
code for my layout activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<android.support.v4.widget.DrawerLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/drawer"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
tools:openDrawer="end">
<android.support.design.widget.CoordinatorLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
tools:context="com.example.nav.MainActivity"
android:foregroundGravity="right">
<android.support.design.widget.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="end"
android:theme="#style/AppTheme.AppBarOverlay">
<android.support.v7.widget.Toolbar
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
android:layout_gravity="right"
app:popupTheme="#style/AppTheme.PopupOverlay"
android:foregroundGravity="right"
android:textAlignment="viewEnd"
android:touchscreenBlocksFocus="false" />
</android.support.design.widget.AppBarLayout>
<include layout="#layout/content_main" />
</android.support.design.widget.CoordinatorLayout>
<android.support.design.widget.NavigationView
android:id="#+id/navigation_view"
android:layout_height="match_parent"
android:layout_width="wrap_content"
android:layout_gravity="end"
app:headerLayout="#layout/nav_header"
app:menu="#menu/menu_navigation"
android:textAlignment="viewEnd" />
</android.support.v4.widget.DrawerLayout>
Code for my activity
public class MainActivity extends AppCompatActivity {
private DrawerLayout drawerLayout;
private Toolbar toolbar;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
initNavigationDrawer();
}
#TargetApi(Build.VERSION_CODES.M)
public void initNavigationDrawer() {
NavigationView navigationView = (NavigationView)findViewById(R.id.navigation_view);
navigationView.setNavigationItemSelectedListener(new NavigationView.OnNavigationItemSelectedListener() {
#Override
public boolean onNavigationItemSelected(MenuItem menuItem) {
int id = menuItem.getItemId();
switch (id){
case R.id.home:
Toast.makeText(getApplicationContext(),"Home",Toast.LENGTH_SHORT).show();
drawerLayout.closeDrawers();
break;
case R.id.settings:
Toast.makeText(getApplicationContext(),"Settings",Toast.LENGTH_SHORT).show();
break;
case R.id.trash:
Toast.makeText(getApplicationContext(),"Trash",Toast.LENGTH_SHORT).show();
drawerLayout.closeDrawers();
break;
case R.id.logout:
finish();
}
return true;
}
});
drawerLayout = (DrawerLayout)findViewById(R.id.drawer);
ActionBarDrawerToggle actionBarDrawerToggle = new ActionBarDrawerToggle(this,drawerLayout,toolbar,R.string.drawer_open,R.string.drawer_close){
#Override
public void onDrawerClosed(View v){
super.onDrawerClosed(v);
}
#Override
public void onDrawerOpened(View v) {
super.onDrawerOpened(v);
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
if (item != null && item.getItemId() == android.R.id.home) {
if (drawerLayout.isDrawerOpen(Gravity.RIGHT)) {
drawerLayout.closeDrawer(Gravity.RIGHT);
}
else {
drawerLayout.openDrawer(Gravity.RIGHT);
}
}
return false;
}
};
drawerLayout.addDrawerListener(actionBarDrawerToggle);
actionBarDrawerToggle.syncState();
toolbar.setNavigationOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (drawerLayout.isDrawerOpen(Gravity.RIGHT)) {
drawerLayout.closeDrawer(Gravity.RIGHT);
} else {
drawerLayout.openDrawer(Gravity.RIGHT);
}
}
});
}
}
There's really no (practical) way to make ActionBarDrawerToggle do that, as it is always set on the start/left-side navigation button. However, that class is basically just a DrawerListener that manages a specialized Drawable, and wires an ImageButton to the DrawerLayout. We can put together something similar for an end/right-side drawer with an ImageButton that we can place on that same side in a Toolbar (which is required for this example).
public class EndDrawerToggle implements DrawerLayout.DrawerListener {
private final DrawerLayout drawerLayout;
private final AppCompatImageButton toggleButton;
private final int openDrawerContentDescRes;
private final int closeDrawerContentDescRes;
private DrawerArrowDrawable arrowDrawable;
public EndDrawerToggle(DrawerLayout drawerLayout, Toolbar toolbar,
int openDrawerContentDescRes, int closeDrawerContentDescRes) {
this.drawerLayout = drawerLayout;
this.openDrawerContentDescRes = openDrawerContentDescRes;
this.closeDrawerContentDescRes = closeDrawerContentDescRes;
toggleButton = new AppCompatImageButton(toolbar.getContext(), null,
R.attr.toolbarNavigationButtonStyle);
toolbar.addView(toggleButton, new Toolbar.LayoutParams(GravityCompat.END));
toggleButton.setOnClickListener(v -> toggle());
loadDrawerArrowDrawable();
}
public void syncState() {
if (drawerLayout.isDrawerOpen(GravityCompat.END)) {
setPosition(1f);
} else {
setPosition(0f);
}
}
public void onConfigurationChanged(Configuration newConfig) {
loadDrawerArrowDrawable();
syncState();
}
#Override
public void onDrawerSlide(#NonNull View drawerView, float slideOffset) {
setPosition(Math.min(1f, Math.max(0f, slideOffset)));
}
#Override
public void onDrawerOpened(#NonNull View drawerView) {
setPosition(1f);
}
#Override
public void onDrawerClosed(#NonNull View drawerView) {
setPosition(0f);
}
#Override
public void onDrawerStateChanged(int newState) {}
private void loadDrawerArrowDrawable() {
arrowDrawable = new DrawerArrowDrawable(toggleButton.getContext());
arrowDrawable.setDirection(DrawerArrowDrawable.ARROW_DIRECTION_END);
toggleButton.setImageDrawable(arrowDrawable);
}
private void toggle() {
final int drawerLockMode = drawerLayout.getDrawerLockMode(GravityCompat.END);
if (drawerLayout.isDrawerVisible(GravityCompat.END)
&& (drawerLockMode != DrawerLayout.LOCK_MODE_LOCKED_OPEN)) {
drawerLayout.closeDrawer(GravityCompat.END);
} else if (drawerLockMode != DrawerLayout.LOCK_MODE_LOCKED_CLOSED) {
drawerLayout.openDrawer(GravityCompat.END);
}
}
private void setPosition(float position) {
if (position == 1f) {
arrowDrawable.setVerticalMirror(true);
setContentDescription(closeDrawerContentDescRes);
} else if (position == 0f) {
arrowDrawable.setVerticalMirror(false);
setContentDescription(openDrawerContentDescRes);
}
arrowDrawable.setProgress(position);
}
private void setContentDescription(int resId) {
toggleButton.setContentDescription(toggleButton.getContext().getText(resId));
}
}
The EndDrawerToggle class works exactly the same way as ActionBarDrawerToggle does when used with a Toolbar (except the constructor call doesn't need an Activity argument): first instantiate the toggle, then add it as a DrawerListener, and sync it in the Activity's onPostCreate() method. If you're already overriding the Activity's onConfigurationChanged() method, you'll want to call the toggle's corresponding method there, like you would for an ActionBarDrawerToggle.
private EndDrawerToggle drawerToggle;
public void initNavigationDrawer() {
...
drawerLayout = (DrawerLayout) findViewById(R.id.drawer);
drawerToggle = new EndDrawerToggle(drawerLayout,
toolbar,
R.string.drawer_open,
R.string.drawer_close);
drawerLayout.addDrawerListener(drawerToggle);
}
#Override
protected void onPostCreate(Bundle savedInstanceState) {
super.onPostCreate(savedInstanceState);
drawerToggle.syncState();
}
#Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
drawerToggle.onConfigurationChanged(newConfig);
}
If you have two drawers and need to use ActionBarDrawerToggle and EndDrawerToggle simultaneously, it is possible, but we'll need to handle intercepting and dispatching drawer motion events to the correct toggle.
If you prefer fewer classes, you could subclass ActionBarDrawerToggle and merge EndDrawerToggle's functionality into it, dispatching each DrawerListener method call either to the super class, or to the local end toggle code.
However, composition is arguably much cleaner here, and it will let us use EndDrawerToggle as is. This example is a DrawerListener that relays syncState() and onConfigurationChanged() calls to each toggle, but dispatches the listener method calls only to the appropriate one, depending on which drawer is moving.
public class DualDrawerToggle implements DrawerLayout.DrawerListener {
private final DrawerLayout drawerLayout;
private final Toolbar toolbar;
private final ActionBarDrawerToggle actionBarDrawerToggle;
private final EndDrawerToggle endDrawerToggle;
public DualDrawerToggle(Activity activity, DrawerLayout drawerLayout, Toolbar toolbar,
int startDrawerOpenContDescRes, int startDrawerCloseContDescRes,
int endDrawerOpenContDescRes, int endDrawerCloseContDescRes) {
this.drawerLayout = drawerLayout;
this.toolbar = toolbar;
this.actionBarDrawerToggle =
new ActionBarDrawerToggle(activity, drawerLayout, toolbar,
startDrawerOpenContDescRes, startDrawerCloseContDescRes);
this.endDrawerToggle =
new EndDrawerToggle(drawerLayout, toolbar,
endDrawerOpenContDescRes, endDrawerCloseContDescRes);
}
public void syncState() {
actionBarDrawerToggle.syncState();
endDrawerToggle.syncState();
}
public void onConfigurationChanged(Configuration newConfig) {
actionBarDrawerToggle.onConfigurationChanged(newConfig);
// Fixes bug in ABDT, which only reloads the up nav indicator, for some reason.
final DrawerArrowDrawable dad = new DrawerArrowDrawable(toolbar.getContext());
actionBarDrawerToggle.setDrawerArrowDrawable(dad);
endDrawerToggle.onConfigurationChanged(newConfig);
}
#Override
public void onDrawerSlide(#NonNull View drawerView, float slideOffset) {
if (isStartDrawerView(drawerView, drawerLayout.getLayoutDirection())) {
actionBarDrawerToggle.onDrawerSlide(drawerView, slideOffset);
} else {
endDrawerToggle.onDrawerSlide(drawerView, slideOffset);
}
}
#Override
public void onDrawerOpened(#NonNull View drawerView) {
if (isStartDrawerView(drawerView, drawerLayout.getLayoutDirection())) {
actionBarDrawerToggle.onDrawerOpened(drawerView);
} else {
endDrawerToggle.onDrawerOpened(drawerView);
}
}
#Override
public void onDrawerClosed(#NonNull View drawerView) {
if (isStartDrawerView(drawerView, drawerLayout.getLayoutDirection())) {
actionBarDrawerToggle.onDrawerClosed(drawerView);
} else {
endDrawerToggle.onDrawerClosed(drawerView);
}
}
#Override
public void onDrawerStateChanged(int newState) {}
#SuppressLint("RtlHardcoded")
static boolean isStartDrawerView(View drawerView, int layoutDirection) {
final int gravity = ((DrawerLayout.LayoutParams) drawerView.getLayoutParams()).gravity;
final int horizontalGravity = gravity & GravityCompat.RELATIVE_HORIZONTAL_GRAVITY_MASK;
if ((horizontalGravity & GravityCompat.RELATIVE_LAYOUT_DIRECTION) > 0) {
return horizontalGravity == GravityCompat.START;
} else {
if (layoutDirection == View.LAYOUT_DIRECTION_RTL) {
return horizontalGravity == Gravity.RIGHT;
} else {
return horizontalGravity == Gravity.LEFT;
}
}
}
}
Again, DualDrawerToggle works exactly the same way as ActionBarDrawerToggle does when used with a Toolbar, except for the extra content description resource IDs in the constructor.
Do note that the one DualDrawerToggle creates and manages both other toggles internally. You don't need to set up any other toggle instances in your Activity; just the DualDrawerToggle.
Notes:
If you read through the code, you'll see that EndDrawerToggle – and therefore also DualDrawerToggle – can be readily adapted to put a toggle on pretty much anything that can display a Drawable and register clicks; e.g., a FloatingActionButton, an options menu item, a TextView's compound drawable, etc. Simply replace the AppCompatImageButton with your target UI component, which can be passed in the constructor in place of the Toolbar, since the toggle won't be added to that anymore.
Additionally, this could be modified to work with the start/left-aligned drawer, too – completely replacing ActionBarDrawerToggle – so that its toggle could be placed on those various components, as well.
The AppCompatImageButton used here is a regular child of the Toolbar. If you're using a menu on the Toolbar, that menu will take precedence in the layout, and push the toggle inward. To keep it on the outside, you can modify the class as described above to set the toggle on an action menu item. I've an example of that in my answer here.
That menu item example might also be useful if your design requires you use the decor-supplied ActionBar in lieu of your own Toolbar. Though ActionBarDrawerToggle can work with a decor-supplied ActionBar, this example can not, as is.
In your android manifest add this line:
android:supportsRtl="true"
to your application, like so:
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:supportsRtl="true"
Then in your onCreate method, add this line:
getWindow().getDecorView().setLayoutDirection(View.LAYOUT_DIRECTION_RTL);
WARNING::: This only works for SdkVersion 17+, so if your application targets a lower minimum SDK, you will have to create a custom menu and override the OnCreateOptions method(Unless there's another way which I'm not aware of, which is definitely possible).
https://developer.android.com/guide/topics/manifest/application-element.html#supportsrtl
I created an android application using ButterKnife. I wanted to add an activity with Navigation bar . So I used , Navigation Drawer Activityin android studio.
Then I tried to launch it using another activity .Like this ,
Intent intent = new Intent(this, AddInfoActivity.class);
startActivity(intent);
Then I got following error message.
FATAL EXCEPTION: main
Process: xxx.com.au.abcd, PID: 13408
java.lang.RuntimeException: Unable to start activity ComponentInfo{xxx.com.au.abcd/xxx.com.au.abcd.activities.AddInfoActivity}: android.view.InflateException: Binary XML file line #18: Error inflating class fragment
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2436)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2498)
at android.app.ActivityThread.access$900(ActivityThread.java:179)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1324)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:146)
at android.app.ActivityThread.main(ActivityThread.java:5641)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:515)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1288)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1104)
at dalvik.system.NativeStart.main(Native Method)
Caused by: android.view.InflateException: Binary XML file line #18: Error inflating class fragment
at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:719)
at android.view.LayoutInflater.rInflate(LayoutInflater.java:761)
at android.view.LayoutInflater.inflate(LayoutInflater.java:498)
at android.view.LayoutInflater.inflate(LayoutInflater.java:398)
at android.view.LayoutInflater.inflate(LayoutInflater.java:354)
at android.support.v7.app.AppCompatDelegateImplV9.setContentView(AppCompatDelegateImplV9.java:284)
at android.support.v7.app.AppCompatActivity.setContentView(AppCompatActivity.java:140)
at xxx.com.au.abcd.activities.AddInfoActivity.onCreate(AddInfoActivity.java:33)
at android.app.Activity.performCreate(Activity.java:5484)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1093)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2400)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2498)
at android.app.ActivityThread.access$900(ActivityThread.java:179)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1324)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:146)
at android.app.ActivityThread.main(ActivityThread.java:5641)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:515)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1288)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1104)
at dalvik.system.NativeStart.main(Native Method)
Caused by: java.lang.NullPointerException
at xxx.com.au.abcd.activities.NavigationDrawerFragment.onCreateView(NavigationDrawerFragment.java:103)
at android.app.Fragment.performCreateView(Fragment.java:1700)
at android.app.FragmentManagerImpl.moveToState(FragmentManager.java:866)
at android.app.FragmentManagerImpl.moveToState(FragmentManager.java:1040)
at android.app.FragmentManagerImpl.addFragment(FragmentManager.java:1142)
at android.app.Activity.onCreateView(Activity.java:5020)
at android.support.v4.app.BaseFragmentActivityHoneycomb.onCreateView(BaseFragmentActivityHoneycomb.java:36)
at android.support.v4.app.FragmentActivity.onCreateView(FragmentActivity.java:75)
at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:695)
at android.view.LayoutInflater.rInflate(LayoutInflater.java:761)
at android.view.LayoutInflater.inflate(LayoutInflater.java:498)
at android.view.LayoutInflater.inflate(LayoutInflater.java:398)
at android.view.LayoutInflater.inflate(LayoutInflater.java:354)
at android.support.v7.app.AppCompatDelegateImplV9.setContentView(AppCompatDelegateImplV9.java:284)
at android.support.v7.app.AppCompatActivity.setContentView(AppCompatActivity.java:140)
at xxx.com.au.abcd.activities.AddInfoActivity.onCreate(AddInfoActivity.java:33)
at android.app.Activity.performCreate(Activity.java:5484)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1093)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2400)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2498)
at android.app.ActivityThread.access$900(ActivityThread.java:179)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1324)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:146)
at android.app.ActivityThread.main(ActivityThread.java:5641)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:515)
And this is my activity with navigation bar,
AddInfoActivity.java
import android.app.Activity;
import butterknife.ButterKnife;
import tekhinno.com.au.mygulukose.R;
public class AddInfoActivity extends BaseActivity
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.add_info_activity);
ButterKnife.inject(this);
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:
mTitle = getString(R.string.title_section1);
break;
case 2:
mTitle = getString(R.string.title_section2);
break;
case 3:
mTitle = getString(R.string.title_section3);
break;
}
}
public void restoreActionBar() {
ActionBar actionBar = getActionBar();
actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_STANDARD);
actionBar.setDisplayShowTitleEnabled(true);
actionBar.setTitle(mTitle);
}
/**
* A placeholder fragment containing a simple view.
*/
public static class PlaceholderFragment extends Fragment {
/**
* The fragment argument representing the section number for this
* fragment.
*/
private static final String ARG_SECTION_NUMBER = "section_number";
public PlaceholderFragment() {
}
/**
* Returns a new instance of this fragment for the given section
* number.
*/
public static PlaceholderFragment newInstance(int sectionNumber) {
PlaceholderFragment fragment = new PlaceholderFragment();
Bundle args = new Bundle();
args.putInt(ARG_SECTION_NUMBER, sectionNumber);
fragment.setArguments(args);
return fragment;
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_add_info, container, false);
return rootView;
}
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
((AddInfoActivity) activity).onSectionAttached(
getArguments().getInt(ARG_SECTION_NUMBER));
}
}
}
NavigationDrawerFragment.java
import butterknife.ButterKnife;
import tekhinno.com.au.mygulukose.R;
/**
* Fragment used for managing interactions for and presentation of a navigation drawer.
* See the <a href="https://developer.android.com/design/patterns/navigation-drawer.html#Interaction">
* design guidelines</a> for a complete explanation of the behaviors implemented here.
*/
public class NavigationDrawerFragment extends Fragment {
/**
* Remember the position of the selected item.
*/
private static final String STATE_SELECTED_POSITION = "selected_navigation_drawer_position";
/**
* Per the design guidelines, you should show the drawer on launch until the user manually
* expands it. This shared preference tracks this.
*/
private static final String PREF_USER_LEARNED_DRAWER = "navigation_drawer_learned";
/**
* A pointer to the current callbacks instance (the Activity).
*/
private NavigationDrawerCallbacks mCallbacks;
/**
* Helper component that ties the action bar to the navigation drawer.
*/
private ActionBarDrawerToggle mDrawerToggle;
private DrawerLayout mDrawerLayout;
private ListView mDrawerListView;
private View mFragmentContainerView;
private int mCurrentSelectedPosition = 0;
private boolean mFromSavedInstanceState;
private boolean mUserLearnedDrawer;
public NavigationDrawerFragment() {
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Read in the flag indicating whether or not the user has demonstrated awareness of the
// drawer. See PREF_USER_LEARNED_DRAWER for details.
SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(getActivity());
mUserLearnedDrawer = sp.getBoolean(PREF_USER_LEARNED_DRAWER, false);
if (savedInstanceState != null) {
mCurrentSelectedPosition = savedInstanceState.getInt(STATE_SELECTED_POSITION);
mFromSavedInstanceState = true;
}
// Select either the default item (0) or the last selected item.
selectItem(mCurrentSelectedPosition);
}
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
// Indicate that this fragment would like to influence the set of actions in the action bar.
setHasOptionsMenu(true);
}
**#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
mDrawerListView = (ListView) inflater.inflate(
R.layout.drawer_add_info, container, false);
mDrawerListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
selectItem(position);
}
});
mDrawerListView.setAdapter(new ArrayAdapter<String>(
getActionBar().getThemedContext(),
android.R.layout.simple_list_item_activated_1,
android.R.id.text1,
new String[]{
getString(R.string.title_section1),
getString(R.string.title_section2),
getString(R.string.title_section3),
}));
mDrawerListView.setItemChecked(mCurrentSelectedPosition, true);
return mDrawerListView;
}**
public boolean isDrawerOpen() {
return mDrawerLayout != null && mDrawerLayout.isDrawerOpen(mFragmentContainerView);
}
/**
* Users of this fragment must call this method to set up the navigation drawer interactions.
*
* #param fragmentId The android:id of this fragment in its activity's layout.
* #param drawerLayout The DrawerLayout containing this fragment's UI.
*/
public void setUp(int fragmentId, DrawerLayout drawerLayout) {
mFragmentContainerView = getActivity().findViewById(fragmentId);
mDrawerLayout = drawerLayout;
// set a custom shadow that overlays the main content when the drawer opens
mDrawerLayout.setDrawerShadow(R.drawable.drawer_shadow, GravityCompat.START);
// set up the drawer's list view with items and click listener
ActionBar actionBar = getActionBar();
actionBar.setDisplayHomeAsUpEnabled(true);
actionBar.setHomeButtonEnabled(true);
// ActionBarDrawerToggle ties together the the proper interactions
// between the navigation drawer and the action bar app icon.
mDrawerToggle = new ActionBarDrawerToggle(
getActivity(), /* host Activity */
mDrawerLayout, /* DrawerLayout object */
R.drawable.ic_drawer, /* nav drawer image to replace 'Up' caret */
R.string.navigation_drawer_open, /* "open drawer" description for accessibility */
R.string.navigation_drawer_close /* "close drawer" description for accessibility */
) {
#Override
public void onDrawerClosed(View drawerView) {
super.onDrawerClosed(drawerView);
if (!isAdded()) {
return;
}
getActivity().invalidateOptionsMenu(); // calls onPrepareOptionsMenu()
}
#Override
public void onDrawerOpened(View drawerView) {
super.onDrawerOpened(drawerView);
if (!isAdded()) {
return;
}
if (!mUserLearnedDrawer) {
// The user manually opened the drawer; store this flag to prevent auto-showing
// the navigation drawer automatically in the future.
mUserLearnedDrawer = true;
SharedPreferences sp = PreferenceManager
.getDefaultSharedPreferences(getActivity());
sp.edit().putBoolean(PREF_USER_LEARNED_DRAWER, true).apply();
}
getActivity().invalidateOptionsMenu(); // calls onPrepareOptionsMenu()
}
};
// If the user hasn't 'learned' about the drawer, open it to introduce them to the drawer,
// per the navigation drawer design guidelines.
if (!mUserLearnedDrawer && !mFromSavedInstanceState) {
mDrawerLayout.openDrawer(mFragmentContainerView);
}
// Defer code dependent on restoration of previous instance state.
mDrawerLayout.post(new Runnable() {
#Override
public void run() {
mDrawerToggle.syncState();
}
});
mDrawerLayout.setDrawerListener(mDrawerToggle);
}
private void selectItem(int position) {
mCurrentSelectedPosition = position;
if (mDrawerListView != null) {
mDrawerListView.setItemChecked(position, true);
}
if (mDrawerLayout != null) {
mDrawerLayout.closeDrawer(mFragmentContainerView);
}
if (mCallbacks != null) {
mCallbacks.onNavigationDrawerItemSelected(position);
}
}
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
try {
mCallbacks = (NavigationDrawerCallbacks) activity;
} catch (ClassCastException e) {
throw new ClassCastException("Activity must implement NavigationDrawerCallbacks.");
}
}
#Override
public void onDetach() {
super.onDetach();
mCallbacks = null;
}
#Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putInt(STATE_SELECTED_POSITION, mCurrentSelectedPosition);
}
#Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
// Forward the new configuration the drawer toggle component.
mDrawerToggle.onConfigurationChanged(newConfig);
}
#Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
// If the drawer is open, show the global app actions in the action bar. See also
// showGlobalContextActionBar, which controls the top-left area of the action bar.
if (mDrawerLayout != null && isDrawerOpen()) {
inflater.inflate(R.menu.global, menu);
showGlobalContextActionBar();
}
super.onCreateOptionsMenu(menu, inflater);
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
if (mDrawerToggle.onOptionsItemSelected(item)) {
return true;
}
if (item.getItemId() == R.id.action_example) {
Toast.makeText(getActivity(), "Example action.", Toast.LENGTH_SHORT).show();
return true;
}
return super.onOptionsItemSelected(item);
}
/**
* Per the navigation drawer design guidelines, updates the action bar to show the global app
* 'context', rather than just what's in the current screen.
*/
private void showGlobalContextActionBar() {
ActionBar actionBar = getActionBar();
actionBar.setDisplayShowTitleEnabled(true);
actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_STANDARD);
actionBar.setTitle(R.string.app_name);
}
private ActionBar getActionBar() {
return getActivity().getActionBar();
}
/**
* Callbacks interface that all activities using this fragment must implement.
*/
public static interface NavigationDrawerCallbacks {
/**
* Called when an item in the navigation drawer is selected.
*/
void onNavigationDrawerItemSelected(int position);
}
}
And these are my layout files,
fragment_add_info.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:paddingBottom="#dimen/activity_vertical_margin"
android:paddingLeft="#dimen/activity_horizontal_margin"
android:paddingRight="#dimen/activity_horizontal_margin"
android:paddingTop="#dimen/activity_vertical_margin"
tools:context="tekhinno.com.au.mygulukose.activities.AddInfoActivity$PlaceholderFragment">
<TextView
android:id="#+id/section_label"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</RelativeLayout>
drawer_add_info.xml
<ListView 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:background="#cccc"
android:choiceMode="singleChoice"
android:divider="#android:color/transparent"
android:dividerHeight="0dp"
tools:context="tekhinno.com.au.mygulukose.activities.NavigationDrawerFragment" />
add_info_activity.xml
<!-- A DrawerLayout is intended to be used as the top-level content view using match_parent for both width and height to consume the full space available. -->
<android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/drawer_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="tekhinno.com.au.mygulukose.activities.AddInfoActivity">
<!-- As the main content view, the view below consumes the entire
space available using match_parent in both dimensions. -->
<FrameLayout
android:id="#+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<!-- The drawer is given a fixed width in dp and extends the full height of
the container. -->
<fragment
android:id="#+id/navigation_drawer"
android:name="tekhinno.com.au.mygulukose.activities.NavigationDrawerFragment"
android:layout_width="#dimen/navigation_drawer_width"
android:layout_height="match_parent"
android:layout_gravity="start"
tools:layout="#layout/drawer_add_info" />
</android.support.v4.widget.DrawerLayout>
NOTE :- These layout files and NavigationDrawerFragment.java were generated by Android Studio.
Have any idea about this problem ?
You are using getFragmentManager() to get the fragment manager. You need to get SupportFragmentManager if you are extending AppCompatActivity by your BaseActivity.
#Override
public void onNavigationDrawerItemSelected(int position) {
// update the main content by replacing fragments
FragmentManager fragmentManager = getSupportFragmentManager();
fragmentManager.beginTransaction()
.replace(R.id.container, PlaceholderFragment.newInstance(position + 1))
.commit();
}
Note: While using support packages you need to use SupportFragmentManager.
Few days ago I implemented TabHostFramgent in a Fragment with a NavigationDrawer, and I faced with a problem that is the following error :
java.lang.IllegalStateException: No tab known for tag null
The thing is that all works perfectly since my first item list of my NavigationDrawer is my TabHostFragment, so it works perfect, but the problem is when I go in example to the second item and then I want to go back to the first item, every time that I try so it crashes.
I was searching everywhere, here in SO, code.google.com, etc... and I still don't get the proper answer.
My tab_host_test_2.xmllooks like :
<android.support.v4.app.FragmentTabHost xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="#android:id/tabhost"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<TabWidget
android:id="#android:id/tabs"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal" />
<FrameLayout
android:id="#android:id/tabcontent"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_weight="0" />
<FrameLayout
android:id="#+id/realtabcontent"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1" />
</LinearLayout>
</android.support.v4.app.FragmentTabHost>
My activity_main.xml where I've got my NavigationDrawer looks like :
<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 to display Fragments -->
<FrameLayout
android:id="#+id/frame_container"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<!-- Listview to display slider menu -->
<ListView
android:id="#+id/list_slidermenu"
android:layout_width="240dp"
android:layout_height="match_parent"
android:layout_gravity="start"
android:choiceMode="singleChoice"
android:divider="#color/list_divider"
android:dividerHeight="1dp"
android:listSelector="#drawable/list_selector"
android:background="#color/list_background"/>
</android.support.v4.widget.DrawerLayout>
My TabHostFragment.java:
public class TabHostFragment extends Fragment {
public TabHostFragment(){
}
private FragmentTabHost mTabHost;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.tab_host_test2, container, false);
return rootView;
}
#Override
public void onViewCreated(View view, Bundle savedInstanceState) {
mTabHost = (FragmentTabHost)view.findViewById(android.R.id.tabhost);
mTabHost.setup(getActivity(), getChildFragmentManager(), R.id.realtabcontent);
mTabHost.addTab(mTabHost.newTabSpec("tab1").setIndicator("Tab1"),
MisOfertasFragment.class, null);
mTabHost.addTab(mTabHost.newTabSpec("tab2").setIndicator("Tab2"),
RecomendacionesFragment.class, null);
}
}
My ActivityMain.java:
public class MainActivity extends FragmentActivity {
private DrawerLayout mDrawerLayout;
private ListView mDrawerList;
private ActionBarDrawerToggle mDrawerToggle;
// saber si esta abierto
public boolean mDrawerOpened;
// nav drawer title
private CharSequence mDrawerTitle;
private FragmentTabHost mTabHost;
// used to store app title
private CharSequence mTitle;
//para ponerlo visible
public MenuItem mi;
// slide menu items
private String[] navMenuTitles;
private TypedArray navMenuIcons;
private ArrayList<NavDrawerItem> navDrawerItems;
private NavDrawerListAdapter adapter;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mTitle = mDrawerTitle = getTitle();
// load slide menu items
navMenuTitles = getResources().getStringArray(R.array.nav_drawer_items);
// nav drawer icons from resources
navMenuIcons = getResources()
.obtainTypedArray(R.array.nav_drawer_icons);
mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
mDrawerList = (ListView) findViewById(R.id.list_slidermenu);
navDrawerItems = new ArrayList<NavDrawerItem>();
// adding nav drawer items to array
// Home
navDrawerItems.add(new NavDrawerItem(navMenuTitles[0], navMenuIcons.getResourceId(0, -1)));
// Find People
navDrawerItems.add(new NavDrawerItem(navMenuTitles[1], navMenuIcons.getResourceId(1, -1)));
// Photos
navDrawerItems.add(new NavDrawerItem(navMenuTitles[2], navMenuIcons.getResourceId(2, -1)));
// Communities, Will add a counter here
navDrawerItems.add(new NavDrawerItem(navMenuTitles[3], navMenuIcons.getResourceId(3, -1)));
// Pages
navDrawerItems.add(new NavDrawerItem(navMenuTitles[4], navMenuIcons.getResourceId(4, -1)));
// What's hot, We will add a counter here
navDrawerItems.add(new NavDrawerItem(navMenuTitles[5], navMenuIcons.getResourceId(5, -1)));
//AyudaSugerencias
navDrawerItems.add(new NavDrawerItem(navMenuTitles[6], navMenuIcons.getResourceId(6, -1)));
navDrawerItems.add(new NavDrawerItem(navMenuTitles[7], navMenuIcons.getResourceId(7, -1)));
// Recycle the typed array
navMenuIcons.recycle();
mDrawerList.setOnItemClickListener(new SlideMenuClickListener());
// setting the nav drawer list adapter
adapter = new NavDrawerListAdapter(getApplicationContext(),
navDrawerItems);
mDrawerList.setAdapter(adapter);
// enabling action bar app icon and behaving it as toggle button
getActionBar().setDisplayHomeAsUpEnabled(true);
getActionBar().setBackgroundDrawable(new ColorDrawable(0xff1d97dd));
getActionBar().setHomeButtonEnabled(true);
mDrawerToggle = new ActionBarDrawerToggle(this, mDrawerLayout,
R.drawable.ic_drawer, //nav menu toggle icon
R.string.app_name, // nav drawer open - description for accessibility
R.string.app_name // nav drawer close - description for accessibility
) {
public void onDrawerClosed(View view) {
getActionBar().setTitle(
Html.fromHtml("<font color='ffffff'>"
+ mTitle + "</font>"));
// calling onPrepareOptionsMenu() to show action bar icons
invalidateOptionsMenu();
mDrawerOpened = false;
syncState();
}
public void onDrawerOpened(View drawerView) {
getActionBar().setTitle(
Html.fromHtml("<font color='ffffff'>"
+ mDrawerTitle + "</font>"));
// calling onPrepareOptionsMenu() to hide action bar icons
invalidateOptionsMenu();
mDrawerOpened = true;
syncState();
}
};
mDrawerLayout.setDrawerListener(mDrawerToggle);
if (savedInstanceState == null) {
// on first time display view for first nav item
displayView(0);
}
}
/**
* Slide menu item click listener
*/
private class SlideMenuClickListener implements
ListView.OnItemClickListener {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position,
long id) {
// display view for selected nav drawer item
displayView(position);
}
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
Fragment fragment = null;
// toggle nav drawer on selecting action bar app icon/title
if (mDrawerToggle.onOptionsItemSelected(item)) {
return true;
}
// Handle action bar actions click
switch (item.getItemId()) {
case R.id.action_settings:
return true;
case R.id.ofertasRefresh:
return true;
case R.id.menu_search:
return true;
case R.id.newOffer:
getFragmentManager().beginTransaction().replace(R.id.frame_container, new TipusNouProducte()).commit();
return true;
default:
return super.onOptionsItemSelected(item);
}
}
/* *
* Called when invalidateOptionsMenu() is triggered
*/
#Override
public boolean onPrepareOptionsMenu(Menu menu) {
// if nav drawer is opened, hide the action items
boolean drawerOpen = mDrawerLayout.isDrawerOpen(mDrawerList);
menu.findItem(R.id.action_settings).setVisible(!drawerOpen);
if (mDrawerOpened) {
menu.removeItem(R.id.ofertasRefresh);
menu.removeItem(R.id.menu_search);
menu.removeItem(R.id.newOffer);
}
if (!mDrawerOpened) {
menu.add(Menu.NONE, R.id.ofertasRefresh, Menu.NONE, mTitle);
}
return super.onPrepareOptionsMenu(menu);
}
/**
* Diplaying fragment view for selected nav drawer list item
*/
private void displayView(int position) {
mDrawerList.setItemChecked(position, true);
mDrawerList.setSelection(position);
setTitle(navMenuTitles[position]);
mDrawerLayout.closeDrawer(mDrawerList);
Fragment fragment = null;
switch (position) {
case 0:
fragment = new TabHostFragment();
break;
case 1:
fragment = new RecomendacionesFragment();
break;
case 2:
fragment = new LocalizacionFragment();
break;
case 3:
fragment = new ListaProductosFragment();
break;
case 4:
fragment = new ConfiguracionFragment();
break;
case 5:
fragment = new AyudaSugerenciasFragment();
break;
case 6:
fragment = new AyudaSugerencias();
break;
default:
break;
}
if (fragment != null) {
FragmentManager fragmentManager = getSupportFragmentManager();
fragmentManager.beginTransaction()
.replace(R.id.frame_container, fragment).commit(); /// here says that replace android.app.Fragment in FragmentTransaction cannot be applied...
// 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");
}
}
#Override
public void setTitle(CharSequence title) {
mTitle = title;
getActionBar().setTitle(mTitle);
}
/**
* When using the ActionBarDrawerToggle, you must call it during
* onPostCreate() and onConfigurationChanged()...
*/
#Override
protected void onPostCreate(Bundle savedInstanceState) {
super.onPostCreate(savedInstanceState);
// Sync the toggle state after onRestoreInstanceState has occurred.
mDrawerToggle.syncState();
}
#Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
// Pass any configuration change to the drawer toggls
mDrawerToggle.onConfigurationChanged(newConfig);
}
}
The full LogCat error is :
03-04 16:53:05.708 2232-2232/info.androidhive.slidingmenu E/AndroidRuntime﹕ FATAL EXCEPTION: main
Process: info.androidhive.slidingmenu, PID: 2232
java.lang.IllegalStateException: No tab known for tag null
at android.support.v4.app.FragmentTabHost.doTabChanged(FragmentTabHost.java:330)
at android.support.v4.app.FragmentTabHost.onAttachedToWindow(FragmentTabHost.java:280)
at android.view.View.dispatchAttachedToWindow(View.java:13406)
at android.view.ViewGroup.dispatchAttachedToWindow(ViewGroup.java:2707)
at android.view.ViewGroup.dispatchAttachedToWindow(ViewGroup.java:2714)
at android.view.ViewGroup.addViewInner(ViewGroup.java:3919)
at android.view.ViewGroup.addView(ViewGroup.java:3733)
at android.view.ViewGroup.addView(ViewGroup.java:3678)
at android.view.ViewGroup.addView(ViewGroup.java:3654)
at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:958)
at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1126)
at android.support.v4.app.BackStackRecord.run(BackStackRecord.java:739)
at android.support.v4.app.FragmentManagerImpl.execPendingActions(FragmentManager.java:1489)
at android.support.v4.app.FragmentManagerImpl$1.run(FragmentManager.java:454)
at android.os.Handler.handleCallback(Handler.java:739)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:135)
at android.app.ActivityThread.main(ActivityThread.java:5221)
at java.lang.reflect.Method.invoke(Native Method)
at java.lang.reflect.Method.invoke(Method.java:372)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:899)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:694)
EDIT
The answer of #Y.S., was kinda different about what I was asking for, but it could be a solution, but it didn't worked fine at all, and the NavigationDrawer is under the TabHostFragment, etc... I don't want to change anything of my layout.
As the error suggests
Java : illegal state exception : no tab known for tag null
you tried to initialise TabHost but TabHost was null.
Try the code that I have used to initialise the TabHost and it works fine. Keep you code in onCreateView(). This problem occurs when you try to setup your FragmentTabHost in onViewCreated(), which is called too late. Try to set it up in onCreateView(), and add at least one tab before returning the view Object.
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,Bundle savedInstanceState) {
// Create FragmentTabHost
mTabHost = new FragmentTabHost(getActivity());
// Locate fragment1.xml to create FragmentTabHost
mTabHost.setup(getActivity(), getChildFragmentManager(), R.layout.fragment1);
mTabHost.addTab(mTabHost.newTabSpec("groups").setIndicator("",getResources().getDrawable(R.drawable.tab_group_icon)),FragmentTab1.class, null);
mTabHost.addTab(mTabHost.newTabSpec("contacts").setIndicator("",getResources().getDrawable(R.drawable.tab_user_icon)),FragmentTab2.class, null);
MainActivity.fabButton.setVisibility(View.VISIBLE);
return mTabHost;
}
change Layout to:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<FrameLayout
android:layout_width="match_parent"
android:layout_height="0dip"
android:layout_weight="1" />
<android.support.v4.app.FragmentTabHost
android:id="#android:id/tabhost"
android:layout_width="match_parent"
android:layout_height="wrap_content" >
<FrameLayout
android:id="#android:id/tabcontent"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_weight="0" />
</android.support.v4.app.FragmentTabHost>
</LinearLayout>
Hope it helps.
There is another way to display tabs which can be used here.
Define TabHostFragment like this:
public class TabHostFragment extends Fragment implements ActionBar.TabListener{
public TabHostFragment(){
}
AppSectionsPagerAdapter mAppSectionsPagerAdapter;
ViewPager mViewPager;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.tab_host_test2, container, false);
return rootView;
}
#Override
public void onViewCreated(View view, Bundle savedInstanceState){
mAppSectionsPagerAdapter = new AppSectionsPagerAdapter(getChildFragmentManager());
final ActionBar actionBar = ((FragmentActivity)getActivity()).getSupportActionBar();
actionBar.setHomeButtonEnabled(false);
actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
mViewPager = (ViewPager) view.findViewById(R.id.pager);
mViewPager.setAdapter(mAppSectionsPagerAdapter);
mViewPager.setOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener() {
#Override
public void onPageSelected(int position) {
actionBar.setSelectedNavigationItem(position);
}
});
for (int i = 0; i < mAppSectionsPagerAdapter.getCount(); i++) {
actionBar.addTab(
actionBar.newTab()
.setText(mAppSectionsPagerAdapter.getPageTitle(i))
.setTabListener(this));
}
}
#Override
public void onTabUnselected(ActionBar.Tab tab, FragmentTransaction fragmentTransaction) {
}
#Override
public void onTabSelected(ActionBar.Tab tab, FragmentTransaction fragmentTransaction) {
mViewPager.setCurrentItem(tab.getPosition());
}
#Override
public void onTabReselected(ActionBar.Tab tab, FragmentTransaction fragmentTransaction) {
}
public static class AppSectionsPagerAdapter extends FragmentPagerAdapter {
public AppSectionsPagerAdapter(FragmentManager fm) {
super(fm);
}
#Override
public Fragment getItem(int i) {
Fragment f = null;
switch (i) {
case 0:
f = new MisOfertasFragment();
break;
case 1:
f = new RecomendacionesFragment();
break;
}
return f;
}
#Override
public int getCount() {
return 2;
}
#Override
public CharSequence getPageTitle(int position) {
return getFragmentTitle(position);
}
private String getFragmentTitle(int position){
if(position == 0)
return "Tab 1";
else if(position == 1)
return "Tab 2";
else
return "";
}
}
}
Define tab_host_test2.xml like this:
<android.support.v4.view.ViewPager
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/pager"
android:layout_width="match_parent"
android:layout_height="match_parent" />
Rest of the code remains the same.
Try this. This should work.
EDIT:
Add this to the displayView() method:
if(position != 0)
getSupportActionBar().setNavigationMode(ActionBar.NAVIGATION_MODE_STANDARD);
specify in .xml file where you are using this TabHostFragment(complete path like com.my.TabHostFragment). like
<com.my.TabHostFragment
android:id="#+id/fragmentId"
android:layout_width="match_parent"
android:layout_height="match_parent"
/>
My application contains a Navigation Drawer and i use its list items as a menu, by clicking on which help in retrieving data from database and populating my listview in main activity...
I want to send a query to a database function based on the item clicks of drawer list and based on the query result my another list view in main activity will be populated..
Basically what i tried till now is assigning a different string holding the query based on the item click into the String type variable "query" and passing it as a parameter to a function of database who processes it as a rawQuery and retrieves result...
Due to some errors which am not able to detect it is throwing Null Pointer Exception...
Following is the code for MainActivity.java
public class MainActivity extends ActionBarActivity
implements NavigationDrawerFragment.NavigationDrawerCallbacks {
private NavigationDrawerFragment mNavigationDrawerFragment;
private CharSequence mTitle;
private Cursor c;
public MyDatabaseHandler dbOpen;
private String query;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mNavigationDrawerFragment =
(NavigationDrawFragment)
getSupportFragmentManager().findFragmentById(R.id.navigation_drawer);
mTitle = getTitle();
mNavigationDrawerFragment.setUp(
R.id.navigation_drawer,
(DrawerLayout) findViewById(R.id.drawer_layout));
dbOpen = new MyDatabaseHandler(this);
c = dbOpen.getListContent(query);
ListView lv = (ListView) findViewById(R.id.list);
lv.setAdapter(new SimpleCursorAdapter(this,R.layout.topic_list_each_row,
c,new String[]{MyDatabaseHandler.KEY_UTOPICNAME,MyDatabaseHandler.KEY_UNAME },
new int[] {R.id.topicname,R.id.unitname} ,0));
}
#Override
public void onNavigationDrawerItemSelected(int position) {
FragmentManager fragmentManager = getSupportFragmentManager();
fragmentManager.beginTransaction()
.replace(R.id.container, PlaceholderFragment.newInstance(position + 1))
.commit();
}
//here where i have thought of passing string into query variable
public void onSectionAttached(int number) {
switch (number) {
case 1:
query = "SELECT * FROM cosmtable ORDER BY utopicname";
break;
...............
..............
}}
public void restoreActionBar() {
ActionBar actionBar = getSupportActionBar();
actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_STANDARD);
actionBar.setDisplayShowTitleEnabled(true);
actionBar.setTitle(mTitle);
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
if (!mNavigationDrawerFragment.isDrawerOpen()) {
// Only show items in the action bar relevant to this screen
// if the drawer is not showing. Otherwise, let the drawer
// decide what to show in the action bar.
getMenuInflater().inflate(R.menu.main, menu);
restoreActionBar();
return true;
}
return super.onCreateOptionsMenu(menu);
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
/**
* A placeholder fragment containing a simple view.
*/
public static class PlaceholderFragment extends Fragment {
/**
* The fragment argument representing the section number for this
* fragment.
*/
private static final String ARG_SECTION_NUMBER = "section_number";
/**
* Returns a new instance of this fragment for the given section
* number.
*/
public static PlaceholderFragment newInstance(int sectionNumber) {
PlaceholderFragment fragment = new PlaceholderFragment();
Bundle args = new Bundle();
args.putInt(ARG_SECTION_NUMBER, sectionNumber);
fragment.setArguments(args);
return fragment;
}
public PlaceholderFragment() {
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_main, container, false);
return rootView;
}
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
((MainActivity) activity).onSectionAttached(
getArguments().getInt(ARG_SECTION_NUMBER));}}}
The activity_main file is-
<android.support.v4.widget.DrawerLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/drawer_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.example.pockettutsforcosm.MainActivity" >
<FrameLayout
android:id="#+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<ListView
android:id="#+id/list"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:dividerHeight="10dp">
</ListView>
</LinearLayout>
<fragment
android:id="#+id/navigation_drawer"
android:name="com.example.pockettutsforcosm.NavigationDrawerFragment"
android:layout_width="#dimen/navigation_drawer_width"
android:layout_height="match_parent"
android:layout_gravity="start"
tools:layout="#layout/fragment_navigation_drawer" />
</android.support.v4.widget.DrawerLayout>
Please help me out in finding a way to achieve the results..
If further details needed then please let me know..
Thank You
UPDATE
One thing i Figured out in this is i was trying to write the query at wrong place i.e., the query variable shouldn't be assigned with a value at onAttach event...
SO i changed the code in Main Activity as follows-
public void onNavigationDrawerItemSelected(int position) {
// update the main content by replacing fragments
//FragmentManager fragmentManager = getSupportFragmentManager();
//fragmentManager.beginTransaction()
// .replace(R.id.container, PlaceholderFragment.newInstance(position))
// .commit();
try
{
switch(position)
{
case 0:
query = "SELECT * FROM cosmtable ORDER BY topic_name";
c = dbOpen.getListContent(query);
ListView lv = (ListView) findViewById(R.id.list);
lv.setAdapter(new SimpleCursorAdapter(this,R.layout.topic_list_each_row,c,
new String[]{MyDatabasehandler.KEY_UTOPICNAME,MyDatabaseHandler.KEY_UNAME},
new int[] {R.id.topicname,R.id.unitname} ,0));
break;
.............................................
}
}
catch (Exception e) {
Log.e("error on fragment", "creating the mainScreen");
}
finally {
FragmentManager fragmentManager = getSupportFragmentManager();
fragmentManager.beginTransaction()
.replace(R.id.container, PlaceholderFragment.newInstance(position + 1 ))
.commit();}}
And after doing this the content to be loaded from first item click of navigation drawer doesn't appears when the application is first launched....
it appears only when the item is clicked...
i want it to appear on application launch...
Do i need to create separate methods in my database handler class to return separate query results for each switch case??
Basically what i did is i created a separate function which can manipulate the query string accordingly the position of each element of navigation drawer and then it is being passed to get cursor data function in database handler and then the query results being back thrown to the simple cursor adapter in MainActivity....
The other thing is did for the problem of blank screen when the application is launched is i called the same function which manipulating the database query for the first element...
This is giving me my desired outputs..
Still if there is another good to go method out there then i am open to know that approach too.
for till now i will accept this as a answer..
I am trying to implement a navigation drawer in a BaseActivity, that shows different options depending on the activity that is currently showing. For that, I developed a BaseActivity, that implements the navigation drawer, and decides what to show, depending on the activity that is currently showing. The purpose of this, is to make all other activities that need to use the navigation drawer, expand the BaseActivity.
The following code, shows no errors, but the navigation drawer shows itself completely empty, and does not show when I click the 'home' button, neither the 'menu' button, a functionality that I implemented with the 'onKeyDown' method. It just shows, when I use the following gesture: move the finger from the left to the right in the left side of the screen.
When I do the same in each class I need, instead of using a BaseActivity, everything works perfeclty fine.
I have been trying this for days now and I still do not understand why, the content of the navigation drawer is still not showing. I would appreciate some help please. Thanks in advance.
Here, the core classes of the problem:
BaseActivity.java
public abstract class BaseActivity extends ActionBarActivity
{
public DrawerLayout drawerLayout = null;
public ActionBarDrawerToggle drawerToggle = null;
public Activity currentActivity = null;
public ArrayList<Item> navDrawerItems = new ArrayList<Item>();
public ItemListAdapter adapter = null;
public ListView drawerList = null;
int id = 0;
protected void onCreate(Bundle savedInstanceState, int resLayoutID)
{
super.onCreate(savedInstanceState);
setContentView(resLayoutID);
currentActivity = this;
drawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
drawerToggle = new ActionBarDrawerToggle(currentActivity,
drawerLayout,
R.drawable.ic_drawer,
R.string.open_menu,
R.string.close_menu)
{
public void onDrawerClosed(View view)
{
Log.e("", "Close drawer");
getSupportActionBar().setTitle(getTitle());
ActivityCompat.invalidateOptionsMenu(currentActivity);
}
public void onDrawerOpened(View drawerView)
{
Log.e("", "Open drawer");
getSupportActionBar().setTitle(getTitle());
ActivityCompat.invalidateOptionsMenu(currentActivity);
}
};
drawerLayout.setDrawerListener(drawerToggle);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setHomeButtonEnabled(true);
// Populate navigation drawer depending on the activity
// that is currently showing.
if (this.getClass().getSimpleName().equals("Z"))
setUpNavigationForZActivity();
}
private void setUpNavigationForZActivity()
{
Log.e("", "In setUpNavigationForZActivity");
// Prepare list items.
id = R.string.title_activity_A;
navDrawerItems.add(new NavigationDrawerItem(getString(id), Utils.activityIcon().get(id)));
id = R.string.title_activity_B;
navDrawerItems.add(new NavigationDrawerItem(getString(id), Utils.activityIcon().get(id)));
// Populate view.
drawerList = (ListView) findViewById(R.id.left_menu);
adapter = new ItemListAdapter(currentActivity, navDrawerItems;
drawerList.setAdapter(adapter);
drawerList.setOnItemClickListener(new OnItemClickListener()
{
public void onItemClick(AdapterView<?> parent, View view, int position,
long id)
{
Intent intent = null;
switch(position)
{
case 0:
intent = new Intent(currentActivity, A.class);
startActivity(intent)
break;
case 1:
intent = new Intent(currentActivity, B.class);
startActivity(intent)
break;
default:
}
}
});
}
#Override
public boolean onOptionsItemSelected(MenuItem item)
{
if (drawerToggle.onOptionsItemSelected(item))
return true;
return super.onOptionsItemSelected(item);
}
#Override
protected void onPostCreate(Bundle savedInstanceState)
{
super.onPostCreate(savedInstanceState);
drawerToggle.syncState();
}
#Override
public void onConfigurationChanged(Configuration newConfig)
{
super.onConfigurationChanged(newConfig);
drawerToggle.onConfigurationChanged(newConfig);
}
#Override
public boolean onKeyDown(int keyCode, KeyEvent e)
{
Log.e("", "onKeyDown");
if (keyCode == KeyEvent.KEYCODE_MENU)
{
if(!drawerLayout.isDrawerOpen(Gravity.LEFT))
drawerLayout.openDrawer(Gravity.LEFT);
else
drawerLayout.closeDrawer(Gravity.LEFT);
}
return super.onKeyDown(keyCode, e);
}
}
Z.java
public class Z extends BaseActivity
{
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState, R.layout.Z);
setContentView(R.layout.Z);
//Other things to do...
}
}
Z.xml
<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" >
<!-- Main content view -->
<ScrollView
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:fillViewport="true" >
// Other layout and views configurations...
</ScrollView>
<!-- Navigation drawer -->
<ListView
android:id="#+id/left_menu"
android:layout_width="240dp"
android:layout_height="match_parent"
android:layout_gravity="start"
android:background="#color/gray_7_5"
android:choiceMode="singleChoice" />
</android.support.v4.widget.DrawerLayout>
I do not exactly know why you would want to implement it that way but if you still want to do it this way i would suggest making your navdrawer use a listview with an adapter to draw items from an array and then have your base activity have a getData() call that you can override in your derived activities that will supply the data that the Adapter so that the listview will then draw the appropriate items in the navdrawer. You will then have to implement the onItemClick event for each listview per activity.