Android Create Bottom Sheet Map Like Google Maps

Android How To Create Bottom Sheet Map Like Google Maps


1. Project Structure

Package name : map.bottomsheet.fyprojects.com.bottomsheetmap


2. Gradle

apply plugin: 'com.android.application'

android {
    compileSdkVersion 28
    defaultConfig {
        applicationId "map.bottomsheet.fyprojects.com.bottomsheetmap"
        minSdkVersion 16
        targetSdkVersion 28
        versionCode 1
        versionName "1.0"
        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
}

dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    implementation 'com.android.support:appcompat-v7:28.0.0'
    implementation 'com.android.support.constraint:constraint-layout:1.1.3'
    testImplementation 'junit:junit:4.12'
    androidTestImplementation 'com.android.support.test:runner:1.0.2'
    androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'

    implementation 'com.android.support:design:28.0.0'
    implementation 'com.android.support:support-v13:28.0.0'
    implementation 'com.android.support:recyclerview-v7:28.0.0'
    implementation 'com.github.bumptech.glide:glide:3.7.0'
    implementation 'com.balysv:material-ripple:1.0.2'
    implementation 'com.google.android.gms:play-services-maps:16.1.0'
}


3. Res Folder Dtructure

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

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

    <!-- search bar layout -->
    <include
        android:id="@+id/search_bar"
        layout="@layout/include_card_view_search_bar" />


    <!--bottom sheet container-->
    <include layout="@layout/sheet_map" />

    <android.support.design.widget.FloatingActionButton
        android:id="@+id/fab_directions"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_margin="@dimen/spacing_smlarge"
        android:clickable="true"
        android:tint="@android:color/white"
        app:fabSize="normal"
        app:layout_anchor="@id/bottom_sheet"
        app:layout_anchorGravity="top|end"
        app:rippleColor="@android:color/white"
        app:srcCompat="@drawable/ic_pin_drop" />


</android.support.design.widget.CoordinatorLayout>


include_card_view_search_bar.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:fitsSystemWindows="true"
    android:orientation="vertical">

    <android.support.v7.widget.CardView
        android:id="@+id/search_bar"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginBottom="@dimen/spacing_middle"
        android:layout_marginLeft="@dimen/spacing_middle"
        android:layout_marginRight="@dimen/spacing_middle"
        android:layout_marginTop="@dimen/spacing_large"
        android:clipToPadding="false"
        app:cardBackgroundColor="@android:color/white"
        app:cardCornerRadius="3dp"
        app:cardElevation="3dp"
        app:cardUseCompatPadding="false"
        app:layout_collapseMode="parallax">

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

            <ImageButton
                android:id="@+id/bt_menu"
                android:layout_width="?attr/actionBarSize"
                android:layout_height="?attr/actionBarSize"
                android:background="?attr/selectableItemBackgroundBorderless"
                android:tint="@color/grey_60"
                app:srcCompat="@drawable/ic_stack_menu" />

            <TextView
                android:id="@+id/search_text"
                android:layout_width="0dp"
                android:layout_height="match_parent"
                android:layout_weight="1"
                android:gravity="center_vertical"
                android:text="Search"
                android:textAppearance="@style/Base.TextAppearance.AppCompat.Subhead"
                android:textColor="@color/grey_40" />

            <ImageButton
                android:layout_width="?attr/actionBarSize"
                android:layout_height="?attr/actionBarSize"
                android:background="?attr/selectableItemBackgroundBorderless"
                android:tint="@color/grey_60"
                app:srcCompat="@drawable/ic_mic" />

        </LinearLayout>

    </android.support.v7.widget.CardView>

</LinearLayout>


