Actionbar items always appear in overflow menu - android

I am using a MainActivity derived from FragmentActivity with Fragments representing each tab
in the ActionBar. From the docs at http://developer.android.com/guide/topics/ui/actionbar.html, I implemented a split ActionBar with tabs on top and the remaining Action Items on the bottom part of the ActionBar.
Because each tab's Fragment have their own specific Action Items, a menu representing these Actions is loaded when a Fragment is being called.
This works in general. However, the Action Items always appear in the Overflow Menu on the bottom part of the ActionBar, even though there is plenty of space left of it. Actually, no visible item(s) or text take up space.
I am using the support v4 library.
MainActivity
public class MainActivity extends FragmentActivity implements ActionBar.TabListener {
TabNavigatorPagerAdapter tabNavigatorPagerAdapter;
ViewPager viewPager;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// Create the adapter that will return a fragment for each of the three primary sections
// of the app
tabNavigatorPagerAdapter = new TabNavigatorPagerAdapter(getSupportFragmentManager());
// Set up the action bar
final ActionBar actionBar = getActionBar();
// Specify that the Home/Up button should not be enabled, since there is no hierarchical
// parent
actionBar.setHomeButtonEnabled(false);
//force tabs at top and actions at bottom
actionBar.setDisplayShowHomeEnabled(false);
actionBar.setDisplayShowTitleEnabled(false);
// Specify that we will be displaying tabs in the action bar
actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
// Set up the ViewPager, attaching the adapter and setting up a listener for when the
// user swipes between sections
viewPager = (ViewPager) findViewById(R.id.pager);
viewPager.setAdapter(tabNavigatorPagerAdapter);
viewPager.setOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener() {
#Override
public void onPageSelected(int position) {
// When swiping between different app sections, select the corresponding tab
// We can also use the ActionBar.Tab#select() to do this if we have a reference
// to the Tab
actionBar.setSelectedNavigationItem(position);
}
});
// For each of the sections in the app, add a tab to the action bar.
// Add Calendar activity
actionBar.addTab(actionBar.newTab().setText(R.string.calendar_activity).setTabListener(this));
// Add Grocery List activity
actionBar.addTab(actionBar.newTab().setText(R.string.grocery_list_activity).setTabListener(this));
// Add Search activity
actionBar.addTab(actionBar.newTab().setText(R.string.search_activity).setTabListener(this));
}
#Override
public void onTabUnselected(ActionBar.Tab tab, FragmentTransaction fragmentTransaction) {
}
#Override
public void onTabSelected(ActionBar.Tab tab, FragmentTransaction fragmentTransaction) {
// When the given tab is selected, switch to the corresponding page in the ViewPager.
viewPager.setCurrentItem(tab.getPosition());
}
#Override
public void onTabReselected(ActionBar.Tab tab, FragmentTransaction fragmentTransaction) {
}
public static class TabNavigatorPagerAdapter extends FragmentPagerAdapter {
public TabNavigatorPagerAdapter(android.support.v4.app.FragmentManager fm) {
super(fm);
}
#Override
public Fragment getItem(int i) {
switch (i) {
case 0:
// This is the Calendar section of the App
return new CalendarFragment();
default:
// The other sections of the app are dummy placeholders
Fragment fragment = new DummySectionFragment();
Bundle args = new Bundle();
args.putInt(DummySectionFragment.ARG_SECTION_NUMBER, i + 1);
fragment.setArguments(args);
return fragment;
}
}
#Override
public int getCount() {
return 3;
}
#Override
public CharSequence getPageTitle(int position) {
return "Section " + (position + 1);
}
}
// The Calendar fragment
public static class CalendarFragment extends Fragment {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_calendar, container, false);
Bundle args = getArguments();
((TextView) rootView.findViewById(android.R.id.text1)).setText(R.string.calendar_activity);
setHasOptionsMenu(true);
return rootView;
}
#Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
super.onCreateOptionsMenu(menu, inflater);
menu.clear();
inflater.inflate(R.menu.menu_calendar, menu);
}
}
}
Manifest
<?xml version="1.0" encoding="utf-8"?>
<uses-sdk android:minSdkVersion="11" />
<application
android:allowBackup="true"
android:icon="#drawable/ic_launcher"
android:label="#string/app_name"
android:theme="#android:style/Theme.Holo.Light.DarkActionBar">
<activity
android:name=".MainActivity"
android:label="#string/app_name"
android:uiOptions="splitActionBarWhenNarrow">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<meta-data android:name="android.support.UI_OPTIONS"
android:value="splitActionBarWhenNarrow"/>
</activity>
<activity
android:name=".CollectionDemoActivity"
android:label="#string/demo_collection">
</activity>
</application>
Calendar menu xml
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:myfirstapp="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
tools:context="com.kikicorp.myfirstapp.MainActivity">
<item
android:id="#+id/qwe"
android:icon="#drawable/ic_launcher"
myfirstapp:showAsAction="ifRoom"
android:title="qwe">
</item>
<item
android:id="#+id/ee"
android:icon="#drawable/ic_action_edit"
myfirstapp:showAsAction="ifRoom"
android:title="edit">
</item>
<item
android:id="#+id/xx"
android:icon="#drawable/ic_action_new"
myfirstapp:showAsAction="ifRoom"
android:title="new">
</item>
<item
android:id="#+id/go_crazy"
android:icon="#drawable/ic_action_search"
myfirstapp:showAsAction="ifRoom"
android:title="#string/go_crazy_action">
</item>
</menu>
Result screenshot

