如何将带单选按钮的CardView作为对话框弹出并实现背景模糊效果
自定义CardView排序对话框实现指南
需求实现目标
- 将包含2个互斥单选按钮的自定义CardView布局作为对话框展示
- 对话框弹出时,底层的HomeFragment布局添加模糊效果
- 用户选中任意单选按钮后,延迟500ms再关闭对话框,保证用户能看到选中状态反馈
用到的布局文件
sort_image.xml(自定义对话框布局)
<com.google.android.material.card.MaterialCardView xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_width="300dp" android:layout_height="200dp" android:layout_gravity="center" android:backgroundTint="@color/grey" app:cardCornerRadius="20dp"> <RelativeLayout android:layout_width="match_parent" android:layout_height="match_parent"> <TextView android:id="@+id/sort_textView" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentTop="true" android:layout_centerInParent="true" android:layout_marginTop="5dp" android:fontFamily="@font/roboto" android:text="Sort by" android:textAlignment="center" android:textColor="@color/lite_grey" android:textSize="25sp" /> <com.google.android.material.card.MaterialCardView android:id="@+id/divider_line_sort_by" android:layout_width="match_parent" android:layout_height="1dp" android:layout_below="@id/sort_textView" android:layout_marginStart="10dp" android:layout_marginTop="5dp" android:layout_marginEnd="10dp" android:backgroundTint="@color/lite_grey" app:cardCornerRadius="50dp" /> <RelativeLayout android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerInParent="true"> <TextView android:id="@+id/latest_sort_textView" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginStart="30dp" android:layout_marginTop="30dp" android:fontFamily="@font/roboto" android:text="Latest" android:textAlignment="center" android:textColor="@color/lite_grey" android:textSize="25sp" /> <TextView android:id="@+id/most_popular_sort_textView" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_below="@+id/latest_sort_textView" android:layout_alignParentStart="true" android:layout_centerInParent="true" android:layout_marginStart="30dp" android:layout_marginTop="25sp" android:fontFamily="@font/roboto" android:text="Most Popular" android:textAlignment="center" android:textColor="@color/lite_grey" android:textSize="25sp" /> <RadioGroup android:id="@+id/sort_radio_group" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentEnd="true"> <RadioButton android:id="@+id/latest_sort_radio_button" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="25sp" /> <RadioButton android:id="@+id/most_popular_sort_radio_button" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="10dp" /> </RadioGroup> </RelativeLayout> </RelativeLayout> </com.google.android.material.card.MaterialCardView>
fragment_home.xml(触发弹窗的底层布局,仅核心代码)
注:仅提供该布局的核心代码
<com.google.android.material.card.MaterialCardView android:id="@+id/sort" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerInParent="true" android:layout_marginEnd="5dp" android:layout_marginBottom="5dp" android:layout_toStartOf="@id/divider_line" android:backgroundTint="@color/black" android:elevation="6dp" android:paddingBottom="10dp" android:textAlignment="center" app:cardCornerRadius="10dp"> <TextView android:id="@+id/sort_text" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginStart="8dp" android:layout_marginEnd="8dp" android:layout_marginBottom="5dp" android:fontFamily="@font/roboto" android:text="@string/sort" android:textAlignment="center" android:textColor="@color/white" android:textSize="17sp" android:textStyle="bold" /> </com.google.android.material.card.MaterialCardView>
功能实现代码
首先在res/values/styles.xml中添加透明对话框样式,避免默认对话框背景遮挡自定义布局:
<style name="TransparentDialog" parent="Theme.MaterialComponents.Dialog"> <item name="android:windowBackground">@android:color/transparent</item> <item name="android:windowNoTitle">true</item> <item name="android:windowIsFloating">true</item> </style>
然后在HomeFragment中添加如下逻辑:
import android.app.Dialog; import android.os.Handler; import android.os.Looper; import android.view.View; import android.widget.RadioGroup; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.fragment.app.Fragment; public class HomeFragment extends Fragment { // 底层根布局,用于添加模糊效果 private View rootView; // 触发弹窗的排序卡片按钮 private MaterialCardView sortCard; // 对话框关闭延迟时间,单位ms,可自行调整 private static final long DISMISS_DELAY = 500; @Nullable @Override public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { rootView = inflater.inflate(R.layout.fragment_home, container, false); sortCard = rootView.findViewById(R.id.sort); // 排序按钮点击弹出对话框 sortCard.setOnClickListener(v -> showSortDialog()); return rootView; } private void showSortDialog() { Dialog sortDialog = new Dialog(requireContext(), R.style.TransparentDialog); sortDialog.setContentView(R.layout.sort_image); sortDialog.setCanceledOnTouchOutside(true); // 给底层布局添加模糊效果(Android 12+ 可用系统RenderEffect,低版本可引入BlurView等第三方库实现) if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.S) { rootView.setRenderEffect(android.graphics.RenderEffect.createBlurEffect(25f, 25f, android.graphics.Shader.TileMode.CLAMP)); } // 对话框关闭时移除模糊效果 sortDialog.setOnDismissListener(dialog -> { if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.S) { rootView.setRenderEffect(null); } }); // 单选按钮选中监听 RadioGroup sortRadioGroup = sortDialog.findViewById(R.id.sort_radio_group); sortRadioGroup.setOnCheckedChangeListener((group, checkedId) -> { // 选中后延迟关闭,保证用户看到选中状态 new Handler(Looper.getMainLooper()).postDelayed(() -> { if (sortDialog.isShowing()) { sortDialog.dismiss(); } // 在这里添加选中后的业务逻辑 if (checkedId == R.id.latest_sort_radio_button) { // 按最新排序逻辑 } else if (checkedId == R.id.most_popular_sort_radio_button) { // 按最热门排序逻辑 } }, DISMISS_DELAY); }); sortDialog.show(); } }
补充说明
- 低版本Android模糊效果可以用RenderScript或者第三方Blur库实现,调用逻辑和上述代码一致,仅模糊方法不同
- 延迟时间推荐设置在300-800ms区间,兼顾用户感知和操作流畅度
内容的提问来源于stack exchange,提问作者Vasant Raval
相关产品推荐
相关产品推荐

