Android Google Map-从FAB菜单中选择地图类型

时间:2018-08-27 03:33:39

标签: android android-layout android-fragments kotlin material-ui

我正试图创建一个外观漂亮的菜单来更改地图类型,就像Google Maps上的菜单类型一样。单击图层FAB时会显示该菜单。我不知道这是不是自定义FAB菜单,或者它是否设置了动画效果并打开了一个片段。

Screenshot of Google Maps layers menu

如何实现这种外观?

2 个答案:

答案 0 :(得分:2)

经过大量的阅读和学习,我设法完全设计出了自己满意的外观。对于任何想要相同外观的人,下面是我的代码和资源...

注意:它并不完全完美,在其他设备上可能看起来有所不同,并且不要过多地判断我的编码(我是初学者...我可以进行一些重构,但是它可以完成的工作)。

加分点:

  • 写在科特林
  • 很确定需要API 21+。对于较早的版本,此处尚未实现任何解决方法
  • 选择视图的打开/关闭使用圆形显示动画,而不是Google扩展一个动画(我更喜欢实现)
  • 缺乏优化可能会导致低端设备的性能下降

资源


enter image description here type_default.png

enter image description here type_satellite.png

enter image description here type_terrain.png

rounded_rectangle.xml

<shape xmlns:android="http://schemas.android.com/apk/res/android">
    <solid android:color="#2962ff" />
    <corners android:radius="10dp" />
</shape>

ic_map_layers.xml

<vector xmlns:android="http://schemas.android.com/apk/res/android"
        android:width="24dp"
        android:height="24dp"
        android:viewportWidth="24.0"
        android:viewportHeight="24.0">
    <path
        android:fillColor="#3C4043"
        android:pathData="M11.99,18.54l-7.37,-5.73L3,14.07l9,7 9,-7 -1.63,-1.27 
        -7.38,5.74zM12,16l7.36,-5.73L21,9l-9,-7 -9,7 1.63,1.27L12,16z"/>
</vector>

地图布局文件


这里列出的代码也与地图和其他FAB一起嵌套在约束布局中,但是如果您正在阅读此书,我认为您不需要知道如何将地图放入...

<android.support.design.widget.FloatingActionButton
    android:id="@+id/map_type_FAB"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_marginEnd="24dp"
    android:layout_marginTop="24dp"
    android:clickable="true"
    android:focusable="true"
    app:backgroundTint="#FFF"
    app:fabSize="mini"
    app:layout_constraintEnd_toEndOf="parent"
    app:layout_constraintTop_toTopOf="@+id/map_view"
    app:rippleColor="#eff5ff"
    app:srcCompat="@drawable/ic_map_layers" />