You are using the native action bar, as indicated by the fact that you are inheriting from FragmentActivity, not ActionBarActivity. Hence, myfirstapp:showAsAction will be ignored. Use android:showAsAction for the native action bar.
If you are intending to use appcompat-v7 for the action bar backport, then change your class to inherit from ActionBarActivity, not FragmentActivity.

Related

Trying to show Google Maps inside fragment dynamically, error inflating class fragment

I'm new-ish to Android so this could be a very obvious mistake I'm making.
I am trying to get my fragment to display Google Maps, but it keeps crashing the app. The error message is
"java.lang.RuntimeException: Unable to start activity ComponentInfo{com.example.daniel.mts/com.example.daniel.mts.MainActivity}: android.view.InflateException: Binary XML file line #12: Error inflating class fragment"
Here is my MainActivity that displays a toolbar, and also replaces the FrameLayout in activity_main.xml with my HomeFragment.
public class MainActivity extends AppCompatActivity
implements OnFragmentInteractionListener {
private DrawerLayout mDrawer;
private Toolbar toolbar;
private NavigationView nvDrawer;
private ActionBarDrawerToggle drawerToggle;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//Set toolbar to replace the action bar
toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
//find drawer view
mDrawer = (DrawerLayout) findViewById(R.id.drawer_layout);
drawerToggle = setupDrawerToggle();
//Tie drawerlayout events to the action bar toggle for open and close
mDrawer.addDrawerListener(drawerToggle);
//Find our drawer view
nvDrawer = (NavigationView) findViewById(R.id.nvView);
//Setup drawer view
setUpDrawerContent(nvDrawer);
Fragment fragment = null;
Class fragmentClass = HomeFragment.class;
try {
fragment = (Fragment) fragmentClass.newInstance();
} catch (Exception e) {
e.printStackTrace();
}
FragmentTransaction def = getSupportFragmentManager().beginTransaction();
def.replace(R.id.flContent, fragment);
def.commit();
}
Here is my activity main xml file
<!-- This LinearLayout represents the contents of the screen -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<!-- The toolbar displayed at the top -->
<include
layout="#layout/toolbar"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<!-- The main content view where fragments are loaded -->
<FrameLayout
android:id="#+id/flContent"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>
<!-- The navigation drawer that comes from the left -->
<!-- android:layout_gravity needs to be set to 'start' -->
<android.support.design.widget.NavigationView
android:id="#+id/nvView"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="start"
android:background="#android:color/white"
app:menu="#menu/drawer_view"
app:headerLayout="#layout/nav_header" />
</android.support.v4.widget.DrawerLayout>
My HomeFragment contains just boilerplate code from creating a new fragment, it displays my home_fragment.xml
public class HomeFragment extends Fragment {
// TODO: Rename parameter arguments, choose names that match
// the fragment initialization parameters, e.g. ARG_ITEM_NUMBER
private static final String ARG_PARAM1 = "param1";
private static final String ARG_PARAM2 = "param2";
// TODO: Rename and change types of parameters
private String mParam1;
private String mParam2;
private OnFragmentInteractionListener mListener;
public HomeFragment() {
// Required empty public constructor
}
/**
* Use this factory method to create a new instance of
* this fragment using the provided parameters.
*
* #param param1 Parameter 1.
* #param param2 Parameter 2.
* #return A new instance of fragment HomeFragment.
*/
// TODO: Rename and change types and number of parameters
public static HomeFragment newInstance(String param1, String param2) {
HomeFragment fragment = new HomeFragment();
Bundle args = new Bundle();
args.putString(ARG_PARAM1, param1);
args.putString(ARG_PARAM2, param2);
fragment.setArguments(args);
return fragment;
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (getArguments() != null) {
mParam1 = getArguments().getString(ARG_PARAM1);
mParam2 = getArguments().getString(ARG_PARAM2);
}
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.home_fragment, container, false); }
// TODO: Rename method, update argument and hook method into UI event
public void onButtonPressed(Uri uri) {
if (mListener != null) {
mListener.onFragmentMessage("hello", uri);
}
}
#Override
public void onAttach(Context context) {
super.onAttach(context);
if (context instanceof OnFragmentInteractionListener) {
mListener = (OnFragmentInteractionListener) context;
} else {
throw new RuntimeException(context.toString()
+ " must implement OnFragmentInteractionListener");
}
}
#Override
public void onDetach() {
super.onDetach();
mListener = null;
}
/**
* This interface must be implemented by activities that contain this
* fragment to allow an interaction in this fragment to be communicated
* to the activity and potentially other fragments contained in that
* activity.
* <p>
* See the Android Training lesson <a href=
* "http://developer.android.com/training/basics/fragments/communicating.htm l"
* >Communicating with Other Fragments</a> for more information.
*/
public void onFragmentMessage(String MSG, Object data) {
}
This is my home_fragment.xml which displays the fragment that should show the map.
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.example.daniel.mts.HomeFragment">
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:text="#string/home_frag" />
<fragment
android:id="#+id/map"
android:layout_width="match_parent"
android:layout_height="match_parent"
class="com.google.android.gms.maps.SupportMapFragment" />
</FrameLayout>
This is my manifest file
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.daniel.mts">
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
<application
android:allowBackup="true"
android:icon="#mipmap/ic_bus"
android:label="#string/app_name"
android:supportsRtl="true"
android:theme="#style/AppTheme">
<activity
android:name=".MainActivity"
android:screenOrientation="portrait"
>
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<meta-data
android:name="com.google.android.gms.version"
android:value="#integer/google_play_services_version" />
<meta-data
android:name="com.google.android.geo.API_KEY"
android:value="#string/google_api_key"/>
</application>
</manifest>
Where am I messing up?
Based from Fragments, you can use either one of these two ways to add a fragment to the activity layout:
Declare the fragment inside the activity's layout file.
In this case, you can specify layout properties for the fragment as if it were a view.
When the system creates this activity layout, it instantiates each fragment specified in the layout and calls the onCreateView() method for each one, to retrieve each fragment's layout. The system inserts the View returned by the fragment directly in place of the <fragment> element.
Or, programmatically add the fragment to an existing ViewGroup.
To make fragment transactions in your activity (such as add, remove, or replace a fragment), you must use APIs from FragmentTransaction. You can get an instance of FragmentTransaction from your Activity like this:
FragmentManager fragmentManager = getFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
You can then add a fragment using the add() method, specifying the fragment to add and the view in which to insert it. For example:
ExampleFragment fragment = new ExampleFragment();
fragmentTransaction.add(R.id.fragment_container, fragment);
fragmentTransaction.commit();
You may check the given documentations for the complete details.
And in addition to that, you may also try the solution used by #Edoardo Moreni in this SO post, wherein he was able to solve similar issue by removing the fragment from the xml, inserted it in the activity xml and passed onCreateView (from the fragment class) to the superclass.
Hope that helps!