sheet_map.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/bottom_sheet"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:background="@android:color/transparent"
    android:orientation="vertical"
    app:behavior_hideable="true"
    app:behavior_peekHeight="85dp"
    app:layout_behavior="android.support.design.widget.BottomSheetBehavior">

    <android.support.v7.widget.CardView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="5dp"
        app:cardCornerRadius="1dp"
        app:cardElevation="20dp">

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

            <View
                android:layout_width="30dp"
                android:layout_height="5dp"
                android:layout_gravity="center"
                android:layout_marginTop="10dp"
                android:background="@drawable/swipe_up_handle" />

            <TextView
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_marginLeft="@dimen/spacing_xxlarge"
                android:layout_marginStart="@dimen/spacing_xxlarge"
                android:gravity="center_vertical"
                android:minHeight="50dp"
                android:paddingEnd="@dimen/spacing_large"
                android:paddingLeft="@dimen/spacing_large"
                android:paddingRight="@dimen/spacing_large"
                android:paddingStart="@dimen/spacing_large"
                android:text="Dandelion Chocolate"
                android:textAppearance="@style/TextAppearance.AppCompat.Headline" />

            <LinearLayout
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:orientation="vertical"
                android:padding="@dimen/spacing_large">

                <LinearLayout
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:layout_marginBottom="@dimen/spacing_middle"
                    android:layout_marginLeft="@dimen/spacing_xxlarge"
                    android:layout_marginStart="@dimen/spacing_xxlarge"
                    android:gravity="center_vertical"
                    android:orientation="horizontal">

                    <android.support.v7.widget.AppCompatRatingBar
                        style="@style/Yellow.Small.AppCompatRatingBar"
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:numStars="5"
                        android:rating="3.5"
                        android:stepSize="0.5"
                        android:theme="@style/Yellow.Small.AppCompatRatingBar" />

                    <TextView
                        android:layout_width="match_parent"
                        android:layout_height="wrap_content"
                        android:text="4.7 (51)"
                        android:textAppearance="@style/TextAppearance.AppCompat.Medium" />

                </LinearLayout>

                <View
                    android:layout_width="match_parent"
                    android:layout_height="1dp"
                    android:layout_marginLeft="@dimen/spacing_xxlarge"
                    android:layout_marginStart="@dimen/spacing_xxlarge"
                    android:background="@color/grey_10" />

                <TextView
                    android:layout_width="match_parent"
                    android:layout_height="?attr/actionBarSize"
                    android:layout_marginLeft="@dimen/spacing_xxlarge"
                    android:layout_marginStart="@dimen/spacing_xxlarge"
                    android:gravity="center_vertical"
                    android:text="12 min away"
                    android:textAppearance="@style/TextAppearance.AppCompat.Medium"
                    android:textColor="@color/colorPrimary" />

                <View
                    android:layout_width="match_parent"
                    android:layout_height="1dp"
                    android:layout_marginLeft="@dimen/spacing_xxlarge"
                    android:layout_marginStart="@dimen/spacing_xxlarge"
                    android:background="@color/grey_10" />

                <LinearLayout
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:layout_marginTop="@dimen/spacing_middle"
                    android:orientation="vertical">

                    <LinearLayout
                        android:layout_width="match_parent"
                        android:layout_height="wrap_content"
                        android:gravity="center_vertical"
                        android:orientation="horizontal">

                        <ImageButton
                            android:layout_width="wrap_content"
                            android:layout_height="?attr/actionBarSize"
                            android:background="@android:color/transparent"
                            android:tint="@color/grey_20"
                            app:srcCompat="@drawable/ic_location" />

                        <View
                            android:layout_width="@dimen/spacing_mxlarge"
                            android:layout_height="0dp" />

                        <TextView
                            android:layout_width="match_parent"
                            android:layout_height="wrap_content"
                            android:gravity="center_vertical"
                            android:text="740 Valencia St, San Francisco, CA"
                            android:textAppearance="@style/TextAppearance.AppCompat.Medium"
                            android:textColor="@color/grey_90" />

                    </LinearLayout>

                    <LinearLayout
                        android:layout_width="match_parent"
                        android:layout_height="wrap_content"
                        android:gravity="center_vertical"
                        android:orientation="horizontal">

                        <ImageButton
                            android:layout_width="wrap_content"
                            android:layout_height="?attr/actionBarSize"
                            android:background="@android:color/transparent"
                            android:tint="@color/grey_20"
                            app:srcCompat="@drawable/ic_phone" />

                        <View
                            android:layout_width="@dimen/spacing_mxlarge"
                            android:layout_height="0dp" />

                        <TextView
                            android:layout_width="match_parent"
                            android:layout_height="wrap_content"
                            android:gravity="center_vertical"
                            android:text="(415) 349-0942"
                            android:textAppearance="@style/TextAppearance.AppCompat.Medium"
                            android:textColor="@color/grey_90" />

                    </LinearLayout>

                    <LinearLayout
                        android:layout_width="match_parent"
                        android:layout_height="wrap_content"
                        android:gravity="center_vertical"
                        android:orientation="horizontal">

                        <ImageButton
                            android:layout_width="wrap_content"
                            android:layout_height="?attr/actionBarSize"
                            android:background="@android:color/transparent"
                            android:tint="@color/grey_20"
                            app:srcCompat="@drawable/ic_schedule" />

                        <View
                            android:layout_width="@dimen/spacing_mxlarge"
                            android:layout_height="0dp" />

                        <TextView
                            android:layout_width="match_parent"
                            android:layout_height="wrap_content"
                            android:gravity="center_vertical"
                            android:text="Wed, 10 AM - 9 PM"
                            android:textAppearance="@style/TextAppearance.AppCompat.Medium"
                            android:textColor="@color/grey_90" />

                    </LinearLayout>

                </LinearLayout>

            </LinearLayout>

        </LinearLayout>
    </android.support.v7.widget.CardView>
</LinearLayout>


