thickness 控制圆环粗细,innerradius 控制空心部分大小,但xml中同时设置时innerradius被忽略,仅thickness生效;需手动计算并只设thickness,且显式指定uselevel="false"。

innerRadius 和 thickness 到底谁决定圆环粗细?
直接说结论:thickness 控制圆环的“线宽”,innerRadius 控制空心部分大小,二者共同决定外径(outerRadius = innerRadius + thickness)。但 XML 中不能同时设 innerRadius 和 thickness —— Android 会忽略 innerRadius,只认 thickness(当 type="ring" 时)。
常见错误现象:innerRadius 写了没反应、圆环始终很粗或直接变成实心圆。
- 只设
android:innerRadius:无效,系统按默认thickness渲染(通常约 5dp) - 只设
android:thickness:生效,圆环粗细由它决定 - 两个都设:
innerRadius被静默丢弃,以thickness为准 - 想精确控制外径?得手动算:
outerRadius = innerRadius + thickness,然后只设thickness,再用android:useLevel="false"(避免被当作 level-list 误读)
ring 在不同 API 版本下的尺寸兼容性问题
android:innerRadius 和 android:thickness 自 API 1 起就存在,但行为在 API 21+ 有隐性变化:高版本更严格校验单位,且对 0dp 值更敏感。若圆环不显示,先检查是否用了无单位数字(如 innerRadius="10")。
- 必须带单位:
android:innerRadius="10dp"或android:thickness="2sp"(虽然sp不推荐用于尺寸,但语法合法) - API 21+ 若设
android:thickness="0dp",可能渲染为不可见(不是崩溃,是“画了个零粗细的圈”) - 低于 API 21 时,
android:useLevel默认为true,会导致 ring 被当进度条处理——务必显式设android:useLevel="false"
实际项目中怎么安全设置一个 24dp 外径、8dp 粗细的圆环?
目标外径 24dp、粗细 8dp → 内半径应为 16dp,但别写 innerRadius。直接按公式反推:thickness = 8dp,再通过 android:width 和 android:height 控制整体容器大小(因为 ring 自身不撑开布局)。
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="ring"
android:useLevel="false"
android:thickness="8dp">
<solid android:color="#FF6200EE" />
</shape>
- 把该 drawable 用在
ImageView时,ImageView的layout_width/layout_height至少设为24dp,否则会被裁剪 - 若用在背景(如
View.background),需确保 View 本身尺寸 ≥ 外径,否则只显示局部 - 别依赖
innerRadius做响应式设计——它不可靠;改用代码动态生成GradientDrawable更可控
为什么用 shape ring 做 loading 动画经常变形?
因为 shape 是静态绘制,没有帧控能力。所谓“旋转动画”其实是给整个 View 加 RotateAnimation 或 ObjectAnimator,而 ring 的尺寸一旦在 XML 里写死,缩放/旋转中心默认是 View 左上角,不是圆心。
- 解决办法:把 ring 放进
layer-list,用android:gravity="center"居中;或者直接用ProgressBar+ 自定义indeterminateDrawable - 更稳的选择:改用
AnimatedVectorDrawable配合路径动画,完全避开 shape 尺寸陷阱 - 性能提示:大量使用
shape ring作背景(尤其嵌套 RecyclerView item)会触发频繁重绘,厚度值越大越耗 GPU
真正难的不是设对那两个属性,而是意识到:XML shape 的 ring 是个“哑巴图形”,它不响应尺寸变化、不参与测量逻辑、也不懂你想要的圆心对齐——所有这些,都得靠外层容器和动画逻辑兜底。