How to add one section separator for Navigation Drawer in Android?

I have a navigation drawer like this image. I want to add a section separator (like the line separating Neptune). It seems simple but I can't find anything on the web that was useful for my case.
Here is my MainActivity:
public class MainActivity extends Activity {
private DrawerLayout mDrawerLayout;
private ListView mDrawerList;
private ActionBarDrawerToggle mDrawerToggle;
private CharSequence mDrawerTitle;
private CharSequence mTitle;
private String[] mPlanetTitles;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mTitle = mDrawerTitle = getTitle();
mPlanetTitles = getResources().getStringArray(R.array.planets_array);
mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
mDrawerList = (ListView) findViewById(R.id.left_drawer);
// 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
mDrawerList.setAdapter(new ArrayAdapter<String>(this,
R.layout.drawer_list_item, mPlanetTitles));
mDrawerList.setOnItemClickListener(new DrawerItemClickListener());
// enable ActionBar app icon to behave as action to toggle nav drawer
getActionBar().setDisplayHomeAsUpEnabled(true);
getActionBar().setHomeButtonEnabled(true);
// ActionBarDrawerToggle ties together the the proper interactions
// between the sliding drawer and the action bar app icon
mDrawerToggle = new ActionBarDrawerToggle(
this, /* host Activity */
mDrawerLayout, /* 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 */
) {
public void onDrawerClosed(View view) {
getActionBar().setTitle(mTitle);
invalidateOptionsMenu(); // creates call to onPrepareOptionsMenu()
}
public void onDrawerOpened(View drawerView) {
getActionBar().setTitle(mDrawerTitle);
invalidateOptionsMenu(); // creates call to onPrepareOptionsMenu()
}
};
mDrawerLayout.setDrawerListener(mDrawerToggle);
if (savedInstanceState == null) {
selectItem(0);
}
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.main, menu);
return super.onCreateOptionsMenu(menu);
}
/* Called whenever we call invalidateOptionsMenu() */
#Override
public boolean onPrepareOptionsMenu(Menu menu) {
// If the nav drawer is open, hide action items related to the content view
boolean drawerOpen = mDrawerLayout.isDrawerOpen(mDrawerList);
menu.findItem(R.id.action_websearch).setVisible(!drawerOpen);
return super.onPrepareOptionsMenu(menu);
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
// The action bar home/up action should open or close the drawer.
// ActionBarDrawerToggle will take care of this.
if (mDrawerToggle.onOptionsItemSelected(item)) {
return true;
}
// Handle action buttons
switch(item.getItemId()) {
case R.id.action_websearch:
// create intent to perform web search for this planet
Intent intent = new Intent(Intent.ACTION_WEB_SEARCH);
intent.putExtra(SearchManager.QUERY, getActionBar().getTitle());
// catch event that there's no activity to handle intent
if (intent.resolveActivity(getPackageManager()) != null) {
startActivity(intent);
} else {
Toast.makeText(this, R.string.app_not_available, Toast.LENGTH_LONG).show();
}
return true;
default:
return super.onOptionsItemSelected(item);
}
}
/* The click listner for ListView in the navigation drawer */
private class DrawerItemClickListener implements ListView.OnItemClickListener {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
selectItem(position);
}
}
private void selectItem(int position) {
// update the main content by replacing fragments
Fragment fragment = new PlanetFragment();
Bundle args = new Bundle();
args.putInt(PlanetFragment.ARG_PLANET_NUMBER, position);
fragment.setArguments(args);
FragmentManager fragmentManager = getFragmentManager();
fragmentManager.beginTransaction().replace(R.id.content_frame, fragment).commit();
// update selected item and title, then close the drawer
mDrawerList.setItemChecked(position, true);
setTitle(mPlanetTitles[position]);
mDrawerLayout.closeDrawer(mDrawerList);
}
#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);
}
/**
* Fragment that appears in the "content_frame", shows a planet
*/
public static class PlanetFragment extends Fragment {
public static final String ARG_PLANET_NUMBER = "planet_number";
public PlanetFragment() {
// Empty constructor required for fragment subclasses
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_planet, container, false);
int i = getArguments().getInt(ARG_PLANET_NUMBER);
String planet = getResources().getStringArray(R.array.planets_array)[i];
int imageId = getResources().getIdentifier(planet.toLowerCase(Locale.getDefault()),
"drawable", getActivity().getPackageName());
((ImageView) rootView.findViewById(R.id.image)).setImageResource(imageId);
getActivity().setTitle(planet);
return rootView;
}
}
}
activity_main.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">
<FrameLayout
android:id="#+id/content_frame"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<ListView
android:id="#+id/left_drawer"
android:layout_width="240dp"
android:layout_height="match_parent"
android:layout_gravity="start"
android:choiceMode="singleChoice"
android:divider="#android:color/transparent"
android:dividerHeight="0dp"
android:background="#111"/>
</android.support.v4.widget.DrawerLayout>
drawer_list_item.xml:
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#android:id/text1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceListItemSmall"
android:gravity="center_vertical"
android:paddingLeft="16dp"
android:paddingRight="16dp"
android:textColor="#fff"
android:background="?android:attr/activatedBackgroundIndicator"
android:minHeight="?android:attr/listPreferredItemHeightSmall"/>
I want this to be simple but I can't find anything good on the web. Is there a way that I can isolate Neptune and create a section for it? Does anyone have any suggestions? Thanks.
Make sure you define each group with a unique ID, separator won't appear without the ID.
For example, this is my drawer_menu.xml:
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<group
android:id="#+id/menu_top"
android:checkableBehavior="single">
<item
android:checked="true"
android:id="#+id/drawer_item_timeline"
android:icon="#drawable/ic_timer_grey600_24dp"
android:title="#string/drawer_timeline"/>
<item
android:id="#+id/drawer_item_reports"
android:icon="#drawable/ic_timetable_grey600_24dp"
android:title="#string/drawer_reports"/>
</group>
<group
android:id="#+id/menu_bottom"
android:checkableBehavior="none">
<item
android:id="#+id/drawer_item_settings"
android:icon="#drawable/ic_settings_black_24dp"
android:title="#string/drawer_settings" >
</item>
</group>
</menu>
Gabriel adds below in the comments that if the group doesn't have an id, the separator will not appear.
To separate menu items by a divider line, only group items with a unique id like following example:
activity_main_drawer.xml:
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
tools:showIn="navigation_view">
<item
android:id="#+id/nav_apps_and_games"
android:icon="#drawable/ic_apps_black_24dp"
android:title="#string/my_apps_and_games" />
<item
android:id="#+id/nav_bookmarked_apps"
android:icon="#drawable/ic_add_bookmark_black_24dp"
android:title="#string/bookmarked_apps" />
<item
android:id="#+id/nav_manage_downloads"
android:icon="#drawable/ic_downloading_file_black_24dp"
android:title="#string/manage_downloads" />
<!-- SET A UNIQUE ID TO THE BELOW GROUP -->
<group android:id="#+id/group1">
<item
android:id="#+id/nav_settings"
android:icon="#drawable/ic_settings_black_24dp"
android:title="#string/settings" />
<item
android:id="#+id/nav_sign_up"
android:icon="#drawable/ic_card_membership_black_24dp"
android:title="#string/sign_up_login" />
</group>
</menu>
Visual Result:
My hacky method is similar to Mostrapotski's.
In my Layout for my custom adapter, I'm adding a horizontal separator at the beginning of each item and setting it's visibility to gone.
For the elements that mark the beginning of a new group, I set their visibility to visible so that the separator shows up on top of it.
You have two choices
Your items can be separated (a list at the top, and classic views at the bottom).
Then instead of the listview in your main layout (android:id="#+id/left_drawer") you can have a rather complex LinearLayout including those 3 items (list, separator, and bottom views)
Your items must be exactly as in your example, then you need the separator in the list, you can use some logic in your adapter to draw a view on top of the list item where you need the separator. (meaning your list item won't be a single textview anymore, but a LinearLayout with a gone separator (and visible sometimes, according to your adapter's logic).
To help you with some sample code, can you please post all the items you need in your menu ? We need to know exactly what will be static and what will be scrollable.
Edit: If you want that working with the exemple, get rid of the line
mDrawerList.setAdapter(new ArrayAdapter<String>(this, ...)
You need to supply a home made adapter like this:
https://github.com/codepath/android_guides/wiki/Using-an-ArrayAdapter-with-ListView
As i said in 2, in your adapter, you will have logic, and thus you can say in the getView() method
if(myPlanet.isNeptune())
holder.mSepatator.setVisibility(View.VISIBLE);
else
holder.mSepatator.setVisibility(View.GONE);
Add group in Menu file to add divider
enter image description here
<group android:checkableBehavior="none">
<item android:title="______________________________________________________________"
android:iconTint="#color/colorWhite"
android:enabled="false">
</item>
</group>

Adding Admob Google Play Services into Fragment

I'm trying to migrated from Android SDK to Google Play Services for Admob. I'm having problems with adding in the java code on the fragment side.
It's an Activity that uses fragments as Tabs to navigate between XML layouts. In the past I was able to add all the admob information directly in the XML layout. Google Services requires you to have it linked on the java side.
It keeps on crashing, and I can't figure how to handle the AdView with the fragements. I was looking at adding it into the Main.java but unsure how TabListener will handle the AdView.
I need some help on this one.
I already done the following items:
1. Add Google Play services library into my project
2. I declared all permission in the manifest
<activity android:name="com.google.android.gms.ads.AdActivity" android:configChanges="keyboard|keyboardHidden|orientation|screenLayout|uiMode|screenSize|smallestScr eenSize" />
<meta-data android:name="com.google.android.gms.version" android:value="#integer/google_play_services_version" />
I have a Main.java and TabListener to switch between the fragments but can't figure out how to link the Adview xml to the Fragments.
It can't see the views in the fragment, and it doesn't work in the Main.java.
AdView adView = (AdView)this.findViewById(R.id.adView);
AdRequest adRequest = new AdRequest.Builder().build();
adView.loadAd(adRequest)
Main.java is my main.
public class Main extends Activity {
// Declare Tab Variable
ActionBar.Tab Tab1, Tab2, Tab3;
Fragment fragmentTab1 = new FragmentTab1();
Fragment fragmentTab2 = new FragmentTab2();
Fragment fragmentTab3 = new FragmentTab3();
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
ActionBar actionBar = getActionBar();
// Hide Actionbar Icon
// Set to False, we are not using icons
actionBar.setDisplayShowHomeEnabled(false);
// Hide Actionbar Title
// Set to False, used up too much space on phones
actionBar.setDisplayShowTitleEnabled(false);
// Create Actionbar Tabs
actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
// Set Tab Icon and Titles
// Titles are as follows below
Tab1 = actionBar.newTab().setText("Tab 1");
Tab2 = actionBar.newTab().setText("Tab 2");
Tab3 = actionBar.newTab().setText("Tab 3);
// Set Tab Listeners
Tab1.setTabListener(new TabListener(fragmentTab1));
Tab2.setTabListener(new TabListener(fragmentTab2));
Tab3.setTabListener(new TabListener(fragmentTab3));
// Add tabs to actionbar
actionBar.addTab(Tab1);
actionBar.addTab(Tab2);
actionBar.addTab(Tab3);
}
}
TabListener.java for switching between fragments.
public class TabListener implements ActionBar.TabListener {
Fragment fragment;
public TabListener(Fragment fragment) {
// TODO Auto-generated constructor stub
this.fragment = fragment;
}
#Override
public void onTabSelected(Tab tab, FragmentTransaction ft) {
// TODO Auto-generated method stub
ft.replace(R.id.fragment_container, fragment);
}
#Override
public void onTabUnselected(Tab tab, FragmentTransaction ft) {
// TODO Auto-generated method stub
ft.remove(fragment);
}
#Override
public void onTabReselected(Tab tab, FragmentTransaction ft) {
// TODO Auto-generated method stub
}
}
My XML fragmentTab1 for example.
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/LinearLayout1"
android:orientation="vertical"
android:background="#drawable/background1"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<com.google.android.gms.ads.AdView
xmlns:ads="http://schemas.android.com/apk/res-auto"
android:id="#+id/adView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
ads:adUnitId="#string/admob_string"
android:gravity="bottom"
ads:adSize="BANNER"/>
</LinearLayout>
Your AdView code needs to go in your Fragment.java class not your Main.java class. Also, a standard convention would be to name "Main" MainActivity.java rather than Main.java.

Android Fragment Duplicate Objects in Layout

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

Problem with the action bar and fragments: the app crashes when go back on a tab

I'm new on Android and I try to make an application on Android Honeycomb 3.0
Here is my problem: I have 2 tabs in my action bar. Tab 1 uses fragments A and B and Tab 2 uses fragments C and D. When I load the application, the tab 1 is selected and fragments A and B are displayed. Then I click on tab 2 and it also works fine. But when I go back to tab 1, the app crashes and the following error is shown:
android.view.InflateException: Binary XML file line #6: Error inflating class fragment.....
.....
Caused by:java.lang.IllegalArgumentException: Binary XML file line #6: Duplicate
id 0x7f............. tag null or parent id 0x.......
here is my code:
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
ActionBar bar = getActionBar();
bar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
bar.setDisplayShowTitleEnabled(false);
ActionBar.Tab tab1 = bar.newTab().setText("tab 1");
ActionBar.Tab tab2 = bar.newTab().setText("tab 2");
Fragment frag1 = new FragmentOne();
Fragment frag2 = new FragmentTwo();
tab1.setTabListener(new MyTabListener(frag1));
tab2.setTabListener(new MyTabListener(frag2));
bar.addTab(tab1);
bar.addTab(tab2);
}
private class MyTabListener implements ActionBar.TabListener {
private Fragment mFragment;
// Called to create an instance of the listener when adding a new tab
public MyTabListener(Fragment fragment) {
mFragment = fragment;
}
public void onTabSelected(Tab tab, FragmentTransaction ft) {
ft.add(R.id.fragments, mFragment);
}
public void onTabUnselected(Tab tab, FragmentTransaction ft) {
ft.remove(mFragment);
}
public void onTabReselected(Tab tab, FragmentTransaction ft) {
// do nothing
}
}
Fragment 1:
public class FragmentOne extends Fragment {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View mainView = inflater.inflate(R.layout.fragments, container, false);
return mainView;
}
}
fragments.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<fragment
xmlns:android="http://schemas.android.com/apk/res/android"
android:name="ch.comem.test.FragmentOneA"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/idFragment_one_a"
android:layout_weight="30">
</fragment>
<fragment
xmlns:android="http://schemas.android.com/apk/res/android"
android:name="ch.comem.test.FragmentOneB"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/idFragment_one_b"
android:layout_weight="70">
</fragment>
Thanks for your help.
The main issue I see is that your FragmentOne class inflates fragments.xml, which itself contains references to two further fragments FragmentOne and FragmentTwo. This is not valid as Fragments can not contain other Fragments.

Categories

Resources