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>