11、自动亮度调节(下):手动实现简易自动亮度
上一章我们聊了光线传感器的监听机制。说白了,就是能拿到当前环境的光照值了。但拿到之后呢?
嗯,这才是关键。你得让屏幕亮度跟着动起来。
我刚开始做这个功能时,以为直接调系统亮度就完事了。结果发现,事情没那么简单。系统亮度设置和当前窗口亮度,其实是两回事。今天我们就来手动实现一个简易的自动亮度调节。
核心思路:监听 → 计算 → 设置
整个流程其实就三步:
- 监听光照值:通过 SensorEventListener 拿到 lux
- 计算目标亮度:把 lux 映射到 0~1 的亮度范围
- 设置窗口亮度:通过 WindowManager.LayoutParams 修改
说白了,就是一个简单的映射关系。光照强,屏幕亮;光照弱,屏幕暗。
关键点:我们修改的是当前窗口的亮度,不是系统全局亮度。这样不会影响其他应用,用户体验更好。
代码实现:简易自动亮度
先看核心代码。我习惯把逻辑封装成一个类,方便复用。
public class AutoBrightnessHelper {
private WindowManager.LayoutParams layoutParams;
private Activity activity;
private SensorManager sensorManager;
private Sensor lightSensor;
// 亮度映射范围
private static final float MIN_BRIGHTNESS = 0.1f;
private static final float MAX_BRIGHTNESS = 1.0f;
// 光照阈值(lux)
private static final float MIN_LUX = 10f;
private static final float MAX_LUX = 10000f;
public AutoBrightnessHelper(Activity activity) {
this.activity = activity;
this.layoutParams = activity.getWindow().getAttributes();
this.sensorManager = (SensorManager) activity.getSystemService(Context.SENSOR_SERVICE);
this.lightSensor = sensorManager.getDefaultSensor(Sensor.TYPE_LIGHT);
}
private final SensorEventListener lightListener = new SensorEventListener() {
@Override
public void onSensorChanged(SensorEvent event) {
float lux = event.values[0];
float brightness = mapLuxToBrightness(lux);
setWindowBrightness(brightness);
}
@Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {
// 一般不用处理
}
};
private float mapLuxToBrightness(float lux) {
// 限制范围
lux = Math.max(MIN_LUX, Math.min(lux, MAX_LUX));
// 线性映射到 0~1
float normalized = (lux - MIN_LUX) / (MAX_LUX - MIN_LUX);
// 映射到亮度范围
return MIN_BRIGHTNESS + normalized * (MAX_BRIGHTNESS - MIN_BRIGHTNESS);
}
private void setWindowBrightness(float brightness) {
layoutParams.screenBrightness = brightness;
activity.getWindow().setAttributes(layoutParams);
}
public void start() {
if (lightSensor != null) {
sensorManager.registerListener(lightListener, lightSensor, SensorManager.SENSOR_DELAY_NORMAL);
}
}
public void stop() {
sensorManager.unregisterListener(lightListener);
}
}
这段代码看着简单,但有几个坑。我一个个说。
避坑指南:我踩过的几个雷
坑一:亮度范围是 0~1,不是 0~255
我曾经直接传了个 128 进去,结果屏幕直接黑了。因为 screenBrightness 接受的是 float 类型,范围 0.0(最暗)到 1.0(最亮)。0.5 就是 50% 亮度。
坑二:别忘了在 onPause 里注销监听
如果不注销,Activity 退到后台后传感器还在跑。电量哗哗地掉。我有个项目上线后用户反馈耗电快,查了半天才发现是这个问题。
坑三:映射函数别太激进
有些同学喜欢用指数函数或分段函数,想让亮度变化更「自然」。但说实话,线性映射在大多数场景下已经够用了。过度设计反而容易出问题。
映射逻辑:光照值 → 亮度值
上面代码里的 mapLuxToBrightness 方法,其实就是一个简单的线性映射。我画了个图,方便你理解。
你看,横轴是光照值(lux),纵轴是亮度值(0~1)。当光照从 10 lux 增加到 10000 lux 时,亮度从 0.1 平滑上升到 1.0。
这个映射不是固定的。你可以根据实际场景调整。比如在暗光环境下希望更暗,就把 MIN_BRIGHTNESS 改成 0.05。我一般会在设置里留个滑块让用户自己调。
完整使用示例
在 Activity 里怎么用?很简单:
public class MainActivity extends AppCompatActivity {
private AutoBrightnessHelper brightnessHelper;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
brightnessHelper = new AutoBrightnessHelper(this);
}
@Override
protected void onResume() {
super.onResume();
brightnessHelper.start();
}
@Override
protected void onPause() {
super.onPause();
brightnessHelper.stop();
}
}
嗯,就这么几行。但有个细节要注意:start() 必须在 onResume 里调用,而不是 onCreate。因为 onResume 时窗口才真正可见,设置亮度才有效果。
进阶思考:为什么不用系统自动亮度?
你可能会问:系统不是自带自动亮度吗?为什么还要自己实现?
原因有几个:
- 系统自动亮度是全局的:你改了,所有应用都受影响。有时候用户只想在当前应用里用自动亮度。
- 系统响应慢:有些厂商的自动亮度有很长的延迟,体验不好。
- 自定义映射:你可以根据自己的需求设计亮度曲线。比如阅读类应用可以更暗,导航类应用可以更亮。
我记得有个做电子书阅读器的朋友,他们就把 MIN_BRIGHTNESS 设到了 0.02,配合夜间模式,用户体验特别好。
小结
手动实现自动亮度,核心就是三步:监听光照、映射计算、设置窗口亮度。代码量不大,但细节不少。
我建议你动手写一遍。先跑通基础功能,再慢慢调优映射曲线。遇到问题别慌,八成是亮度范围搞错了,或者忘了注销监听。
好了,这一章就到这里。下一章我们聊聊更高级的玩法——如何让亮度变化更平滑,而不是突然跳变。