Android谷歌地图-从FAB菜单选择地图类型

Android谷歌地图-从FAB菜单选择地图类型,android,android-layout,android-fragments,kotlin,material-ui,Android,Android Layout,Android Fragments,Kotlin,Material Ui,我正试图创建一个好看的菜单来更改地图类型,就像谷歌地图上的一样。。当您单击图层FAB时,它会出现。我不知道它是否是一个自定义的FAB菜单,或者它是否会设置动画并打开一个片段 如何实现这种外观?我现在能想到的最简单的解决方案是: 将添加到布局中: 在“活动”中,将“可见性”设置为“视图”。单击按钮上的“可见性”: fab.setOnClickListener{ cardview.visibility = View.VISIBLE } 经过大量的阅读和学习,我成功地设计出了令我满意的

我正试图创建一个好看的菜单来更改地图类型,就像谷歌地图上的一样。。当您单击图层FAB时,它会出现。我不知道它是否是一个自定义的FAB菜单,或者它是否会设置动画并打开一个片段


如何实现这种外观?

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

  • 添加到布局中:
  • 在“活动”中,将“可见性”设置为“视图”。单击按钮上的“可见性”:

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

  • 经过大量的阅读和学习,我成功地设计出了令我满意的外观。对于任何想要相同外观的人,下面是我的代码和参考资料

    注意:它并不完美,在其他一些设备上可能看起来不一样,不要对我的编码判断太多(我是一个初学者……我可以进行一些重构,但它完成了工作)

    额外要点:

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

    资源


    键入默认值.png

    type_satellite.png

    键入地形.png

    圆角矩形.xml

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

    最终结果


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


    谢谢你的帮助,伙计。这对我的想法很有帮助:)我已经发布了我最终完成的答案。NicCoe如果Ro Ras post帮助投票,或者接受他的答案
    <shape xmlns:android="http://schemas.android.com/apk/res/android">
        <solid android:color="#2962ff" />
        <corners android:radius="10dp" />
    </shape>
    
    <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>
    
    <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>
    
       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
        }
    }