news 2026/10/15 2:32:01

views-widgets-samples 之 CardView 实战:在 Android 5.0 支持库中用圆角与阴影构建卡片布局

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
views-widgets-samples 之 CardView 实战:在 Android 5.0 支持库中用圆角与阴影构建卡片布局
  • 示例工程

【免费下载链接】views-widgets-samples

Multiple samples showing the best practices in views-widgets on Android.

项目地址:https://gitcode.com/gh_mirrors/vi/views-widgets-samples
点击查看免费下载

CardView 是 Android 5.0(API 21)时期随 support library 引入的卡片式容器控件,为内容提供统一风格的圆角矩形背景与投影阴影。本文以 views-widgets-samples 仓库中的 CardView 示例 为骨架,结合其 Java/Kotlin 双版本源码与仪器测试,系统讲解 CardView 的布局写法、cardCornerRadius与elevation两大核心属性的作用原理、交互式调节与测试验证方法,帮助你直接落地到自己的 Android 项目中。

示例概览:演示什么、怎么组织

CardView 示例的定位非常明确:演示 support library 中随 Android 5.0 引入的android.support.v7.widget.CardView控件的基本用法。该声明同时出现在 CardView/README.md 与 base-strings.xml 的应用描述中。

从工程结构上看,仓库为该示例提供了两个独立可导入的工程目录:

  • Java 版(默认示例):位于 CardView/,主代码在 CardView/Application/src/main/java/com/example/android/cardview/ 下;
  • Kotlin 版:位于 CardViewKotlin/,主代码在 CardViewKotlin/Application/src/main/java/com/example/android/cardview/ 下。

两个版本的界面与交互完全一致,差异仅在语言与测试框架选型上:

维度Java 版(CardView)Kotlin 版(CardViewKotlin)
主界面入口CardViewActivity.javaCardViewActivity.kt
卡片逻辑承载CardViewFragment.javaCardViewFragment.kt
布局文件fragment_card_view.xmlfragment_card_view.xml
测试用例SampleTests.java(继承ActivityInstrumentationTestCase2)SampleTests.kt(JUnit4 +ActivityTestRule+AndroidJUnit4)
前置 SDK 要求Android SDK 28 + Build Tools v28.0.3Android SDK 27

示例运行后呈现一个可交互的演示页:页面中央是一张蓝色圆角卡片,卡片下方依次是Radius(圆角半径)与Elevation(高度/阴影)两个 SeekBar,拖动滑块即可实时观察卡片外观变化。这种"一个控件 + 两个属性调节条"的极简设计,恰好覆盖了 CardView 区别于普通容器的全部核心特性。

搭建环境:前置条件与构建方式

README 明确了构建本示例的三项前置条件:

  • Android SDK 28
  • Android Build Tools v28.0.3
  • Android Support Repository(提供android.support.v7.widget.CardView所在的 support 库)

其中 Gradle Wrapper 版本为 6.7.1,配置见 CardView/gradle/wrapper/gradle-wrapper.properties;Kotlin 版对应要求 SDK 27。若使用本示例开发环境时的 SDK 版本与上述不完全一致,可在 Android Studio 的 SDK Manager 中安装对应版本,或自行调整工程的 build 配置。

构建方式 README 给出了两条等价路径,任选其一即可:

  1. 命令行构建:在工程根目录(即CardView/或CardViewKotlin/,注意 Kotlin 版需使用其自带的 gradlew)执行:

    ./gradlew build

    该命令会依次执行编译、打包与测试任务。首次运行会由 Gradle Wrapper 自动下载 6.7.1 发行版并拉取依赖,耗时取决于网络状况。

  2. Android Studio 导入:使用File → Import Project(或 Open)选中工程根目录,由 IDE 基于 settings.gradle(内容为include 'Application')识别Application模块并完成同步后,即可直接 Run 到模拟器或真机。

工程采用单模块结构:Application是唯一的 app 模块,其入口CardViewActivity已在 AndroidManifest.xml 中声明为带MAIN/LAUNCHERintent-filter 的启动 Activity。

