05 · preference 封装层与 Settings 使用地图
本篇回答:①组件库的三个滑块 Preference 各是什么;②为什么 MiCarSettings 一个都没用; ③Settings 侧到底谁在用哪个组件。
1. 组件库三个 Preference 封装
| 类 | 绑定 widget | 特征 |
|---|---|---|
SeekBarPreference(PREF/SeekBarPreference.java,AOSP 移植) | 框架 android.widget.SeekBar(:64,布局裸 <SeekBar>) | 完整持久化 + callChangeListener 闸门 + DPAD(:108-133);mUpdatesContinuously 控制拖动中是否落盘(:81) |
SliderPreference(PREF/ext/preferenceItem/SliderPreference.java) | IconSlider(:28,布局 micar_appcompat_preference_widget_slider_material.xml) | 有缺口,见 §2 |
SeekBarPreferenceCompat(PREF/ext/preferenceItem/SeekBarPreferenceCompat.java) | IconSeekBar(:76-77 强转) | 保留 SeekBarPreference 全套逻辑,仅换 widget |
SeekBarPreference 的值流(基类语义)
onSetInitialValue: getPersistedInt 恢复(:204-209)
用户拖动: fromUser && (mUpdatesContinuously || !mTrackingTouch) 才连续持久化(:81)
拖动中只刷 label(:85),onStopTrackingTouch 值变了才落盘(:95-100)
setValueInternal: clamp [mMin,mMax](:353-359) → persistInt(:364)
syncValueInternal: callChangeListener 闸门(:397),被拒则回滚 widget(:400)
min/max 映射: SeekBar max = mMax−mMin(:187),progress = value−min(:198)
2. ⚠️ 组件库版 SliderPreference 的半移植缺口
PREF/ext/preferenceItem/SliderPreference.java:
onSetInitialValue读getPersistedInt恢复(:160-165)——会恢复;setValueInternal(:238-255)从不调用 persistInt——不落盘;- 也不过 callChangeListener 闸门,监听器(:44-52)直接 setValueInternal + 回调自有
OnProgressChangedListener.onProgressChanged(float)(:333-339); - thumb 文本用
(int) sliderValue截断(:249/:155,非四舍五入)。
结论:只恢复不落盘,疑似半移植 bug(未确认是否有意)。2023-11-18 随 “Preference new UI”(3d9a1023)新建后未再改。
3. SeekBarPreferenceCompat 的口径不一致坑
syncValueInternal(:141-151)回调的是裸 seekBar.getProgress()(不含 mMin 偏移,:144),
而 updateLabelValue 收到的是含 min 的值——回调口径与显示口径不一致。min≠0 的调用方
会拿到小一个 min 的回调值。
4. 为什么 Settings 不用组件库封装
MiCarSettings 全仓 grep micarx.preference.* 零命中。 Settings 用自建体系:
flowchart TD SP["settingsBaseUi<br/>common.SliderPreference(1109 行)<br/>extends RichTitlePreference :73"] subgraph Widgets["widget 包装(均 implements IFusionSlider)"] W1["MiCarSlider<br/>extends material Slider"] W2["MiCarIconSlider<br/>extends micarx IconSlider"] W3["MiCarIconSeekBar<br/>extends micarx IconSeekBar"] end SP -->|R.id.carui_slider :618| Widgets Sub["miauto.preferences.MiCarIconSeekBarPreference<br/>extends common.SliderPreference :42"] Sub --> SP
- Settings 版多出:可见即可说(ViewDescriptionCompat)、埋点(TrackEvent)、action button、 防抖、取整机制(mProgressChangeTimes/alignAdjustProgress,能量回收 KB 02 篇)。
- 两版分叉史:组件库版 2023-11-18 出现于 micarx(3d9a1023)后未动;Settings 版 2024-02-27 随”车控代码抽离”(a66a979a6)出现并持续演进。同名两套实现,git 无共同 历史,改哪边都不影响另一边。
app/src/main/res/values/themes.xml:77把seekBarPreferenceStyle重指到 Settings 自有Preference.CarUi.SeekBarPreference.Auto。
5. Settings 侧使用地图(按子模块)
| settingsPage 子模块 | 使用点 | 组件 |
|---|---|---|
| micarChargeSettings | EnergyCurrentController.kt;xml miauto_energy_manager_fragment | common.SliderPreference+MiCarIconSeekBar;XML 用 MiCarIconSeekBarPreference |
| micarDisplaySettings | RearTvScreenAngleIconSliderController.kt;xml miauto_display_atmosphere_settings_fragment | MiCarIconSeekBar;MiCarIconSeekBarPreference |
| micarDrivingSettings | AccelerateParam/BrakingStrength/VehicleAudioMotionWaveVolume/BaseCustomVehicleProgress/CustomEnergyRecoveryStrength;布局 micar_ui_pref_traction_ratio_seek_bar | common.SliderPreference/MiCarIconSeekBar;布局里 MiCarIconSlider |
| micarLightSettings | KeyBgLightLevelPrefController、AtmosphereLightBrightnessProgressPrefController | common.SliderPreference |
| micarLockSettings | HeadGateHeight/TailGateHeightPrefController;RoofSunShadeSliderPreference;布局 lock_seekbar_with_two_btns | MiCarIconSeekBar;RoofSunShadeSliderPreference extends common.SliderPreference;布局里 MiCarSlider |
| micarSafetyServiceSettings | ownermode/views/SpeedLimitSliderView.kt(限速滑块,N801PROB-144519) | MiCarIconSlider(直封,不走 SliderPreference 族) |
| micarVolume | ReduceEnvironmentalNoiseSliderController、BaseVolume/InCarIntercomVolume | MiCarIconSeekBar/common.SliderPreference |
| settingsAutoPilot | MiCarAutoPilotFixSpd/OverSpdOffsetPrefController;MiCarHeightLimitSeekBarPreference | common.SliderPreference+MiCarIconSeekBar;布局里 MiCarIconSlider |
| micarMedia | VideoPlayerActivity.kt + exo_player_control_view.xml:91 | 直接用 material Slider(播放进度) |
教训(N801PROB-144519):排查取整滑块要 grep 机制名(mProgressChangeTimes/
alignAdjustProgress)不能只 grep 配置名——SpeedLimitSliderView 是”直封 MiCarIconSlider”
的平行实现,不走 SliderPreference 族,修能量回收时漏网了它。
6. catalog 官方示例(用法组合参考)
catalog/.../seekbar/SeekBarActivity.java + activity_seek_bar.xml 四类同屏:
- micarx
AppCompatSeekBar(含ignoreClick=true变体,xml :41/:58); IconSeekBar:按压动画开关、hint CENTER/BELOW、拖动中 setThumbText(:26-37);- material
Slider:OnChangeListener 回显、touch listener、setIgnoreClick/setPressEnlarge/ setCornersEnable(:68-122),Widget.MiCar.Slider.SliderEnlargeStyle(xml :181-183); IconSlider:按压动画、hint 位置、enable、ignoreClick(:58-104)。
VerticalSliderActivity.java:setValues(60f)、enable/ignoreClick、%.3f 回显、
setStepSize(10) 离散演示(:22-44)。