Android相机应用自定义SeekBar实现对焦值调节方案咨询
Android相机应用实现原生风格对焦调节SeekBar指南
一、自定义SeekBar样式(匹配原生视觉)
原生相机的对焦SeekBar是窄条+圆形滑块,你需要自定义Drawable实现这个效果:
- 新建
progress_drawable.xml(进度条背景):
<layer-list xmlns:android="http://schemas.android.com/apk/res/android"> <item android:id="@android:id/background"> <shape android:shape="line"> <stroke android:width="2dp" android:color="#80FFFFFF"/> </shape> </item> <item android:id="@android:id/progress"> <clip> <shape android:shape="line"> <stroke android:width="2dp" android:color="#FFFFFF"/> </shape> </clip> </item> </layer-list>
- 新建
thumb_drawable.xml(圆形滑块):
<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="oval"> <solid android:color="#FFFFFF"/> <size android:width="16dp" android:height="16dp"/> <stroke android:width="2dp" android:color="#FF4081"/> </shape>
- 布局中引用自定义SeekBar:
<SeekBar android:id="@+id/focus_seekbar" android:layout_width="200dp" android:layout_height="wrap_content" android:progressDrawable="@drawable/progress_drawable" android:thumb="@drawable/thumb_drawable" android:visibility="gone" android:max="1000"/> <!-- 用大数值保证调节精度 -->
二、相机对焦核心逻辑(以CameraX为例,API21+推荐)
CameraX是Google官方推荐的相机框架,比旧Camera API更稳定:
- 获取相机支持的对焦距离范围:
val cameraProviderFuture = ProcessCameraProvider.getInstance(context) cameraProviderFuture.addListener({ val cameraProvider = cameraProviderFuture.get() val cameraSelector = CameraSelector.DEFAULT_BACK_CAMERA val cameraInfo = cameraProvider.getCameraInfo(cameraSelector) // 获取最小对焦距离(0.0f代表无限远,数值越大对焦距离越近) val minFocusDistance = cameraInfo.getCameraCharacteristics() .get(CameraCharacteristics.LENS_INFO_MINIMUM_FOCUS_DISTANCE) ?: 0.1f }, ContextCompat.getMainExecutor(context))
- 实时设置对焦值的方法:
private fun setFocusDistance(distanceRatio: Float) { // 转换为相机实际对焦距离,ratio为0时是无限远,1时是最近对焦 val actualDistance = minFocusDistance * distanceRatio val focusMeteringAction = FocusMeteringAction.Builder( SurfaceOrientedMeteringPointFactory(previewView.width.toFloat(), previewView.height.toFloat()) .createPoint(previewView.width/2f, previewView.height/2f), // 对焦中心 1.0f ).setAutoCancelDuration(0, TimeUnit.MILLISECONDS) .setFocusDistance(actualDistance) .build() camera.cameraControl.startFocusAndMetering(focusMeteringAction) }
三、SeekBar与相机联动(流畅滑动处理)
重点做防抖处理,避免滑动时频繁调用相机API导致卡顿:
private var focusHandler = Handler(Looper.getMainLooper()) private var focusRunnable: Runnable? = null focus_seekbar.setOnSeekBarChangeListener(object : SeekBar.OnSeekBarChangeListener { override fun onProgressChanged(seekBar: SeekBar?, progress: Int, fromUser: Boolean) { if (!fromUser) return // 防抖:滑动时每50ms才更新一次对焦 focusRunnable?.let { focusHandler.removeCallbacks(it) } focusRunnable = Runnable { val ratio = progress / seekBar!!.max.toFloat() setFocusDistance(ratio) } focusHandler.postDelayed(focusRunnable!!, 50) } override fun onStartTrackingTouch(seekBar: SeekBar?) { focus_seekbar.visibility = View.VISIBLE } override fun onStopTrackingTouch(seekBar: SeekBar?) { // 滑动结束后精准设置一次对焦 val ratio = seekBar!!.progress / seekBar.max.toFloat() setFocusDistance(ratio) // 延迟隐藏SeekBar,和原生逻辑一致 focusHandler.postDelayed({ focus_seekbar.visibility = View.GONE }, 2000) } })
四、额外优化点
- 仅在用户点击预览区域时唤起SeekBar,匹配原生相机交互逻辑;
- 若适配API20及以下旧设备,可通过
Camera.Parameters.setFocusDistance(float)实现,需先调用getParameters()修改参数再通过setParameters()提交; - 不同设备对焦范围存在差异,需根据
CameraCharacteristics动态调整SeekBar的精度范围。
内容的提问来源于stack exchange,提问作者Akshar Kalathiya
相关产品推荐
相关产品推荐

