0

In my app I have set a few tabs using FragmentActivity and a button beside my tabs which activates a slide menu. At the moment I have two Fragments which are displayed for tab 1 and 2. The fragment for tab 1 contains a v2 Google Map and the second is just a blank screen.

enter image description here enter image description here

However when I activate my slide menu I get very different behavior, I have used this slide menu lib for several projects now without any problems. When I activate slide menu while fragment 2 is displayed it works fine but when fragment 1 (map view) is displayed, activating the slide menu causes the map to go black and it displays the map again when the slide menu is closed.

enter image description here enter image description here

Here is my code for setting up the tab

XML

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent" >

<TabHost
    android:id="@android:id/tabhost"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:layout_alignParentLeft="true"
    android:layout_alignParentTop="true" >

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical" >

        <LinearLayout
            android:id="@+id/linearLayout1"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignParentLeft="true"
            android:layout_alignParentTop="true"
            android:orientation="vertical" >

            <Button
                android:id="@+id/button1"
                style="?android:attr/buttonStyleSmall"
                android:layout_width="fill_parent"
                android:layout_height="55dp"
                android:text="Button" />
        </LinearLayout>

        <LinearLayout
            android:id="@+id/linearLayout2"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignParentRight="true"
            android:layout_alignParentTop="true"
            android:layout_toRightOf="@+id/linearLayout1"
            android:orientation="vertical" >

            <TabWidget
                android:id="@android:id/tabs"
                android:layout_width="fill_parent"
                android:layout_height="wrap_content" >
            </TabWidget>
        </LinearLayout>

        <FrameLayout
            android:id="@android:id/tabcontent"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_alignParentBottom="true"
            android:layout_alignParentLeft="true"
            android:layout_alignParentRight="true"
            android:layout_below="@+id/linearLayout1" >

            <FrameLayout
                android:id="@+id/tab_1"
                android:layout_width="fill_parent"
                android:layout_height="fill_parent" />

            <FrameLayout
                android:id="@+id/tab_2"
                android:layout_width="fill_parent"
                android:layout_height="fill_parent" />

            <FrameLayout
                android:id="@+id/tab_3"
                android:layout_width="fill_parent"
                android:layout_height="fill_parent" />

            <FrameLayout
                android:id="@+id/tab_4"
                android:layout_width="fill_parent"
                android:layout_height="fill_parent" />
        </FrameLayout>
    </RelativeLayout>
</TabHost>

JAVA

public class TabsFragment extends Fragment implements OnTabChangeListener {

private static final String TAG = "FragmentTabs";
public static final String TAB_MAP = "Map";
public static final String TAB_VENUES = "Venus";
public static final String TAB_GENRE = "Gap";
public static final String TAB_TICKETS = "Titus";

private View mRoot;
private TabHost mTabHost;
int mCurrentTab;
Button slide_btn;

@Override
public void onAttach(Activity activity) {
    super.onAttach(activity);
}

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
        Bundle savedInstanceState) {
    mRoot = inflater.inflate(R.layout.tabs_fragment, null);
    mTabHost = (TabHost) mRoot.findViewById(android.R.id.tabhost);
    setupTabs();

    return mRoot;
}

@Override
public void onActivityCreated(Bundle savedInstanceState) {
    super.onActivityCreated(savedInstanceState);
    setRetainInstance(true);

    mTabHost.setOnTabChangedListener(this);
    mTabHost.setCurrentTab(0);

    // manually start loading stuff in the first tab
    updateTab(TAB_MAP, R.id.tab_1);     
}

private void setupTabs() {
    mTabHost.setup(); // important!
    mTabHost.addTab(newTab(TAB_MAP, R.id.tab_1, R.drawable.tab_home));
    mTabHost.addTab(newTab(TAB_VENUS, R.id.tab_2, R.drawable.tab_home));
    mTabHost.addTab(newTab(TAB_GAP, R.id.tab_3, R.drawable.tab_home));
    mTabHost.addTab(newTab(TAB_TITUS, R.id.tab_4, R.drawable.tab_home));
}

