Elvis Oliveira
Elvis Oliveira

Reputation: 941

Android - Maps don't scroll horizontally

I'm using Google Maps V2 in my Android Project. I have created (with the wizard) an Activity with Scrollable Tabs + Swipe, in one of my layout i'm using SupportMapFragment, but in the map i can't scroll the map horizontally, when a swipe inside the map it's show me the another view. Here's my code:

MainActivity

    public class MainActivity extends FragmentActivity {

    private List<Fragment> paginas;

    /**
     * The {@link android.support.v4.view.PagerAdapter} that will provide
     * fragments for each of the sections. We use a
     * {@link android.support.v4.app.FragmentPagerAdapter} derivative, which
     * will keep every loaded fragment in memory. If this becomes too memory
     * intensive, it may be best to switch to a
     * {@link android.support.v4.app.FragmentStatePagerAdapter}.
     */
    SectionsPagerAdapter mSectionsPagerAdapter;

    /**
     * The {@link ViewPager} that will host the section contents.
     */
    ViewPager mViewPager;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        if(paginas==null){
            paginas = new ArrayList<Fragment>();
            paginas.add(new LocalizacaoPesquisadorActivity());
            paginas.add(new VotosPorRegiaoActivity());
        }

        // Create the adapter that will return a fragment for each of the three
        // primary sections of the app.
        mSectionsPagerAdapter = new SectionsPagerAdapter(
                getSupportFragmentManager());

        // Set up the ViewPager with the sections adapter.
        mViewPager = (ViewPager) findViewById(R.id.pager);
        mViewPager.setAdapter(mSectionsPagerAdapter);



    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.main, menu);
        return true;
    }

    /**
     * A {@link FragmentPagerAdapter} that returns a fragment corresponding to
     * one of the sections/tabs/pages.
     */
    public class SectionsPagerAdapter extends FragmentPagerAdapter {

        public SectionsPagerAdapter(FragmentManager fm) {
            super(fm);
        }

        @Override
        public Fragment getItem(int position) {
            // getItem is called to instantiate the fragment for the given page.
            // Return a DummySectionFragment (defined as a static inner class
            // below) with the page number as its lone argument.
            switch (position) {
            case 0:
                return paginas.get(0);
            case 1:
                return paginas.get(1);
            default: return null;

            }           
        }

        @Override
        public int getCount() {
            // Show 3 total pages.
            return paginas.size();
        }

        @Override
        public CharSequence getPageTitle(int position) {
            Locale l = Locale.getDefault();
            switch (position) {
            case 0:
                return getString(R.string.title_activity_localizacao_pesquisador).toUpperCase(l);
            case 1:
                return getString(R.string.title_activity_votos_por_regiao).toUpperCase(l);          
            }
            return null;
        }
    }



}

LocalizacaoPesquisadorActivity

public class LocalizacaoPesquisadorActivity extends Fragment {

public View onCreateView(LayoutInflater inflater, ViewGroup container,
        Bundle savedInstanceState) {
    View rootView = inflater.inflate(R.layout.activity_localizacao_pesquisador,
            container, false);
    System.out.println();
    return rootView;
}


}

activity_main.xml

<android.support.v4.view.ViewPager xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/pager"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity" >

    <android.support.v4.view.PagerTitleStrip
        android:id="@+id/pager_title_strip"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_gravity="top"
        android:background="#33b5e5"
        android:paddingBottom="4dp"
        android:paddingTop="4dp"
        android:textColor="#fff" />

</android.support.v4.view.ViewPager>