<android.support.constraint.ConstraintLayout
    android:id="@+id/map_type_selection"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:background="@drawable/map_type_background"
    android:elevation="6dp"
    android:padding="8dp"
    android:visibility="invisible"
    app:layout_constraintEnd_toEndOf="@+id/map_type_FAB"
    app:layout_constraintTop_toTopOf="@+id/map_type_FAB">


    <View
        android:id="@+id/map_type_default_background"
        android:layout_width="54dp"
        android:layout_height="54dp"
        android:background="@drawable/rounded_rectangle"
        android:visibility="invisible"
        app:layout_constraintBottom_toBottomOf="@+id/map_type_default"
        app:layout_constraintEnd_toEndOf="@+id/map_type_default"
        app:layout_constraintStart_toStartOf="@+id/map_type_default"
        app:layout_constraintTop_toTopOf="@+id/map_type_default" />

    <ImageButton
        android:id="@+id/map_type_default"
        android:layout_width="50dp"
        android:layout_height="50dp"
        android:layout_marginStart="8dp"
        android:layout_marginTop="8dp"
        android:background="@drawable/type_default"
        android:scaleType="fitCenter"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/textView13" />

    <View
        android:id="@+id/map_type_satellite_background"
        android:layout_width="54dp"
        android:layout_height="54dp"
        android:background="@drawable/rounded_rectangle"
        android:visibility="invisible"
        app:layout_constraintBottom_toBottomOf="@+id/map_type_satellite"
        app:layout_constraintEnd_toEndOf="@+id/map_type_satellite"
        app:layout_constraintStart_toStartOf="@+id/map_type_satellite"
        app:layout_constraintTop_toTopOf="@+id/map_type_satellite" />

    <ImageButton
        android:id="@+id/map_type_satellite"
        android:layout_width="50dp"
        android:layout_height="50dp"
        android:layout_marginEnd="32dp"
        android:layout_marginStart="32dp"
        android:layout_marginTop="8dp"
        android:background="@drawable/type_satellite"
        android:scaleType="fitCenter"
        app:layout_constraintEnd_toStartOf="@+id/map_type_terrain"
        app:layout_constraintStart_toEndOf="@+id/map_type_default"
        app:layout_constraintTop_toBottomOf="@+id/textView13" />

    <View
        android:id="@+id/map_type_terrain_background"
        android:layout_width="54dp"
        android:layout_height="54dp"
        android:background="@drawable/rounded_rectangle"
        android:visibility="invisible"
        app:layout_constraintBottom_toBottomOf="@+id/map_type_terrain"
        app:layout_constraintEnd_toEndOf="@+id/map_type_terrain"
        app:layout_constraintStart_toStartOf="@+id/map_type_terrain"
        app:layout_constraintTop_toTopOf="@+id/map_type_terrain" />

    <ImageButton
        android:id="@+id/map_type_terrain"
        android:layout_width="50dp"
        android:layout_height="50dp"
        android:layout_marginEnd="8dp"
        android:layout_marginTop="8dp"
        android:background="@drawable/type_terrain"
        android:scaleType="fitCenter"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/textView13" />

    <TextView
        android:id="@+id/textView13"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="8dp"
        android:layout_marginTop="8dp"
        android:fontFamily="sans-serif"
        android:text="Map Type"
        android:textAllCaps="true"
        android:textColor="@android:color/black"
        android:textSize="12sp"
        android:textStyle="bold"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <TextView
        android:id="@+id/map_type_default_text"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="8dp"
        android:text="Default"
        android:textColor="#808080"
        android:textSize="12sp"
        app:layout_constraintEnd_toEndOf="@+id/map_type_default"
        app:layout_constraintStart_toStartOf="@+id/map_type_default"
        app:layout_constraintTop_toBottomOf="@+id/map_type_default" />

    <TextView
        android:id="@+id/map_type_satellite_text"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="8dp"
        android:text="Satellite"
        android:textColor="#808080"
        android:textSize="12sp"
        app:layout_constraintEnd_toEndOf="@+id/map_type_satellite"
        app:layout_constraintStart_toStartOf="@+id/map_type_satellite"
        app:layout_constraintTop_toBottomOf="@+id/map_type_satellite" />

    <TextView
        android:id="@+id/map_type_terrain_text"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="8dp"
        android:text="Terrain"
        android:textColor="#808080"
        android:textSize="12sp"
        app:layout_constraintEnd_toEndOf="@+id/map_type_terrain"
        app:layout_constraintStart_toStartOf="@+id/map_type_terrain"
        app:layout_constraintTop_toBottomOf="@+id/map_type_terrain" />

</android.support.constraint.ConstraintLayout>

地图片段