private TabSpec newTab(String tag, int tabContentId, int drawableId) {
    Log.d(TAG, "buildTab(): tag=" + tag);

    View indicator = LayoutInflater.from(getActivity()).inflate(
            R.layout.tabindicator,
            (ViewGroup) mRoot.findViewById(android.R.id.tabs), false);
    ImageView icon = (ImageView) indicator.findViewById(R.id.icon);
    icon.setImageResource(drawableId);

    TabSpec tabSpec = mTabHost.newTabSpec(tag);
    tabSpec.setIndicator(indicator);
    tabSpec.setContent(tabContentId);
    return tabSpec;
}

@Override
public void onTabChanged(String tabId) {
    Log.d(TAG, "onTabChanged(): tabId=" + tabId);

    if (TAB_MAP.equals(tabId)) {
        updateTab(tabId, R.id.tab_1);
        mCurrentTab = 0;
        return;
    }
    if (TAB_VENUS.equals(tabId)) {
        updateTab(tabId, R.id.tab_2);
        mCurrentTab = 1;
        return;
    }
    if (TAB_GAP.equals(tabId)) {
        updateTab(tabId, R.id.tab_3);
        mCurrentTab = 2;
        return;
    }
    if (TAB_TITUS.equals(tabId)) {
        updateTab(tabId, R.id.tab_4);
        mCurrentTab = 3;
        return;
    }
}

public void updateTab(String tabId, int placeholder) {

    if (tabId.equals("Map")) {

        FragmentManager fm = getFragmentManager();
        if (fm.findFragmentByTag(tabId) == null) {
            getFragmentManager().beginTransaction().add(placeholder, new MyFrag(), "Map").commit();
        }           

    } else if (tabId.equals("Venus")) {

        FragmentManager fm = getFragmentManager();
        if (fm.findFragmentByTag(tabId) == null) {
            getFragmentManager().beginTransaction().add(placeholder, new Green(), "Venus").commit();
        }

    } else if (tabId.equals("Gap")) {

    } else if (tabId.equals("Titus")) {

    }
}

public void slideMenu(){

    if(isAdded()){

        int width = (int) TypedValue.applyDimension(
                TypedValue.COMPLEX_UNIT_DIP, 200, getResources()
                        .getDisplayMetrics());
        SlideoutActivity.prepare(getActivity(), R.id.inner_content, width);
        Intent i = new Intent();
        i.setClass(getActivity(), SlideMenuActivity.class);
        i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        startActivity(i);
        getActivity().overridePendingTransition(0, 0);
    }       
}

}

Then I render this in a FragmentActivity with its own layout containing a fragment.

Here is the code I've used for the map

XML

<RelativeLayout xmlns:tools="http://schemas.android.com/tools"
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".Main" >

<LinearLayout
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_above="@+id/relativeLayout1"
    android:layout_alignParentLeft="true"
    android:layout_alignParentRight="true"
    android:layout_alignParentTop="true"
    android:focusable="true"
    android:focusableInTouchMode="true"
    android:orientation="vertical" >

    <fragment
        android:id="@+id/map"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        class="com.google.android.gms.maps.SupportMapFragment" />
</LinearLayout>

<RelativeLayout
    android:id="@+id/relativeLayout1"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:layout_alignParentBottom="true"
    android:layout_alignParentLeft="true"
    android:layout_alignParentRight="true" >

    <ImageButton
        android:id="@+id/button3"
        style="?android:attr/buttonStyleSmall"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentLeft="true"
        android:layout_centerVertical="true"
        android:src="@drawable/search_selected" />

    <EditText
        android:id="@+id/editText1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentRight="true"
        android:layout_toRightOf="@+id/button3"
        android:ems="10"
        android:inputType="text" >
    </EditText>
</RelativeLayout>

JAVA

public class MyFrag extends Fragment {

GoogleMap map;
private static View view;

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
        Bundle savedInstanceState) {
    if (view != null) {
        ViewGroup parent = (ViewGroup) view.getParent();
        if (parent != null)
            parent.removeView(view);
    }
    try {
        view = inflater.inflate(R.layout.main, container, false);
        new LoadMap().execute();
    } catch (InflateException e) {
        /* map is already there, just return view as it is */
    }

    return view;
}

public class LoadMap extends AsyncTask<String, Integer, Location> {

    LocationManager lm;
    LatLng p = new LatLng(51.50703296721856, -0.11260986328125);

