You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android相机应用自定义SeekBar实现对焦值调节方案咨询

Android相机应用实现原生风格对焦调节SeekBar指南

一、自定义SeekBar样式(匹配原生视觉)

原生相机的对焦SeekBar是窄条+圆形滑块,你需要自定义Drawable实现这个效果:

  1. 新建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>
  1. 新建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>
  1. 布局中引用自定义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更稳定:

  1. 获取相机支持的对焦距离范围:
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))
  1. 实时设置对焦值的方法:
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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.25 20:55:26