onMapReady函数中的代码片段。这不是最漂亮的部分,但是可以完成工作。

   override fun onMapReady(googleMap: GoogleMap) {

    // Initialise the map variable
    map = googleMap

    // When map is initially loaded, determine which map type option to 'select'
    when {
        map.mapType == GoogleMap.MAP_TYPE_SATELLITE -> {
            map_type_satellite_background.visibility = View.VISIBLE
            map_type_satellite_text.setTextColor(Color.BLUE)
        }
        map.mapType == GoogleMap.MAP_TYPE_TERRAIN -> {
            map_type_terrain_background.visibility = View.VISIBLE
            map_type_terrain_text.setTextColor(Color.BLUE)
        }
        else -> {
            map_type_default_background.visibility = View.VISIBLE
            map_type_default_text.setTextColor(Color.BLUE)
        }
    }

    // Set click listener on FAB to open the map type selection view
    mapTypeFAB.setOnClickListener {

        // Start animator to reveal the selection view, starting from the FAB itself
        val anim = ViewAnimationUtils.createCircularReveal(
                map_type_selection,
                map_type_selection.width - (map_type_FAB.width / 2),
                map_type_FAB.height / 2,
                map_type_FAB.width / 2f,
                map_type_selection.width.toFloat())
        anim.duration = 200
        anim.interpolator = AccelerateDecelerateInterpolator()

        anim.addListener(object : AnimatorListenerAdapter() {
            override fun onAnimationStart(animation: Animator?) {
                super.onAnimationEnd(animation)
                map_type_selection.visibility = View.VISIBLE
            }
        })

        anim.start()
        mapTypeFAB.visibility = View.INVISIBLE

    }

    // Set click listener on the map to close the map type selection view
    map.setOnMapClickListener {

        // Conduct the animation if the FAB is invisible (window open)
        if (map_type_FAB.visibility == View.INVISIBLE) {

            // Start animator close and finish at the FAB position
            val anim = ViewAnimationUtils.createCircularReveal(
                    map_type_selection,
                    map_type_selection.width - (map_type_FAB.width / 2),
                    map_type_FAB.height / 2,
                    map_type_selection.width.toFloat(),
                    map_type_FAB.width / 2f)
            anim.duration = 200
            anim.interpolator = AccelerateDecelerateInterpolator()

            anim.addListener(object : AnimatorListenerAdapter() {
                override fun onAnimationEnd(animation: Animator?) {
                    super.onAnimationEnd(animation)
                    map_type_selection.visibility = View.INVISIBLE
                }
            })

            // Set a delay to reveal the FAB. Looks better than revealing at end of animation
            Handler().postDelayed({
                kotlin.run {
                    mapTypeFAB.visibility = View.VISIBLE
                }
            }, 100)
            anim.start()
        }
    }

    // Handle selection of the Default map type
    map_type_default.setOnClickListener {
        map_type_default_background.visibility = View.VISIBLE
        map_type_satellite_background.visibility = View.INVISIBLE
        map_type_terrain_background.visibility = View.INVISIBLE
        map_type_default_text.setTextColor(Color.BLUE)
        map_type_satellite_text.setTextColor(Color.parseColor("#808080"))
        map_type_terrain_text.setTextColor(Color.parseColor("#808080"))
        map.mapType = GoogleMap.MAP_TYPE_NORMAL
    }

    // Handle selection of the Satellite map type
    map_type_satellite.setOnClickListener {
        map_type_default_background.visibility = View.INVISIBLE
        map_type_satellite_background.visibility = View.VISIBLE
        map_type_terrain_background.visibility = View.INVISIBLE
        map_type_default_text.setTextColor(Color.parseColor("#808080"))
        map_type_satellite_text.setTextColor(Color.BLUE)
        map_type_terrain_text.setTextColor(Color.parseColor("#808080"))
        map.mapType = GoogleMap.MAP_TYPE_SATELLITE
    }

    // Handle selection of the terrain map type
    map_type_terrain.setOnClickListener {
        map_type_default_background.visibility = View.INVISIBLE
        map_type_satellite_background.visibility = View.INVISIBLE
        map_type_terrain_background.visibility = View.VISIBLE
        map_type_default_text.setTextColor(Color.parseColor("#808080"))
        map_type_satellite_text.setTextColor(Color.parseColor("#808080"))
        map_type_terrain_text.setTextColor(Color.BLUE)
        map.mapType = GoogleMap.MAP_TYPE_TERRAIN
    }
}

最终结果


这是我的最终结果。就像我说的,我只是一个初学者,情况肯定会更好,但是现在,我对结果感到非常满意。

enter image description here

答案 1 :(得分:1)

我现在想到的最简单的解决方案是:

  1. 在布局中添加<CardView>
    ...
   <android.support.design.widget.FloatingActionButton 
      android:id="@+id/fab">  

   <android.support.v7.widget.CardView
      android:id="@+id/cardview"
      app:layout_constraintEnd_toEndOf="@+id/fab"
      app:layout_constraintTop_toTopOf="@+id/fab">
  1. 用对话框填充视图
  2. 将可见性设置为View.GONE

     <android.support.v7.widget.CardView
        android:id="@+id/cardview"
        app:layout_constraintEnd_toEndOf="@+id/fab"
        app:layout_constraintTop_toTopOf="@+id/fab"
        android:visibility="gone">
    
  3. 在活动中,将“可见性”设置为View.Visible,然后单击以下按钮:

    fab.setOnClickListener{  
      cardview.visibility = View.VISIBLE
    }