activity_localizacao_pesquisador.xml

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:map="http://schemas.android.com/apk/res=auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android: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=".LocalizacaoPesquisadorActivity" >

    <EditText
        android:id="@+id/editTextDataLocalizacaoPesquisador"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentLeft="true"
        android:layout_alignParentRight="true"
        android:inputType="none"
        android:hint="Data" 
        android:layout_marginLeft="8dp"
        android:layout_marginRight="8dp"
        android:layout_marginTop="4dp"
        android:layout_marginBottom="4dp"/>

    <Spinner
        android:id="@+id/spinnerHorarioLocalizacaoPesquisador"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignLeft="@+id/editTextDataLocalizacaoPesquisador"
        android:layout_alignRight="@+id/editTextDataLocalizacaoPesquisador"
        android:layout_below="@+id/editTextDataLocalizacaoPesquisador"
        android:layout_marginTop="4dp"
        android:layout_marginBottom="4dp" />

    <Button
        android:id="@+id/buttonAtualizarLocalizacaoPesquisador"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignLeft="@+id/editTextDataLocalizacaoPesquisador"
        android:layout_alignRight="@+id/editTextDataLocalizacaoPesquisador"
        android:layout_below="@+id/spinnerHorarioLocalizacaoPesquisador"
        android:text="Atualizar"
        android:layout_marginTop="4dp"
        android:layout_marginBottom="4dp"
        android:onClick="atuarlizarMapaLocalizacaoPesquisador" />

    <fragment android:id="@+id/mapaLocalizacaoPesquisador"
        android:name="com.google.android.gms.maps.SupportMapFragment"
        android:layout_below="@+id/buttonAtualizarLocalizacaoPesquisador"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignLeft="@+id/buttonAtualizarLocalizacaoPesquisador"
        android:layout_alignRight="@+id/buttonAtualizarLocalizacaoPesquisador"
        android:layout_alignParentBottom="true"
        android:layout_marginBottom="4dp"
        android:layout_marginTop="4dp"        
        map:cameraTargetLat="-23.531152"
        map:cameraTargetLng="-46.789876"
        map:cameraZoom="1"
        />

</RelativeLayout>

I'm think in intercept the swipe action when it is on the map, what you think?

Upvotes: 2

Views: 1120

Answers (1)

Sean Barbeau
Sean Barbeau

Reputation: 11756

First, update your Android SDK and make sure you're using the most recent version of the Android support library by copying from <android-sdk>\extras\android\support\v4\android-support-v4.jar. Older versions of the support library don't handle this properly.

Then extend the ViewPager object:

/**
 * Extension of ViewPager that allows the user to move the map
 * inside the fragment, but still supports swiping to the
 * next fragment via "bezel swipe" (i.e., swiping from the edge)
 */
public class ViewPagerMapBevelScroll extends android.support.v4.view.ViewPager {

    private static final int DEFAULT_SWIPE_MARGIN_WIDTH_DIP = 20;
    private int swipeMarginWidth;

    public ViewPagerMapBevelScroll(Context context) {
        super(context);
        setDefaultSwipeMargin(context);
    }

    public ViewPagerMapBevelScroll(Context context, AttributeSet attrs) {
        super(context, attrs);
        setDefaultSwipeMargin(context);
    }

    private void setDefaultSwipeMargin(final Context context) {
        swipeMarginWidth = (int) (DEFAULT_SWIPE_MARGIN_WIDTH_DIP * context
                .getResources().getDisplayMetrics().density);
    }

    @Override
    protected boolean canScroll(View v, boolean checkV, int dx, int x, int y) {
            if (v instanceof ViewPagerMapBevelScroll) {
                if (getCurrentItem() == SectionsPagerAdapter.MAP_TAB) {
                    return !isAllowedMapSwipe(x, dx);
                }
            }
            return super.canScroll(v, checkV, dx, x, y);
        }

    /**
     * Determines if the pointer movement event at x and moved pixels is
     * considered an allowed swipe movement overriding the inner horizontal
     * scroll content protection.
     * 
     * @param x X coordinate of the active touch point
     * @param dx Delta scrolled in pixels
     * @return true if the movement should start a page swipe
     */
    protected boolean isAllowedMapSwipe(final float x, final float dx) {        
        return ((x < swipeMarginWidth) && (dx > 0))
            || ((x > (getWidth() - swipeMarginWidth)) && (dx < 0));
    }
}

Then, change your layout to use ViewPagerMapBevelScroll (making sure you change the package name to match the location of the ViewPagerMapBevelScroll object):

<com.your.package.ViewPagerMapBevelScroll 
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/pager"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity" >

Then, change your SectionsPagerAdapter to add the MAP_TAB value we're referencing in ViewPagerMapBevelScroll, and set this equal to the index of the tab that contains the map:

public class SectionsPagerAdapter extends FragmentStatePagerAdapter {

    public static final int MAP_TAB = 0; // Set this equal to 
                                         // the index of your map tab

    public SectionsPagerAdapter(FragmentManager fm) {
        super(fm);
    }
...
}

If you want to see a full working version of this check out the open-source GPSTest app.

Credit for the isAllowedMapSwipe method goes to Martin Hochstrasser (see http://goo.gl/Hyl2E)

[Update Nov. 8, 2013] - Note that according to BornToCode's comment on this answer, with the most recent support library with ViewPager and Google Play Services library, this workaround is no longer required for Android 3.0 (Honeycomb) and higher, but is still required to get the proper behavior on Android 2.3 (Gingerbread) and Android 2.2 (Froyo).

Upvotes: 4

Related Questions