奇怪的负1

-1赋给一个无符号整型变量的值会是多少呢?

我的第一感觉告诉我如果赋给32位无符号整型变量应该是1 + 30个0 + 1;16位的无符号整数应该是1 + 14个0 + 1;

事实胜于雄辩测试下看看。

真是不看不知道,一看吓一跳;32位的结果是4294967295(也就是2^32 - 1)。

既然错了就分析分析原因,我先看看代码的运行情况(vc6中调试)。

第一点: - 1 在运行时表示为:0FFh (赋值给8位的整型变量) //突然想起以前学习过的补码、反码。

第二点: -1赋值给无符号变量时使用movesx

 

原来这样!可以大胆的猜测-1赋值给整型无符号变量的值如下:

位数(无符号数)     值

16                         2^16 - 1

8                           2^8 - 1

 

测试一下:

  unsigned char it8 = -1;
  unsigned short it16 = -1;
  unsigned int it32 = -1;
  printf("it8 is: %u/n", it8);
  printf("it16 is: %u/n", it16);
  printf("it32 is: %u/n", it32);

打印结果是:

it8 is: 255
it16 is: 65535
it32 is: 4294967295

 

从结果看推论是正确的,在此也谢谢某位大哥。

感谢你继续反馈! > ❗“改了以后动画范围更奇怪了” 这说明:**动画启动了,但坐标系错乱了** → 光带方向、起始位置不对。 我们来一步步 **排查 shimmer 动画“范围奇怪”的根本原因**,这是典型的 **坐标系不统一 + 位置偏移计算错误** 导致的视觉错乱。 --- ## 🔍 常见导致“动画范围奇怪”的 5 大原因 | 原因 | 现象 | 如何判断 | |------|------|---------| | 1️⃣ `setBounds(l, t, r, b)` 计算错误 | 光带偏移、缩放异常、位置漂移 | 打印 `l`, `t` 是否为或过大 | | 2️⃣ 使用 `getLocationInWindow()` vs `getLocationOnScreen()` 混用 | 不同设备偏移不同,尤其有状态栏时 | 在有刘海屏/底部导航的手机上更明显 | | 3️⃣ shader 的坐标系与 view 的本地坐标系不匹配 | 光带动起来像“跳跃”或“断层” | 虽然动画在跑,但扫过区域不对 | | 4️⃣ `globalWidth/globalHeight` 取的是 targetView 尺寸,但实际布局更大/更小 | 光带太窄 or 太宽 | 对比 layout inspector 实际尺寸 | | 5️⃣ 角度变换未基于中心点,而是左上角 | 斜向光带偏离预期路径 | 设置角度为 45° 时,光带应从左上到右下 | --- ## ✅ 正确做法:确保所有坐标都相对于 **targetView 左上角** 我们要做到: > 🎯 所有子 view 的 shimmer 绘制,其 shader 坐标 = 相对于 `targetView` 的偏移 ### ✅ 正确获取相对位置的方法 ```kotlin val childLocation = IntArray(2).also { view.getLocationOnScreen(it) } val parentLocation = IntArray(2).also { targetView.getLocationOnScreen(it) } val left = childLocation[0] - parentLocation[0] val top = childLocation[1] - parentLocation[1] val right = left + view.width val bottom = top + view.height setBounds(left, top, right, bottom) ``` 📌 关键:使用 `getLocationOnScreen()` 并做差值,得到 **相对于父容器的位置** --- ### ✅ 示例:修复后的 `createShimmerDrawable` ```kotlin private fun createShimmerDrawable(view: View): Drawable { val cornerRadius = config.cornerRadius.coerceAtLeast(0f) // ✅ 每个 drawable 拥有自己的 paint val localPaint = Paint().apply { isAntiAlias = true style = Paint.Style.FILL } return object : Drawable() { override fun draw(canvas: Canvas) { if (bounds.isEmpty || currentShader == null) return localPaint.shader = currentShader if (cornerRadius > 0f) { val rectF = RectF(bounds) val path = Path().apply { addRoundRect(rectF, cornerRadius, cornerRadius, Path.Direction.CW) } canvas.save() canvas.clipPath(path) canvas.drawRect(bounds, localPaint) canvas.restore() } else { canvas.drawRect(bounds, localPaint) } } override fun setAlpha(alpha: Int) {} override fun setColorFilter(colorFilter: ColorFilter?) {} override fun getOpacity(): Int = PixelFormat.TRANSLUCENT }.apply { // ✅ 正确计算相对于 targetView 的坐标 val childLoc = IntArray(2) val parentLoc = IntArray(2) view.getLocationOnScreen(childLoc) targetView.getLocationOnScreen(parentLoc) val l = childLoc[0] - parentLoc[0] val t = childLoc[1] - parentLoc[1] val r = l + view.width val b = t + view.height Log.d("Shimmer", "Set bounds: [$l,$t - $r,$b] for ${view.javaClass.simpleName}") setBounds(l, t, r, b) } } ``` --- ## ✅ 验证步骤:加日志确认坐标正确性 在 `updateGlobalShader` 中也打印一下: ```kotlin private fun updateGlobalShader(offsetFraction: Float) { Log.d("Shimmer", "Updating shader with fraction=$offsetFraction, size=[$globalWidth x $globalHeight]") if (globalWidth <= 0f || globalHeight <= 0f) return val bandWidth = globalWidth * config.shimmerWidth val angleRad = Math.toRadians(config.shimmerAngle.toDouble()) val cos = Math.cos(angleRad).toFloat() val sin = Math.sin(angleRad).toFloat() val diagonal = sqrt((globalWidth * globalWidth + globalHeight * globalHeight).toDouble()).toFloat() val offset = offsetFraction * diagonal val startX = -diagonal * cos + offset val startY = -diagonal * sin + offset val endX = startX + bandWidth * cos val endY = startY + bandWidth * sin Log.d("Shimmer", "Shader: ($startX,$startY) → ($endX,$endY), angle=$config.shimmerAngle") currentShader = LinearGradient( startX, startY, endX, endY, intArrayOf(Color.TRANSPARENT, config.shimmerColor, Color.TRANSPARENT), floatArrayOf(0f, 0.5f, 1f), Shader.TileMode.CLAMP ) } ``` 📌 如果你看到: - `startX` 变化平滑(从到正) - `fraction` 从 -1 → 2 正常循环 - `bounds` 是合理的正数且对齐 UI → 那么 shader 和坐标都没问题! --- ## ✅ 常见“奇怪现象”及解决方案 | 现象 | 可能原因 | 解法 | |------|--------|------| | 光带只出现在某个角落 | `setBounds` 错误,l/t 为或超界 | 检查 getLocationOnScreen 差值 | | 光带横向移动而非斜向 | `shimmerAngle` 没生效 | 确保 `cos/sin` 是根据 `angleRad` 计算的 | | 光带一闪而过 | `bandWidth` 太小 or `diagonal` 计算错误 | 打印 `bandWidth = globalWidth * config.shimmerWidth`,确认不是 0 | | 圆角处光带断裂 | clipPath 裁剪后绘制顺序问题 | 加 `canvas.save()/restore()` | | 多个 view 光带错位 | shader 坐标系没对齐到 parent | 必须使用 relative bounds | --- ## ✅ 最终建议:可视化调试技巧 你可以临时把 `shimmerColor` 改成半透明红色: ```kotlin config.shimmerColor = Color.parseColor("#88FF0000") // 半透红 ``` 然后观察: - 光带是否真的从左上角开始? - 是否覆盖整个 parent 区域? - 子 view 是否正好是“窗口”? 👉 这样一眼就能看出偏移是否正确。 --- ## ✅ 总结:你现在“动画范围奇怪”的最大可能 > ⚠️ **`setBounds` 的坐标不是相对于 `targetView`,而是绝对屏幕坐标 or 错误偏移** 🔧 **解决方法:** ✅ 使用 `getLocationOnScreen()` 获取父子位置,做差值得出相对坐标! ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值