Using ActionBarSherlock With the New SupportMapFragment

Solution 1:

It all works like a charm, mainly thanks to Jake's great work on ActionBarSherlock

Here are the steps I followed:

  1. Create a SherlockMapFragment class in your actiobarsherlock library project. I simply made a copy of SherlockFragment because I also needed support for setHasOptionsMenu(true)
  2. The activity extends SherlockFragmentActivity (as usual)
  3. The fragment extends the newly created SherlockMapFragment
  4. ActionBarSherlock requires the new google-play-services_lib library
  5. Your project requires the ActionBarSherlock library. No need to include the google-play-services again, or to build against Google API.
  6. As mentionned by Graham, you have to drop support for API 7 devices: <uses-sdk android:minSdkVersion="8" android:targetSdkVersion="17" />

And here's some code for a more detailed explanation:

SherlockMapFragment

package com.actionbarsherlock.app;

import com.actionbarsherlock.internal.view.menu.MenuItemWrapper;
import com.actionbarsherlock.internal.view.menu.MenuWrapper;
import com.actionbarsherlock.view.Menu;
import com.actionbarsherlock.view.MenuInflater;
import com.actionbarsherlock.view.MenuItem;
import com.google.android.gms.maps.SupportMapFragment;

import android.app.Activity;
import android.support.v4.app.Watson.OnCreateOptionsMenuListener;
import android.support.v4.app.Watson.OnOptionsItemSelectedListener;
import android.support.v4.app.Watson.OnPrepareOptionsMenuListener;

public class SherlockMapFragment extends SupportMapFragment
        implements OnCreateOptionsMenuListener,
        OnPrepareOptionsMenuListener,
        OnOptionsItemSelectedListener {
    private SherlockFragmentActivity mActivity;

    public SherlockFragmentActivity getSherlockActivity() {
        return mActivity;
    }

    @Override
    public void onAttach(Activity activity) {
        if (!(activity instanceof SherlockFragmentActivity)) {
            throw new IllegalStateException(getClass().getSimpleName()
                    + " must be attached to a SherlockFragmentActivity.");
        }
        mActivity = (SherlockFragmentActivity) activity;

        super.onAttach(activity);
    }

    @Override
    public void onDetach() {
        mActivity = null;
        super.onDetach();
    }

    @Override
    public final void onCreateOptionsMenu(android.view.Menu menu, android.view.MenuInflater inflater) {
        onCreateOptionsMenu(new MenuWrapper(menu), mActivity.getSupportMenuInflater());
    }

    @Override
    public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
        // Nothing to see here.
    }

    @Override
    public final void onPrepareOptionsMenu(android.view.Menu menu) {
        onPrepareOptionsMenu(new MenuWrapper(menu));
    }

    @Override
    public void onPrepareOptionsMenu(Menu menu) {
        // Nothing to see here.
    }

    @Override
    public final boolean onOptionsItemSelected(android.view.MenuItem item) {
        return onOptionsItemSelected(new MenuItemWrapper(item));
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Nothing to see here.
        return false;
    }
}

The activity:

public class MainActivity extends SherlockFragmentActivity {
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }
}

The activity XML layout:

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/root"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="horizontal" >

    <fragment
        android:id="@+id/fragment_map"
        android:name=".ui.fragments.MapFragment"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:tag="tag_fragment_map" />

    <fragment
        android:id="@+id/fragment_help"
        android:name=".ui.fragments.HelpFragment"
        android:layout_width="0dp"
        android:layout_height="match_parent"
        android:tag="tag_fragment_help" />
</FrameLayout>

The map fragment:

public class MapFragment extends SherlockMapFragment {
    private GoogleMap mMap;
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        View root = super.onCreateView(inflater, container, savedInstanceState);
        mMap = getMap();
        return root;
    }
}

Solution 2:

I heard that Jake is not going to do too much more to ABS as Google may be bringing out their own backward compatible ActionBar. I think if I remember correctly it was discussed in one of the Android related Google+ hangouts.

The new maps requires API level 8 onward so before even worrying about the actionbar you will run into problems if you must support API level 7.

My advice would be produce 2 layout files one for level 7 and and one for 8+. In the level 7 use the now old MapView although they are deprecating it, which for me shows how API level 7 is not necessarily worth considering as a target. In the 8+ layout use the new map system.

As for the actionbar, we are porting an app right now and have easily and successfully added a map to a ViewPager, by creating the Fragment programtically (rather than in XML). We have tested it on multiple devices.

We have also had no issues using the new map system as described in Google demos with ABS. We declared the fragment in an XML layout and set this as the content of the activity. The ActionBar displays as normal. The Activity is a SherlockFragmentActivity.

Solution 3:

Basically what i am sure of is that this SupportMapFragment is totally fresh and maybe the maintainer of ActionBarSherlock didn't yet have the time to add it on the ABS Project.

Also it requires API Lvl 8+ so you can just remove your support to the API lvl 7 devices or you will have to wait for Jake to add support for the new SupportMapFragment.

For other API lvls you can find a work around here:http://xrigau.wordpress.com/2012/03/22/howto-actionbarsherlock-mapfragment-listfragment/

Solution 4:

I tried implementing SupportMapFragment with ActionBarSherlock.

It is working very fine.

enter image description here

Below is code snippet.

package com.example.newmapview;

import android.os.Bundle;
import android.widget.Toast;
import com.actionbarsherlock.app.SherlockFragmentActivity;
import com.actionbarsherlock.view.Menu;
import com.actionbarsherlock.view.MenuItem;
import com.actionbarsherlock.view.SubMenu;
import com.google.android.gms.maps.GoogleMap;
import com.google.android.gms.maps.SupportMapFragment;

public class MainActivity extends SherlockFragmentActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        SupportMapFragment fragment = SupportMapFragment.newInstance();
        getSupportFragmentManager().beginTransaction()
                .add(R.id.mapLayout, fragment).commit();

    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {

        SubMenu subMenu = menu.addSubMenu("Type");

        subMenu.add("Normal");
        subMenu.add("SATELLITE");

        subMenu.getItem().setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS);

        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {

        if (item.getTitle().toString().equalsIgnoreCase("Normal")) {
            Toast.makeText(this, "Clicked Normal", Toast.LENGTH_LONG).show();
            GoogleMap googleMap = ((SupportMapFragment) getSupportFragmentManager()
                    .findFragmentById(R.id.mapLayout)).getMap();

            if (googleMap != null)
                googleMap.setMapType(GoogleMap.MAP_TYPE_NORMAL);
            else
                Toast.makeText(this, "GoogleMap is null", Toast.LENGTH_LONG)
                        .show();
        } else if (item.getTitle().toString().equalsIgnoreCase("SATELLITE")) {
            Toast.makeText(this, "Clicked SATELLITE", Toast.LENGTH_LONG).show();
            GoogleMap googleMap = ((SupportMapFragment) getSupportFragmentManager()
                    .findFragmentById(R.id.mapLayout)).getMap();

            if (googleMap != null)
                googleMap.setMapType(GoogleMap.MAP_TYPE_SATELLITE);
            else
                Toast.makeText(this, "GoogleMap is null", Toast.LENGTH_LONG)
                        .show();
        }

        return true;

    }
}

Hope this will help.