如何在Android Studio中实现单选按钮切换CardView UI及展开收起动画?
Android Studio实现两个UI交互需求的详细方案
嘿,这两个需求在Android日常开发里真的挺常用的,尤其是第二个类似Google Keep的提醒切换交互,我来给你一步步拆解实现方法,保证你能快速上手:
一、点击按钮修改CardView/Dialog的UI
1. 先搞定布局基础
先在XML里定义好CardView和触发按钮,如果是Dialog的话,还要准备自定义Dialog的布局:
<!-- activity_main.xml --> <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="match_parent" android:orientation="vertical" android:padding="16dp"> <Button android:id="@+id/modifyCardBtn" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="修改CardView样式"/> <androidx.cardview.widget.CardView android:id="@+id/myCard" android:layout_width="match_parent" android:layout_height="120dp" android:layout_marginTop="16dp" app:cardCornerRadius="8dp" app:cardElevation="4dp"> <TextView android:id="@+id/cardText" android:layout_width="match_parent" android:layout_height="match_parent" android:gravity="center" android:text="初始状态的CardView"/> </androidx.cardview.widget.CardView> </LinearLayout> <!-- dialog_custom.xml(自定义Dialog布局) --> <androidx.cardview.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:id="@+id/dialogCard" android:layout_width="match_parent" android:layout_height="wrap_content" app:cardCornerRadius="12dp"> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical" android:padding="16dp"> <TextView android:id="@+id/dialogText" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="初始Dialog内容"/> <Button android:id="@+id/modifyDialogBtn" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="修改Dialog样式" android:layout_marginTop="16dp"/> </LinearLayout> </androidx.cardview.widget.CardView>
2. 编写点击修改逻辑
在Activity/Fragment里给按钮设置点击监听,直接修改UI属性就行,Dialog的话要先获取它的布局控件:
// MainActivity.kt class MainActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) // 处理CardView的修改逻辑 val modifyCardBtn = findViewById<Button>(R.id.modifyCardBtn) val myCard = findViewById<CardView>(R.id.myCard) val cardText = findViewById<TextView>(R.id.cardText) modifyCardBtn.setOnClickListener { // 修改CardView的圆角、阴影和背景色 myCard.radius = 16f myCard.cardElevation = 8f myCard.setCardBackgroundColor(Color.parseColor("#E8F5E9")) // 修改文本内容 cardText.text = "点击按钮后修改的CardView" } // 处理Dialog的修改逻辑 val dialog = AlertDialog.Builder(this) .setView(R.layout.dialog_custom) .create() dialog.show() val dialogCard = dialog.findViewById<CardView>(R.id.dialogCard) val modifyDialogBtn = dialog.findViewById<Button>(R.id.modifyDialogBtn) val dialogText = dialog.findViewById<TextView>(R.id.dialogText) modifyDialogBtn?.setOnClickListener { dialogCard?.setCardBackgroundColor(Color.parseColor("#FFF3E0")) dialogText?.text = "修改后的Dialog内容" } } }
二、单选按钮切换CardView内容+展开收起动画
这个需求和Google Keep的提醒功能逻辑完全一致,核心是监听单选按钮选中状态+用过渡动画实现平滑切换。
1. 布局设计:单选组+多内容CardView
把RadioGroup放在CardView上方,CardView内部嵌套多个不同的内容布局,初始只显示默认选项的内容:
<!-- activity_main.xml --> <RadioGroup android:id="@+id/reminderOptionGroup" android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal" android:layout_marginTop="16dp"> <RadioButton android:id="@+id/dateOption" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="日期提醒" android:checked="true"/> <RadioButton android:id="@+id/timeOption" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="时间提醒"/> <RadioButton android:id="@+id/locationOption" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="位置提醒"/> </RadioGroup> <androidx.cardview.widget.CardView android:id="@+id/reminderCard" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="16dp" app:cardCornerRadius="8dp"> <!-- 日期提醒内容 --> <LinearLayout android:id="@+id/dateLayout" android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical" android:padding="16dp"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="选择提醒日期"/> <DatePicker android:layout_width="match_parent" android:layout_height="wrap_content"/> </LinearLayout> <!-- 时间提醒内容 --> <LinearLayout android:id="@+id/timeLayout" android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical" android:padding="16dp" android:visibility="gone"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="选择提醒时间"/> <TimePicker android:layout_width="match_parent" android:layout_height="wrap_content"/> </LinearLayout> <!-- 位置提醒内容 --> <LinearLayout android:id="@+id/locationLayout" android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical" android:padding="16dp" android:visibility="gone"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="选择提醒位置"/> <EditText android:layout_width="match_parent" android:layout_height="wrap_content" android:hint="输入位置信息"/> </LinearLayout> </androidx.cardview.widget.CardView>
2. 实现单选切换+平滑动画
用TransitionManager.beginDelayedTransition()来触发内容切换的动画,同时处理不同布局的显示隐藏:
// MainActivity.kt class MainActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) val optionGroup = findViewById<RadioGroup>(R.id.reminderOptionGroup) val dateLayout = findViewById<LinearLayout>(R.id.dateLayout) val timeLayout = findViewById<LinearLayout>(R.id.timeLayout) val locationLayout = findViewById<LinearLayout>(R.id.locationLayout) val reminderCard = findViewById<CardView>(R.id.reminderCard) // 单选按钮切换逻辑+动画 optionGroup.setOnCheckedChangeListener { _, checkedId -> // 开启过渡动画,让内容切换更平滑 TransitionManager.beginDelayedTransition(reminderCard) // 先隐藏所有布局 dateLayout.visibility = View.GONE timeLayout.visibility = View.GONE locationLayout.visibility = View.GONE // 根据选中项显示对应布局 when(checkedId) { R.id.dateOption -> dateLayout.visibility = View.VISIBLE R.id.timeOption -> timeLayout.visibility = View.VISIBLE R.id.locationOption -> locationLayout.visibility = View.VISIBLE } } // 额外实现CardView的展开/收起动画(点击CardView触发) var isExpanded = true reminderCard.setOnClickListener { TransitionManager.beginDelayedTransition(reminderCard) isExpanded = !isExpanded reminderCard.layoutParams.height = if (isExpanded) { ViewGroup.LayoutParams.WRAP_CONTENT } else { // 收起到固定高度 100 } reminderCard.requestLayout() } } }
3. 进阶优化小技巧
- 如果内容布局比较复杂,建议用
ViewStub延迟加载,提升页面启动性能; - 可以自定义动画,比如用
ObjectAnimator组合高度变化、透明度变化的动画效果; - 记得在
onSaveInstanceState里保存当前选中的单选按钮ID,避免旋转屏幕后状态丢失。
内容的提问来源于stack exchange,提问作者Gaurav Ghongde
相关产品推荐
相关产品推荐