    @Override
    protected Location doInBackground(String... params) {
        map = ((SupportMapFragment) getActivity()
                .getSupportFragmentManager().findFragmentById(R.id.map))
                .getMap();

        LocationManager locationManager = (LocationManager) getActivity()
                .getSystemService(Context.LOCATION_SERVICE);
        Criteria criteria = new Criteria();
        String provider = locationManager.getBestProvider(criteria, true);
        Location location = locationManager.getLastKnownLocation(provider);
        p = new LatLng(location.getLatitude(), location.getLongitude());

        return location;
    }

    protected void onPostExecute(Location location) {

        try {

            if (location != null) {

                map.setMyLocationEnabled(true);
                map.moveCamera(CameraUpdateFactory.newLatLng(p));
                map.moveCamera(CameraUpdateFactory.zoomTo(15));
                map.setOnCameraChangeListener(null);
            } else {
                Toast.makeText(getActivity(), "You got nada",
                        Toast.LENGTH_LONG).show();
            }

        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}   
 }
duggu
  • 37,851
  • 12
  • 116
  • 113
Amanni
  • 1,924
  • 6
  • 31
  • 51

2 Answers2

0

This is a known issue.

You may find workaround for your case here:

http://code.google.com/p/gmaps-api-issues/issues/detail?id=4639

or here:

http://code.google.com/p/gmaps-api-issues/issues/detail?id=4659

MaciejGórski
  • 22,187
  • 7
  • 70
  • 94
0

While I did find some helpful bits in the links posted in the other answers there was no conclusive solution. I had to start afresh and find another way to do this and I've accomplished this with a custom horizontal ScrollView. I'm posting the code so anyone who come across this can find a ready made solution to help them out.

code is below

Custom View

public class SlideMenu extends HorizontalScrollView {
public SlideMenu(Context context, AttributeSet attrs, int defStyle) {
    super(context, attrs, defStyle);
    init(context);
}

public SlideMenu(Context context, AttributeSet attrs) {
    super(context, attrs);
    init(context);
}

public SlideMenu(Context context) {
    super(context);
    init(context);
}

void init(Context context) {
    // remove the fading as the HSV looks better without it
    setHorizontalFadingEdgeEnabled(false);
    setVerticalFadingEdgeEnabled(false);
}

public void initViews(View[] children, int scrollToViewIdx, SizeCallback sizeCallback) {
    // A ViewGroup MUST be the only child of the HSV
    ViewGroup parent = (ViewGroup) getChildAt(0);

    // Add all the children, but add them invisible so that the layouts are calculated, but you can't see the Views
    for (int i = 0; i < children.length; i++) {
        children[i].setVisibility(View.INVISIBLE);
        parent.addView(children[i]);
    }

    // Add a layout listener to this HSV
    // This listener is responsible for arranging the child views.
    OnGlobalLayoutListener listener = new MyOnGlobalLayoutListener(parent, children, scrollToViewIdx, sizeCallback);
    getViewTreeObserver().addOnGlobalLayoutListener(listener);
}

@Override
public boolean onTouchEvent(MotionEvent ev) {
    // Do not allow touch events.
    return false;
}

@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
    // Do not allow touch events.
    return false;
}

/**
 * An OnGlobalLayoutListener impl that passes on the call to onGlobalLayout to a SizeCallback, before removing all the Views
 * in the HSV and adding them again with calculated widths and heights.
 */
class MyOnGlobalLayoutListener implements OnGlobalLayoutListener {
    ViewGroup parent;
    View[] children;
    int scrollToViewIdx;
    int scrollToViewPos = 0;
    SizeCallback sizeCallback;

    public MyOnGlobalLayoutListener(ViewGroup parent, View[] children, int scrollToViewIdx, SizeCallback sizeCallback) {
        this.parent = parent;
        this.children = children;
        this.scrollToViewIdx = scrollToViewIdx;
        this.sizeCallback = sizeCallback;
    }

