我正试图创建一个外观漂亮的菜单来更改地图类型,就像Google Maps上的菜单类型一样。单击图层FAB时会显示该菜单。我不知道这是不是自定义FAB菜单,或者它是否设置了动画效果并打开了一个片段。
如何实现这种外观?
答案 0 :(得分:2)
经过大量的阅读和学习,我设法完全设计出了自己满意的外观。对于任何想要相同外观的人,下面是我的代码和资源...
注意:它并不完全完美,在其他设备上可能看起来有所不同,并且不要过多地判断我的编码(我是初学者...我可以进行一些重构,但是它可以完成的工作)。
加分点:
资源
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
}
}
最终结果
这是我的最终结果。就像我说的,我只是一个初学者,情况肯定会更好,但是现在,我对结果感到非常满意。
答案 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">
将可见性设置为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">
在活动中,将“可见性”设置为View.Visible
,然后单击以下按钮:
fab.setOnClickListener{
cardview.visibility = View.VISIBLE
}