colors.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <color name="colorPrimary">#1976D2</color>
    <color name="colorPrimaryDark">#1565C0</color>
    <color name="colorPrimaryLight">#1E88E5</color>
    <color name="colorAccent">#FF4081</color>
    <color name="colorAccentDark">#F50057</color>
    <color name="colorAccentLight">#FF80AB</color>

    <color name="grey_3">#f7f7f7</color>
    <color name="grey_5">#f2f2f2</color>
    <color name="grey_10">#e6e6e6</color>
    <color name="grey_20">#cccccc</color>
    <color name="grey_40">#999999</color>
    <color name="grey_60">#666666</color>
    <color name="grey_80">#37474F</color>
    <color name="grey_90">#263238</color>
    <color name="grey_95">#1a1a1a</color>
    <color name="grey_100_">#0d0d0d</color>

    <color name="yellow_50">#FFFDE7</color>
    <color name="yellow_100">#FFF9C4</color>
    <color name="yellow_200">#FFF59D</color>
    <color name="yellow_300">#FFF176</color>
    <color name="yellow_400">#FFEE58</color>
    <color name="yellow_500">#FFEB3B</color>
    <color name="yellow_600">#FDD835</color>
    <color name="yellow_700">#FBC02D</color>
    <color name="yellow_800">#F9A825</color>
    <color name="yellow_900">#F57F17</color>
    <color name="yellow_A100">#FFFF8D</color>
    <color name="yellow_A200">#FFFF00</color>
    <color name="yellow_A400">#FFEA00</color>
    <color name="yellow_A700">#FFD600</color>

</resources>


dimen.xml

<resources>
    <!--genaral spacing-->
    <dimen name="spacing_xsmall">2dp</dimen>
    <dimen name="spacing_small">3dp</dimen>
    <dimen name="spacing_medium">5dp</dimen>
    <dimen name="spacing_xmedium">7dp</dimen>
    <dimen name="spacing_middle">10dp</dimen>
    <dimen name="spacing_large">15dp</dimen>
    <dimen name="spacing_smlarge">18dp</dimen>
    <dimen name="spacing_mlarge">20dp</dimen>
    <dimen name="spacing_mxlarge">25dp</dimen>
    <dimen name="spacing_xlarge">35dp</dimen>
    <dimen name="spacing_xmlarge">40dp</dimen>
    <dimen name="spacing_xxlarge">50dp</dimen>
    <dimen name="spacing_xxxlarge">55dp</dimen>
    <dimen name="appbar_padding_top">8dp</dimen>
</resources>


 
strings.xml

<resources>
    <string name="app_name">BottomSheetMap</string>
    <string name="bottom_sheet_behavior" translatable="false">android.support.design.widget.BottomSheetBehavior</string>

    <string name="google_maps_key" templateMergeStrategy="preserve" translatable="false">
        AIzaSyC3SrcUtXXXXXXXXXXXXXXXXXXXXXX
    </string>

</resources>


styles.xml

 <resources>

    <!-- Base application theme. -->
    <style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
        <!-- Customize your theme here. -->
        <item name="colorPrimary">@color/colorPrimary</item>
        <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
        <item name="colorAccent">@color/colorAccent</item>
    </style>

    <!--style for ripple library-->
    <style name="RippleStyleWhite">
        <item name="mrl_rippleOverlay">true</item>
        <item name="mrl_rippleColor">#80FFFFFF</item>
        <item name="mrl_rippleHover">true</item>
        <item name="mrl_rippleAlpha">0.2</item>
    </style>

    <style name="RippleStyleBlack" parent="RippleStyleWhite">
        <item name="mrl_rippleColor">#8096989A</item>
    </style>

    <style name="Button.Primary" parent="@style/Widget.AppCompat.Button.Colored">
        <item name="colorButtonNormal">@color/colorPrimary</item>
        <item name="android:textColor">@android:color/white</item>
    </style>

    <style name="Yellow.Small.AppCompatRatingBar" parent="Base.Widget.AppCompat.RatingBar.Small">
        <item name="colorControlNormal">@color/grey_60</item>
        <item name="colorControlActivated">@color/yellow_600</item>
    </style>

</resources>

 


4. Utils

Tools

package map.bottomsheet.fyprojects.com.bottomsheetmap.utils;

import android.app.Activity;
import android.content.Context;
import android.graphics.Bitmap;
import android.os.Build;
import android.support.annotation.DrawableRes;
import android.support.v4.graphics.drawable.RoundedBitmapDrawable;
import android.support.v4.graphics.drawable.RoundedBitmapDrawableFactory;
import android.view.Window;
import android.view.WindowManager;
import android.widget.ImageView;
import com.bumptech.glide.Glide;
import com.bumptech.glide.request.target.BitmapImageViewTarget;
import com.google.android.gms.maps.GoogleMap;