    @Override
    public void onGlobalLayout() {

        final HorizontalScrollView me = SlideMenu.this;

        // The listener will remove itself as a layout listener to the HSV
        me.getViewTreeObserver().removeGlobalOnLayoutListener(this);

        // Allow the SizeCallback to 'see' the Views before we remove them and re-add them.
        // This lets the SizeCallback prepare View sizes, ahead of calls to SizeCallback.getViewSize().
        sizeCallback.onGlobalLayout();

        parent.removeViewsInLayout(0, children.length);

        final int w = me.getMeasuredWidth();
        final int h = me.getMeasuredHeight();

        // System.out.println("w=" + w + ", h=" + h);
        // Add each view in turn, and apply the width and height returned by the SizeCallback.
        int[] dims = new int[2];
        scrollToViewPos = 0;
        for (int i = 0; i < children.length; i++) {
            sizeCallback.getViewSize(i, w, h, dims);
            children[i].setVisibility(View.VISIBLE);
            parent.addView(children[i], dims[0], dims[1]);
            if (i < scrollToViewIdx) {
                scrollToViewPos += dims[0];
            }
        }

        // For some reason we need to post this action, rather than call immediately.
        // If we try immediately, it will not scroll.
        new Handler().post(new Runnable() {
            @Override
            public void run() {
                me.scrollBy(scrollToViewPos, 0);
            }
        });
    }
}

/**
 * Callback interface to interact with the HSV.
 */
public interface SizeCallback {

    public void onGlobalLayout();

    public void getViewSize(int idx, int w, int h, int[] dims);
}
  }

To use it you need 3 xml layouts

Acts as a container to switch between side menu and activity


 <your.pakage.name.SlideMenu 
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:layout_margin="0px"
    android:background="#00ffffff"
    android:fadingEdge="none"
    android:fadingEdgeLength="0px"
    android:padding="0px"
    android:scrollbars="none" >

    <LinearLayout
        android:id="@+id/top"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:layout_margin="0px"
        android:background="#ffffffff"
        android:orientation="horizontal"
        android:padding="0px" >
    </LinearLayout>

</your.pakage.name.SlideMenu >

Design contents of your menu here

<TextView
    android:id="@+id/text1"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="Option 1"         />

<TextView
    android:id="@+id/2"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="Option 2" />

<TextView
    android:id="@+id/text3"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="Option 3"         />

<TextView
    android:id="@+id/text4"
    android:layout_width="324dp"
    android:layout_height="70dp"
    android:text="Option 4"     />

Some Activity and I'll use ImageView to activate slide menu

<LinearLayout 
android:layout_width="match_parent"
android:layout_height="match_parent"    
android:orientation="vertical" >

<ImageView
    android:id="@+id/imageView1"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:src="@drawable/ic_launcher" />

</LinearLayout>

In your Activity you can use this code to make it work

public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    requestWindowFeature(Window.FEATURE_NO_TITLE);

    LayoutInflater inflater = LayoutInflater.from(this);
    SlideMenu sMenu = (MyHorizontalScrollView) inflater.inflate(R.layout.xml_1, null);
    setContentView(sMenu);

    View menu = inflater.inflate(R.layout.xml_2, null);
    View app = inflater.inflate(R.layout.xml_3, null);
    ImageView menu_btn = (ImageView) app.findViewById(R.id.imageView1);


    menu_btn.setOnClickListener(new ClickListenerForScrolling(sMenu, menu));
    final View[] children = new View[] {menu, app};
    int scrollToViewIdx = 1;
    sMenu.initViews(children, scrollToViewIdx, new SizeCallbackForMenu(menu_btn));
}

//Then create some sub classes

class ClickListenerForScrolling implements OnClickListener {
    SlideMenu scrollView;
    View menu;
    boolean menuOut = false;

    public ClickListenerForScrolling(SlideMenu scrollView,
            View menu) {
        super();
        this.scrollView = scrollView;
        this.menu = menu;
    }

    @Override
    public void onClick(View v) {
        int menuWidth = menu.getMeasuredWidth();
        menu.setVisibility(View.VISIBLE);

        if (!menuOut) {
            int left = 0;
            scrollView.smoothScrollTo(left, 0);             
        } else {
            int left = menuWidth;
            scrollView.smoothScrollTo(left, 0);
        }
        menuOut = !menuOut;
    }
}

static class SizeCallbackForMenu implements SizeCallback {
    int btnWidth;
    View btnSlide;

    public SizeCallbackForMenu(View btnSlide) {
        super();
        this.btnSlide = btnSlide;
    }

    @Override
    public void onGlobalLayout() {
        //use this value to control how far the window will scroll horizontally
        btnWidth = btnSlide.getMeasuredWidth();
    }

    @Override
    public void getViewSize(int idx, int w, int h, int[] dims) {
        dims[0] = w;
        dims[1] = h;
        final int menuIdx = 0;
        if (idx == menuIdx) {
            dims[0] = w - btnWidth;
        }
    }
}
Amanni
  • 1,924
  • 6
  • 31
  • 51