☰
把jbox2d物理引擎搬进Android:MeiWidgetView膜拜单车贴纸控件全流程实录
2026/10/8 7:21:56 网站建设 项目流程

把jbox2d物理引擎搬进Android:MeiWidgetView膜拜单车贴纸控件全流程实录

【免费下载链接】MeiWidgetView🔥一款汇总了郭霖,鸿洋,以及自己平时收集的自定义控件集合库(小红书)项目地址: https://gitcode.com/gh_mirrors/me/MeiWidgetView

在 Android 自定义控件圈子里,MeiWidgetView 是一个把郭霖、鸿洋以及作者日常收集的炫酷控件汇总在一起的开源控件库。今天这篇文章聚焦其中一个「物理味」最浓的控件——仿摩拜单车贴纸动画控件(MoBikeView):屏幕上的贴纸像被真实重力拉扯一样翻滚、碰撞、堆叠,摇一摇手机还会「抖」得四处飞散。它背后的核心,是著名的 2D 物理引擎jbox2d。本文将带你完整走一遍「引擎接入 → 控件封装 → 传感器联动」的全流程,新手也能照着做出来。

💡 为什么用 jbox2d?自己写重力、碰撞、旋转动画需要大量数学计算,而 jbox2d 用成熟的刚体动力学帮你「算好了一切」,你只负责把 View 映射到虚拟物理世界里。

一、先看效果与实现原理

想象一堆贴纸撒在桌面上:每一张贴纸都是一个「刚体」,世界有向下的重力(Vec2(0, 10.0f)),四周是四面静止的「墙」(上下左右四个STATIC刚体),贴纸落到墙和彼此之间会发生碰撞、反弹和摩擦。手机加速传感器一旦有变化,就对所有刚体施加一个「冲量」(Linear Impulse),贴纸瞬间获得速度,四散弹飞——这就是摇一摇贴纸的完整原理。

核心类只有两个,分工非常清晰:

文件职责
MoBikeView.java自定义 View 外壳,继承FrameLayout,把生命周期事件转发给物理引擎
MoBike.java物理世界本体:建世界、造刚体、每帧步进、同步 View 位置

其中MoBikeView非常薄,只做了三件事:onSizeChanged记录宽高、onLayout触发建世界、onDraw里驱动world.step()并回写每个子 View 的坐标和角度。

上图就是项目中可用于「贴纸」演示的素材图片(ic_gril.png)——任何你想参与物理模拟的图片,都可以作为贴纸丢进 MoBikeView。

二、引擎接入:一个 jar 搞定

jbox2d 是一个纯 Java 库,接入零配置:

  1. 引擎本体已经随仓库内置在 widget/libs/jbox2d-library-2.3.1-SNAPSHOT.jar;
  2. widget/build.gradle 里用fileTree(dir: 'libs', include: ['*.jar'])一行自动引入,无需任何 Maven 坐标;
  3. 想单独使用这个控件,也可以直接按 README.md 中的方式把整个 widget 模块作为依赖引入。

✅ 对新手最友好的一点:jbox2d 不依赖 Android API,理论上任何 JVM 环境(游戏、Unity、服务端模拟)都能跑同一套物理逻辑。

三、全流程拆解:四步把 View 变成物理刚体

1️⃣ 建立虚拟世界 + 四面围墙

MoBike.createWorld()里先new World(new Vec2(0, 10.0f))设定向下重力,再用updateTopAndBottomBounds()和updateLeftAndRightBounds()在四边创建STATIC类型的多边形刚体当「墙」。注意代码里有个关键比例参数proportion = 50,配合两个换算函数:

  • mappingView2Body(view):像素 → 物理单位(除以 50)
  • mappingBody2View(body):物理单位 → 像素(乘以 50)

这是「像素世界」和「米制物理世界」之间的桥梁,几乎每个 jbox2d 接入项目都需要这一步。

2️⃣ 把子 View 转换成动态刚体

createWorldChild()遍历MoBikeView的每个子 View,调用createBody():

  • 用 View 的中心点(x + width/2, y + height/2,换算后)作为刚体初始位置;
  • 读取 View 的tag(ids.xml 中定义的wd_view_circle_tag)判断形状:true则建CircleShape(圆形),否则建PolygonShape(矩形盒);
  • 统一设置density(0.5)、friction(0.3 摩擦)、restitution(0.3 弹性恢复);
  • 把创建好的Body对象存回 View 的 tag(wd_view_body_tag),并给每个刚体一个随机初速度。