界面骨架:Activity 承载 Fragment,布局定义卡片

整个示例采用 "Activity + 单 Fragment" 的经典组织方式。

CardViewActivity.java 中,onCreate只做两件事:设置activity_card_view布局,并在savedInstanceState == null时(即首次创建,避免旋转重建后重复添加)向R.id.container容器提交CardViewFragment.newInstance():

@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_card_view); if (savedInstanceState == null) { getFragmentManager().beginTransaction() .add(R.id.container, CardViewFragment.newInstance()) .commit(); } }

容器布局 activity_card_view.xml 只是一个带四边 16dp 内边距的FrameLayout(边距值定义在 dimens.xml 的activity_horizontal_margin/activity_vertical_margin)。

真正的卡片界面在 fragment_card_view.xml 中:外层是ScrollView,内部为垂直LinearLayout,依次包含一个 CardView 与两个"标签 + SeekBar"水平行。Kotlin 版 fragment_card_view.xml 结构相同,差异仅在把硬编码的100dp圆角半径/高度抽成了 card_elevation 与 card_radius 尺寸资源。

核心:CardView 布局写法与两大关键属性

CardView 的声明方式与普通 ViewGroup 无异,关键在于它独有的两个属性。示例中的完整声明如下(摘自 fragment_card_view.xml):

<android.support.v7.widget.CardView android:id="@+id/cardview" android:layout_width="fill_parent" android:layout_height="wrap_content" android:elevation="100dp" card_view:cardBackgroundColor="@color/cardview_initial_background" card_view:cardCornerRadius="8dp" android:layout_marginLeft="@dimen/margin_large" android:layout_marginRight="@dimen/margin_large" > <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_margin="@dimen/margin_medium" android:text="@string/cardview_contents" /> </android.support.v7.widget.CardView>

两个注意点需要特别说明:

  • 自定义属性命名空间:cardCornerRadius、cardBackgroundColor属于 CardView 自定义属性,必须使用http://schemas.android.com/apk/res-auto命名空间(即card_view:前缀,见布局根元素的xmlns:card_view声明),而不是android:前缀;
  • android:elevation使用系统命名空间:阴影高度即 Android 5.0 引入的 Material Design 海拔(elevation)概念,因此走系统属性通道。

下面逐一拆解 CardView 的属性与作用原理。

cardCornerRadius:圆角半径

card_view:cardCornerRadius控制卡片四角的圆角弧度,示例初始值为8dp。这个值直接影响背景绘制的Path圆角矩形形状,同时也决定了内容裁剪的边界。

在示例的交互逻辑中,CardViewFragment.java 为 Radius SeekBar 注册了监听器,滑块每次变化都调用mCardView.setRadius(progress),progress 取值为 SeekBar 的进度值(0 到滑块上限,单位实际被当作 dp 的浮点值使用):

mRadiusSeekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() { @Override public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { Log.d(TAG, String.format("SeekBar Radius progress : %d", progress)); mCardView.setRadius(progress); } ... });

对应 Kotlin 版则使用属性语法cardView.radius = progress.toFloat()(见 CardViewFragment.kt)。特别提醒:示例中setRadius(progress)传入的是整型 progress,实际以 dp 语义参与绘制——这一点从布局中cardCornerRadius="8dp"的初始值和 SeekBar 交互可见;在自己的项目中应使用setRadius(dp2px(...))之类的 dp→px 换算,或直接使用cardCornerRadius的 dp 资源,以免在不同密度屏幕上出现偏差。

elevation:阴影高度(海拔)

android:elevation是 Material Design 中通过 Z 轴海拔产生投影的核心属性:海拔越高,卡片下方投影越深、越柔和、范围越大。示例布局中给出了一个演示性的较大初始值100dp,CardViewFragment.java 中对应的 Elevation SeekBar 监听器则调用mCardView.setElevation(progress):

mElevationSeekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() { @Override public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { Log.d(TAG, String.format("SeekBar Elevation progress : %d", progress)); mCardView.setElevation(progress); } ... });

Kotlin 版对应cardView.elevation = progress.toFloat()。