import map.bottomsheet.fyprojects.com.bottomsheetmap.R;

public class Tools {

    public static GoogleMap configActivityMaps(GoogleMap googleMap) {
        // set map type
        googleMap.setMapType(GoogleMap.MAP_TYPE_NORMAL);
        // Enable / Disable zooming controls
        googleMap.getUiSettings().setZoomControlsEnabled(false);

        // Enable / Disable Compass icon
        googleMap.getUiSettings().setCompassEnabled(true);
        // Enable / Disable Rotate gesture
        googleMap.getUiSettings().setRotateGesturesEnabled(true);
        // Enable / Disable zooming functionality
        googleMap.getUiSettings().setZoomGesturesEnabled(true);

        googleMap.getUiSettings().setScrollGesturesEnabled(true);
        googleMap.getUiSettings().setMapToolbarEnabled(true);

        return googleMap;
    }

}


5. Activity

MainActivity

package map.bottomsheet.fyprojects.com.bottomsheetmap;

import android.content.DialogInterface;
import android.os.Build;
import android.support.annotation.NonNull;
import android.support.design.widget.BottomSheetBehavior;
import android.support.design.widget.BottomSheetDialog;
import android.support.design.widget.FloatingActionButton;
import android.support.v7.app.ActionBar;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.Toolbar;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.WindowManager;
import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.Toast;

import com.google.android.gms.maps.CameraUpdate;
import com.google.android.gms.maps.CameraUpdateFactory;
import com.google.android.gms.maps.GoogleMap;
import com.google.android.gms.maps.OnMapReadyCallback;
import com.google.android.gms.maps.SupportMapFragment;
import com.google.android.gms.maps.model.LatLng;
import com.google.android.gms.maps.model.Marker;
import com.google.android.gms.maps.model.MarkerOptions;

import map.bottomsheet.fyprojects.com.bottomsheetmap.utils.Tools;

public class MainActivity extends AppCompatActivity {
    private GoogleMap mMap;
    private BottomSheetBehavior bottomSheetBehavior;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        initMapFragment();
        initComponent();
        Toast.makeText(this, "Swipe up bottom sheet", Toast.LENGTH_SHORT).show();
    }


    private void initComponent() {
        // get the bottom sheet view
        LinearLayout llBottomSheet = (LinearLayout) findViewById(R.id.bottom_sheet);

        // init the bottom sheet behavior
        bottomSheetBehavior = BottomSheetBehavior.from(llBottomSheet);

        // change the state of the bottom sheet
        bottomSheetBehavior.setState(BottomSheetBehavior.STATE_COLLAPSED);

        // set callback for changes
        bottomSheetBehavior.setBottomSheetCallback(new BottomSheetBehavior.BottomSheetCallback() {
            @Override
            public void onStateChanged(@NonNull View bottomSheet, int newState) {

            }

            @Override
            public void onSlide(@NonNull View bottomSheet, float slideOffset) {

            }
        });

        ((FloatingActionButton) findViewById(R.id.fab_directions)).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                bottomSheetBehavior.setState(BottomSheetBehavior.STATE_COLLAPSED);
                try {
                    mMap.animateCamera(zoomingLocation());
                } catch (Exception e) {
                }
            }
        });
    }

    private void initMapFragment() {
        SupportMapFragment mapFragment = (SupportMapFragment) getSupportFragmentManager().findFragmentById(R.id.map);
        mapFragment.getMapAsync(new OnMapReadyCallback() {
            @Override
            public void onMapReady(GoogleMap googleMap) {
                mMap = Tools.configActivityMaps(googleMap);
                MarkerOptions markerOptions = new MarkerOptions().position(new LatLng(37.7610237, -122.4217785));
                mMap.addMarker(markerOptions);
                mMap.moveCamera(zoomingLocation());
                mMap.setOnMarkerClickListener(new GoogleMap.OnMarkerClickListener() {
                    @Override
                    public boolean onMarkerClick(Marker marker) {
                        bottomSheetBehavior.setState(BottomSheetBehavior.STATE_COLLAPSED);
                        try {
                            mMap.animateCamera(zoomingLocation());
                        } catch (Exception e) {
                        }
                        return true;
                    }
                });
            }
        });
    }

    private CameraUpdate zoomingLocation() {
        return CameraUpdateFactory.newLatLngZoom(new LatLng(37.76496792, -122.42206407), 13);
    }

}


6.Manifest

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="map.bottomsheet.fyprojects.com.bottomsheetmap">

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">

        <!-- Add Google Map Library -->
        <uses-library android:name="com.google.android.maps" />

        <!-- Google API Key -->
        <meta-data
            android:name="com.google.android.geo.API_KEY"
            android:value="@string/google_maps_key" />

        <activity android:name="map.bottomsheet.fyprojects.com.bottomsheetmap.MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>