这种「tag 传参 + tag 回收」的方式,让控件不需要你传任何配置对象——想放什么贴纸,直接addView即可。

3️⃣ 每帧步进:物理世界驱动 UI

onDraw()是整个动画的心脏:

world.step(dt, velocityIterations, countIterations); // 60fps 步进 // 遍历子View,把刚体的位置/角度换算回像素后写回 view.setX(getViewX(view)); view.setY(getViewY(view)); view.setRotation(getViewRotation(view)); mViewGroup.invalidate(); // 直接invalidate,post会导致抖动

角度换算细节值得记一笔:body.getAngle()返回弧度,代码里用angle / 3.14f * 180f % 360转成 View 认识的旋转角度。另外注释里特别提示「不要用post触发刷新,否则延迟绘制会导致画面抖动」——这是实战踩坑经验。

4️⃣ 摇一摇:传感器施加冲量

演示页 MeiMoBikeActivity.java 注册了加速度传感器:

// onSensorChanged 中 mMobikeView.onSensorChanged(-event.values[0], event.values[1] * 2.0f);

最终落到MoBike.applyLinearImpulse(),对每个刚体执行body.applyLinearImpulse(vec2, body.getPosition(), true)——「冲量」会让速度瞬间改变,而不是持续施力,所以贴纸是「弹飞」而不是「被拖着走」。另外布局中给MoBikeView绑了点击监听,onRandomChanged()会给所有贴纸随机冲量,模拟器上没有传感器也能玩。

四、动手实战:在你的项目里复现

完整演示页只有几十行,流程如下:

① 布局:参考 mei_mobike_activity.xml,在ConstraintLayout里放一个Toolbar+ 铺满剩余区域的MoBikeView:

<com.meis.widget.mobike.MoBikeView android:id="@+id/mo_bike" android:layout_width="0dp" android:layout_height="0dp" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintTop_toBottomOf="@+id/toolbar" />

② 代码里动态添加贴纸(每张图就是一个刚体):

for (int i = 0; i < mImgs.length; i++) { ImageView iv = new ImageView(this); iv.setImageResource(mImgs[i]); iv.setTag(R.id.wd_view_circle_tag, true); // 标记为圆形刚体 mMobikeView.addView(iv, lp); }

③ 绑定点击:mMobikeView.setOnClickListener(...)里调用onRandomChanged(),点击屏幕即可「乱甩贴纸」。

到这里,一个可交互的摩拜贴纸页就完成了。想换成你的品牌 logo、活动贴纸、表情包,只需要替换setImageResource的图片资源——圆形用circle_tag,方形不带 tag,形状自动识别。

五、进阶玩法与避坑清单

想调整的效果改哪里
重力大小(下落快慢)MoBike.createWorld()中的new Vec2(0, 10.0f)
贴纸弹性/摩擦类顶部的frictionRatio、restitutionRatio
物理世界密度density字段(0.5)
像素↔物理换算proportion = 50,越大物体「看起来越轻飘」
冲量强度(摇一摇力度)onSensorChanged中的倍率(演示里 y 轴 ×2)

⚠️ 三个常见坑:

  1. 忘记 tag:子 View 没被createBody处理,会静止悬浮在空中——确认你的 View 已被加入MoBikeView且布局完成后会触发onLayout;
  2. 用post刷新:会导致物理步进和绘制不同步、画面抖动,坚持在onDraw里直接invalidate();
  3. 圆形刚体用宽高的一半当半径:createCircleBody取的是height/2,方形图建议放进正方形容器再参与模拟。

六、写在最后

MeiWidgetView 这个控件库的价值,正在于把「炫酷效果」拆成了可读、可抄、可改的源码。MoBikeView 作为其中 jbox2d 的样板实现,展示了物理引擎接入 Android 的完整套路:内置 jar → View 与刚体双向映射 → onDraw 步进 → 传感器/点击加冲量。把这个套路学会,你不仅能复刻摩拜贴纸,还能做出弹球、积木堆叠、重力九宫格等一整套物理 UI 效果。

📚 延伸阅读(仓库内其他物理/动画控件):

  • 弹跳小球(简化版物理模式):BounceBallView.java
  • 直播间点赞(贝塞尔曲线):BezierPraiseView.java
  • 浮动粒子(三阶贝塞尔轨迹):FireflyView.java

【免费下载链接】MeiWidgetView🔥一款汇总了郭霖,鸿洋,以及自己平时收集的自定义控件集合库(小红书)项目地址: https://gitcode.com/gh_mirrors/me/MeiWidgetView

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

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询