这里有一个值得展开的原理性细节:CardView 是少数同时打通了"绘制阴影"与"硬件渲染"的 support 库控件。从源码结构看,CardView 在 Lollipop 及以上系统通过 elevation 使用原生阴影渲染,在低版本系统则回退到自绘阴影实现;它的setElevation方法(即示例调用的入口)会同步更新背景层与阴影层,setRadius则会重算背景RoundRectDrawable的形状,并联动裁剪内容。示例通过两个 SeekBar 让你直观地看到:圆角只影响卡片外形,阴影随 elevation 变化——二者是独立可调的两个维度。

cardBackgroundColor:卡片背景色

card_view:cardBackgroundColor设置卡片背景色。示例通过 colors.xml 定义了初始背景色cardview_initial_background = #71C3DE(浅蓝色),使圆角与投影效果在演示中一目了然。若不设置,CardView 会使用主题默认的背景色。

交互与验证:测试用例如何锁死行为

CardView 示例的一个亮点在于:它把"SeekBar 调节圆角/高度"这一交互写成了可自动验证的仪器测试,这既是示例质量的保证,也是理解setRadius/setElevation语义的绝佳教材。

Java 版 SampleTests.java 继承自ActivityInstrumentationTestCase2<CardViewActivity>,共三个用例:

  1. testPreconditions:断言 Activity、Fragment 以及两个 SeekBar 均已正确创建(依赖mRadiusSeekBar、mElevationSeekBar字段,因此源码中为它们标注了@VisibleForTesting);
  2. testRadiusSeekbarChangesRadiusOfCardView:在主线程中把 Radius SeekBar 进度设为 50,随后断言mCardView.getRadius()等于 50.0f——证明滑块变化确实写入了 CardView 的圆角值;
  3. testElevationSeekbarChangesElevationOfCardView:同理把 Elevation SeekBar 设为 40,断言getElevation()返回 40.0f——证明高度属性随滑块联动。
public void testRadiusSeekbarChangesRadiusOfCardView() { getInstrumentation().runOnMainSync(new Runnable() { @Override public void run() { float radius = 50.0f; mFragment.mRadiusSeekBar.setProgress((int) radius); assertEquals(radius, mFragment.mCardView.getRadius()); } }); }

由于getRadius()返回的是 px 值,而进度值以 dp 语义传入,因此在默认密度(mdpi,1dp = 1px)设备上二者直接相等。该测试也侧面印证了前文"progress 以 dp 语义参与绘制"的推断。

Kotlin 版 SampleTests.kt 则升级为 JUnit4 风格:@RunWith(AndroidJUnit4::class)+ActivityTestRule,测试逻辑与 Java 版一一对应。两套测试放在一起阅读,正好可以对照学习 Instrumentation 测试从ActivityInstrumentationTestCase2到ActivityTestRule的演进写法。

主题与资源组织:让卡片融入 App 视觉体系

示例还展示了如何让 CardView 与应用的 Material 主题协同。看 template-styles.xml 与 values-v21/base-template-styles.xml:默认(低版本)下Theme.Base继承android:Theme.Light,而在 API 21+ 的values-v21限定目录下则改为继承android:Theme.Material.Light。也就是说,示例在 Android 5.0 及以上设备上使用真正的 Material 主题,在低版本设备上退化为兼容主题——这与 CardView 本身"新系统原生渲染、旧系统兼容渲染"的设计哲学是一致的。

资源的组织也值得借鉴:字符串(卡片说明文案、两个 SeekBar 的标签)集中在 strings.xml(含cardview_contents中对android:elevation与card_view:cardCornerRadius用法的说明性文本),尺寸集中在 dimens.xml,颜色集中在 colors.xml,主题样式则通过values-sw600dp、values-v11、values-v21等限定目录按屏幕与版本差异化提供。

迁移到 AndroidX 与 Material 时代的实战建议

最后给出一条面向现代工程实践的衔接建议(基于仓库事实的延伸解读):本示例发布于 Android 5.0 + support library 时代,使用的是android.support.v7.widget.CardView。如今 Android 工程普遍迁移到 AndroidX,对应类是androidx.cardview.widget.CardView,核心属性与 API 一一对应(cardCornerRadius、cardBackgroundColor、elevation、setRadius()、setElevation()),因此本示例中的布局写法与交互逻辑几乎可以无痛平移;若追求更现代的 Material 风格卡片,可进一步参考 Material Components 的MaterialCardView(支持描边、按压态、选中态等增强能力)。需要说明的是,这些扩展能力不在本仓库范围内,迁移时请以目标依赖库的官方文档为准。

小结

围绕 CardView/README.md 这份仅数百字节的示例说明,结合仓库中的双版本实现,可以提炼出 CardView 的完整知识闭环:

  • 是什么:Android 5.0 引入、由 support library 提供的卡片容器,自带圆角与投影;
  • 怎么配:card_view:cardCornerRadius控制圆角、android:elevation控制阴影、card_view:cardBackgroundColor控制背景,自定义属性必须走res-auto命名空间;
  • 怎么验证:参考 SampleTests.java / SampleTests.kt 的仪器测试写法,用 SeekBar 驱动setRadius/setElevation并断言getRadius/getElevation的返回值。

对希望在列表、详情页或信息流中快速获得统一卡片视觉的开发者而言,CardView 至今仍是最低成本的方案之一;而这份示例的价值在于,它把"圆角 + 阴影"两个抽象概念变成了可拖动、可测试、可对照源码的具体工程。

  • 示例工程

【免费下载链接】views-widgets-samples

Multiple samples showing the best practices in views-widgets on Android.

项目地址:https://gitcode.com/gh_mirrors/vi/views-widgets-samples
点击查看免费下载

相关推荐

上一篇:X. 论文标题 ![](https://img.shields.io/badge/2024-CVPR-green)
下一篇:终极指南:co异步控制流库的核心函数与参数详解

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/15 2:31:09

科研idea的生成逻辑与落地转化路径解析

外文文献“白嫖”与高效阅读全攻略 宝子们&#xff0c;是不是一提到下载外文文献就头大&#xff1f; 想找的文献要么全网搜不到&#xff0c;要么下载流程复杂到让人原地爆炸。好不容易在某个小网站找到了资源&#xff0c;又担心版权问题不敢点&#xff0c;更别说有些平台动辄几…

作者头像 李华
网站建设 2026/10/15 2:30:58

OLED12864多平台驱动适配:SPI/I²C时序、显存布局与硬件避坑指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/15 2:30:07

AnyPS5:存储扩容、数据备份、画质调优与散热维护全攻略

“AnyPS5”这个词&#xff0c;最开始只是我备忘录里的一个文件夹名。朋友买了新主机后总问我三件事&#xff1a;还能装多少游戏、画面是不是设置错了、风扇为什么越来越响。问的人多了&#xff0c;我发现不管哪一款机型&#xff0c;大家折腾的路径几乎一模一样。于是我把这些反…

作者头像 李华
网站建设 2026/10/15 2:28:58

Fluent中泡沫金属相变储能热非平衡仿真:模型设置与参数标定

带泡沫金属的相变储能仿真&#xff0c;在Fluent里到底怎么做热非平衡&#xff1f;这问题我前前后后折腾了小半年&#xff0c;期间换了三套思路、踩了无数坑&#xff0c;才终于把模型跑稳、结果跑准。今天把整个过程中积累的东西完整写出来&#xff0c;包括热平衡方程和热非平衡…

作者头像 李华
网站建设 2026/10/15 2:27:51

RISC-V裸机NAS实战:OpenSBI引导+C++17异步运行时

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/15 2:27:33

Nacos配置中心落地实践:从动态刷新原理到微服务配置管理避坑指南

服务一多起来&#xff0c;配置文件就成灾了。改个数据库密码要通知五六个人&#xff0c;改完还得挨个重启&#xff0c;运气不好一个下午就搭进去了。我最初关注 Nacos &#xff0c;就是奔着配置中心去的&#xff0c;Spring Cloud Alibaba 全家桶里它承担了注册中心和配置中心两…

作者头像 李华