Android相机屏幕适配

Unity NGUI安卓全面屏顶部黑边问题:原理分析与三种实战解决方案 屏幕适配是移动应用开发中的基础课题,其核心在于确保应用内容在不同尺寸、比例的屏幕上都能正确显示。其原理涉及操作系统定义的安全区域(Safe Area)与渲染引擎的视口(Viewport)匹配。对于游戏开发而言,正确处理安全区能保障核心交互界面不被刘海、挖孔等异形屏遮挡,提升用户体验与产品专业度。在Unity引擎中,现代UGUI系统已内置安全区支持,但许多遗留项目仍在使用NGUI等传统UI框架。NGUI作为一套独立的UI系统,其默认的屏幕尺寸获取与相机投影逻辑并未考虑安全区,导致在全面屏设备上渲染区域无法覆盖 阅读详情

前言

本文默认你已经会的Android相机开发,但是苦恼于相机屏幕适配
如果不会相机开发,可以参考以下作者的文章:


现在出现了越来越多的屏幕,再也不是那个到处充满1920x1080的时代了,所以给身为手机开发者的我们带来了不少麻烦,从而给我们带来了相机屏幕适配这块的问题,大家都知道,在使用相机的时候,如果不对屏幕做适配,那么在预览的时候,界面就会拉伸,这对用户可不是个好体验。

普通解决方案

先说说普通解决方法,我们可以通过camera得到手机摄像头的参数,比如曝光度、照片尺寸、预览尺寸等等的很多信息。所以我们通过以下代码可以得知摄像头到底支持哪些预览分辨率:

// 相机所支持的分辨率
Camera.Parameters parameters = mCamera.getParameters();
List<Camera.Size> supportedPreviewSizes = parameters.getSupportedPreviewSizes();

然后我们还可以得到手机的分辨率是多少

// 手机分辨率
DisplayMetrics dm = context.getResources().getDisplayMetrics();
int w_screen = dm.widthPixels;
int h_screen = dm.heightPixels;
Point screenRelsolution = new Point(w_screen, h_screen);

所以,我们可以用已知的手机分辨率和相机所支持的预览分辨率做对比,找出合适的预览分辨率为相机做适配。

选择最佳分辨率可以参考yanzi1225627方案,也可以参考我的方案[笑]:

    /**
     * 选择最佳相机预览分辨率
     *
     * @param parameters 相机参数
     * @param point      手机分辨率 宽度:point.x,高度point.y
     * @return 最佳相机分辨率
     */
    public static Camera.Size getBestPreviewSize(Camera.Parameters parameters, Point point) {

        double x = point.x; //1080
        double y = point.y; //1920

        List<Camera.Size> supportedPreviewSizes = parameters.getSupportedPreviewSizes();

        List<Camera.Size> sameWidthList = new ArrayList<>();

        for (Camera.Size size : supportedPreviewSizes) {

            if (x == size.height) {
                sameWidthList.add(size);
            }

        }

        int index = -1;

        int min = -1;

        for (int i = 0; i < sameWidthList.size(); i++) {

            Camera.Size s = sameWidthList.get(i);

            int abs = Math.abs(s.width - point.y);

            if (min == -1) {
                min = abs;
            }

            if (abs <= min) {
                min = abs;
                index = i;
            }

        }

        return sameWidthList.get(index);

    }

然后把最佳支持的分辨率设置给相机就行了

mParams.setPreviewSize(bestPreviewSize.width, bestPreviewSize.height);

终极适配方案

使用普通适配方案,其实仔细想想,还是会存在一些问题,比如相机支持的预览分辨率里面,可能支持的分辨率里面没有跟手机分辨率相同,所以还是会导致预览的时候界面被拉伸,那么要怎样才能做到完美贴合般的适配呢,先说说思路

假设手机分辨率为1770*1080,但是相机预览分辨率为1920*1080,也就是这个surfaceview为1920*1080,所以可能是这些样子:
这里写图片描述
其中红色框为手机分辨率,绿色框为相机预览分辨率,如果把这样SurfaceView放置到手机屏幕中(绿框填充红框),界面肯定会被拉长吧,还有可能会是如下情况:
这里写图片描述
这样界面肯定就被收窄了(绿框填充红框
所以还是要适配一波,不过这个适配,主要目的是为了在预览的时候,让预览图不变形。那么我们就先来说说原理吧。

原理
由于相机预览分辨率中,没有跟手机一样的分辨率,所以,我们的点在于修改手机的界面,让界面妥协。

比如手机的分辨率为1000*2000,而相机预览分辨率为1000*3000,那么我们就要将界面的布局设置为1000*3000,这样一来,在预览的时候,就不会出现界面拉伸的现象了。

如果手机分辨率是1000*1000,而预览分辨率为500*700,我们就要将手机界面的长宽比例设置跟预览分辨率比例一样的,设置为5:7,这里要提一点的就是,不能将手机的界面大小设置为500*700,因为手机分辨率为1000*1000,如果只展示500*700的界面,虽然预览图像是正常了,没有拉伸现象了,但是会出现白边。

所以我们应该将手机的界面大小设置为1000*1400,这样一来,手机整个界面就都是预览界面了。

既然知道了原理解决起来就很容易了。

实现

实现步骤:

  1. 得到Camera对象,得到Camera.Parameters对象
  2. 得到相机支持的分辨率,在没有跟手机分辨率相同的情况下,选择最大预览分辨率
  3. 修改界面大小,将界面比例跟预览分辨率比例设置相同
  4. 开启预览

可以使用接口回调的方式,在得到相机预览分辨率的时候,将预览分辨率回调给Activity,然后修改界面大小即可。

所以现在我们获取最佳分辨率的方法应该如下:

    /**
     * 选择最佳相机预览分辨率
     *
     * @param parameters 相机参数
     * @param point      手机分辨率 宽度:point.x,高度point.y
     * @return 最佳相机分辨率
     */
    public static Camera.Size getBestPreviewSize(Camera.Parameters parameters, Point point) {

        List<Camera.Size> list = parameters.getSupportedPreviewSizes();

        int max = 0;
        int index = -1;

        for (int i = 0; i < list.size(); i++) {
            int height = list.get(i).height;
            int width = list.get(i).width;

            // 当手机分辨率和预览分辨率相同的时候,直接返回该预览分辨率
            // 否则选择最大分辨率
            if (point.x == width && point.y == height) {
                return list.get(index);
            }

            Log.e(TAG, "getBestPreviewSize: 相机分辨率 = " + height + " x " + width);

            int i1 = height * width;
            if (i1 > max) {
                max = i1;
                index = i;
            }
        }
        return list.get(index);

    }

获取手机分辨率的方法:

public static Point getScreenMetrics(Context context) {
        DisplayMetrics dm = context.getResources().getDisplayMetrics();
        int w_screen = dm.widthPixels;
        int h_screen = dm.heightPixels;
        return new Point(w_screen, h_screen);
}

然后我们可以拟定一个接口,当得到最佳预览分辨率的时候,将该分辨率告知给Activity:

public interface CamStartPreviewCallback{
    void postPreview(int width, int height);
}

所以告知给Activity的主要方式应该就是:(省略了无数代码)

public void startPreview(SurfaceHolder holder, CamStartPreviewCallback callback) {
    ...
    mParams = mCamera.getParameters();
    Camera.Size bestPreviewSize = getBestPreviewSize(mParams, point);
    callback.postPreview(bestPreviewSize.width, bestPreviewSize.height); 
    ...       
}

postPreview()的具体实现如下:

@Override
public void postPreview(int width, int height) {

    cameraSurfaceView.post(new Runnable() {
            @Override
            public void run() {

                Point screenMetrics = getScreenMetrics(context);

                Log.e(TAG, "run: 手机分辨率 = " + screenMetrics.x + " x " + screenMetrics.y);
                Log.e(TAG, "run: 相机预览分辨率 = " + width + " x " + height);

                ViewGroup.LayoutParams layoutParams1 = root.getLayoutParams();
                ViewGroup.LayoutParams layoutParams2 = cameraSurfaceView.getLayoutParams();

                int fixWidth = 1080;
                int fixHeight = 1920;

                float screenRate = screenMetrics.y * 1.0f / screenMetrics.x;
                float previewRate = width * 1.0f / height;

                Log.e(TAG, "run: screenRate = " + screenRate);
                Log.e(TAG, "run: previewRate = " + previewRate);

                if (screenRate > previewRate) {
                    fixWidth = screenMetrics.y * screenMetrics.x / width;
                    fixHeight = screenMetrics.y;
                } else if (screenRate < previewRate) {
                    fixWidth = screenMetrics.x;
                    fixHeight = (int) (screenMetrics.x * previewRate);
                } else if (screenRate == previewRate) {
                    fixWidth = height;
                    fixHeight = width;
                }

                layoutParams1.width = fixWidth;
                layoutParams1.height = fixHeight;
                root.setLayoutParams(layoutParams1);

                layoutParams2.width = fixWidth;
                layoutParams2.height = fixHeight;
                cameraSurfaceView.setLayoutParams(layoutParams2);

            }
        });

}

说明一下里面的root跟cameraSurfaceView是啥,root就是根布局,而cameraSurfaceView自然就是相机预览界面的surfaceview了
布局界面如下:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/root"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <SurfaceView
            android:id="@+id/cameraSurfaceView"
            android:layout_width="match_parent"
            android:layout_height="match_parent" />

    </RelativeLayout>

</RelativeLayout>

这样一来,我们的相机屏幕适配就完毕了。

结语

其实根据以上内容,大家也看得出来,其实我们在做相机屏幕适配的时候,并不是那种完美的适配,而是由于相机的预览分辨率无法修改,手机界面布局大小做了修改而已,其实这只是手机布局界面的妥协。谁让你不能变呢,那我变就行了呗!

我整理了一下代码,供大家参考
源码:https://github.com/qixuefeng/CameraAdaptDemo

Hypermesh联合ABAQUS—Sets的建立编辑 打开part copy对话框在对话框的最上面位置可以输入copy后的名称,然后将最下面的Separate disconnected regions into parts(将不连续的区域分割成parts)选项的前面方框勾选上。打开abaqus软件界面,File→import→model,将file filter选为inp格式,找到要导入的有限元文件,单击OK导入文件。HyperWorks新建Set时,会在Model Browser显示,打开Create Set对话框显示详细信息。快捷键,高亮set的内容。 阅读详情

相关推荐

项目篇:移动平台机械臂视觉定位抓取实施(基于ROS架构)

ROS包内容: 这篇日志的目的是快速项目实施,所以详细的部分会不断补充。 1、相机采集包(创建抓取图像服务,单张) Realsense Camera(微软深度摄像头,官方提供ros包) Pylon Camera(basler相机,官方提供ros包) 2、定位算法包(抓取图像,定位标志物) Aruco_ros (二维码定位,官方提供ros包) Apriltag (二维码定位,官方提供ros包)...

南北粉面馆 6012

Android SurfaceView预览变形完美解决方法

本篇文章主要介绍了Android SurfaceView预览变形完美解决方法,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧

支持多设备前置摄像头Android二维码扫描Demo源码

在当今多屏时代,屏幕适配技术是移动应用开发的关键。开发者必须确保应用在不同尺寸分辨率屏幕上都能提供最佳用户体验。为此,我们需了解如何处理屏幕方向的变化、屏幕旋转机制,并掌握横竖屏切换的实现原理。相机硬件通常由多个关键组件组成,包括镜头、传感器、图像处理单元以及内存等。其中,镜头负责聚焦进光;传感器负责将光线转化为电信号;图像处理单元则负责将电信号进一步处理成可存储展示的图像数据;最后,内存则用于存储这些图像数据。这些组件协同工作,使得相机能够捕获处理高质量的图像。

weixin_42465332的博客 1134

在安卓中结合使用GLSurfaceViewCanvas使用_笔记_可能有错

续:https://blog.csdn.net/cjzjolly/article/details/81667087 《使用GLSurfaceView实现涂鸦画板功能》 在上文中实现的OpenGL画线效果比较粗糙,但Canvas做绘制线条这方面的比较好用而且方便;但是Canvas移动图形实在是太慢了,所以我试着把两者结合起来使用——Canvas做线条绘制,当需要缩放移动画面时,使用Ope...

轮子初级玩家 2915

android opengl 缩放图片,android – 用于不同DPI的OpenGL表面视图缩放

我有一个800×480 res的设备.当我创建GLSurfaceView时,我得到一个onSurfaceChanged调用533×320(显然应用了1.5 HDPI修改器)并且表面被放大了.所以当我绘制1像素粗线看起来真的很糟糕,我不能有像素完美的渲染.我想要的是原始分辨率表面(800×480).在Activity的onCreate中以这种方式创建视图(如在NDK OpenGL示例中):this....

weixin_34521351的博客 422

Android Camera 自动适配多种屏幕,解决预览照片拉伸保存的图片拉伸

最近公司需要做一个手机自拍照的功能,由于之前有做过类似手机拍照的功能,所以很快就实现了自定义手机拍的功能。但是后面发现部分手机出现预览照片拉伸保存的图片拉伸的情况。然后百度了一下,发现原理很好理解,也有一堆demo,然而并没有解决拉伸的情况。下面总结一下我的解决方法,希望对你有用。 一、原理 我们首先来理解主要的三个大小: 1、SurfaceView的大小,屏幕上显示摄像头拍摄的图像的vi...

sziitjin的博客 7018

android Camera与SurfaceView联合使用时出现图片被拉伸解决方案

相机预览被拉伸处理

qq_41620230的博客 1014

Android AR 高级教程(一)

增强现实是移动计算领域相对较新的发展。尽管它还很年轻,但它已经是这个行业中发展最快的领域之一。公司正在投入大量资金开发使用增强现实的产品,其中最引人注目的是谷歌的谷歌眼镜项目。大多数人认为增强现实很难实现。那是一种误解。像任何好的应用一样,好的增强现实应用需要花费一些精力来编写。你所需要做的就是在潜水前保持开放的心态。这就结束了我们对 AR 的当前未来使用及其在 Android 平台上的实现(或可能的实现)的观察。下一章着眼于在 Android 上创建 AR 应用的基础。

龙哥盟 1956

android 获取短信路径,Android获取系统启动器、电话、短信相机包名

private ResolveInfo res;private Intent infoIntent;//获取启动器包名infoIntent = new Intent(Intent.ACTION_MAIN);infoIntent.addCategory(Intent.CATEGORY_HOME);res = getPackageManager().resolveActivity(infoIntent...

weixin_36033417的博客 286

android相机横屏竖屏,GitHub - qixuefeng/CameraAdapt: Android相机屏幕适配

CameraAdaptDemoAndroid相机屏幕适配该项目主要是为了做相机下的屏幕适配具体思路可以参见我的这篇文章Android 相机屏幕适配测试:机型:华为荣耀8 (厂商:honor,型号:FRD-AL00)相机支持的预览分辨率:1080 x 19201080 x 1440864 x 1536960 x 1280720 x 1280720 x 960720 x 720480 x 640414...

weixin_34711401的博客 606

安卓Camera屏幕竖屏适配

一、为什么要进行适配 1.前言 说起为什么要对屏幕进行适配,主要还是由于安卓系统的开放性。一说到安卓的开放性,我们就不能不讲起安卓系统的发展史。当初安卓系统的诞生之日,这个市场还是诺基亚的天下。也许连当年“安卓之父”安迪·鲁宾先生都不会预料到现在的安卓会是多么的辉煌。据悉,当年安卓的开发团队开发了一段时间安卓后,也许是由于市场的原因他们并不对安卓充满希望。他们在2005年找到了当时韩国的通讯巨头三...

Damon的博客 3313

Android 自定义相机获取照片(屏幕适配

1.在应用程序中自定义相机拍照的大体步骤如下:       1.检测访问相机:检测设备是否支持拍照,然后发出访问设备相机请求。        2.创建一个预览类:创建一个继承自类SurfaceView实现接口SurfaceHolder接口的相机预览类,这个类用来预览从相机得到的实时的图片.。        3.新建一个预览布局:一旦创建了相机预览类,还需要创建一个可以包含预览界面且可以操

wangjiang 6006

项目必备第三方框架

链接:https://www.jianshu.com/p/65a984de4017。商业转载请联系作者获得授权,非商业转载请注明出处。4.【AgentWeb webView封装使用】5.【AndroidUtilCode 工具类】2.【支持uniapp开发的IM——腾讯IM】1.【可以设置位置、颜色的斜着的文字标签】3.【RxBus 消息传递】10.【超简单的组件动画】2.【换肤、UI、工具】11.【超牛的日历控件】8.【Xpopu弹窗】3.【底部可拖动抽屉】4.【仿微信位置选择】

chuyouyinghe的专栏 355

android开发常用工具类、高仿客户、附近厕所、验证码助手、相机图片处理等源码...

Android精选源码 android开发过程经常要用的工具类源码 Android类似QQ空间个人主页下拉头部放大的布局效果 Android高仿煎蛋客户Android完整项目 android帮你找到附近厕所app源码 一款集成了相机,图片裁剪,给图片贴贴图打标签的APP andr...

chuangzhi9350的博客 210

android 学习开发整体问题大全

一个快速开发的mvvm轻量级架构(jetpcak+dagger + 协程)

Master-D的博客 634

拥有百万粉丝的大牛讲述学Android的历程,全网独家首发!

开头 Android开发,假如开始没有任何的开发经验的话, 千万不要着急,不要想着在短时间内就把一个语言学习好, 因为你之前没有任何的学习经验, 在这个过程中需要有耐心地学习完JAVA的基础知识, 然后才开始踏上Android开发之旅。 若之前做过JAVA开发经验的,这类同学可以在Android上迅速上手,但是同样的是不可忽略Android的一些基础知识,只有把基础掌握好了,才能在后期取得大的进步。 1.ListView 中图片错位的问题是如何产生的? 2.混合开发有了解吗? 3.知道哪些混合开发的方式?

天真爱器 100

Opencv 摄像头二次开发,横竖屏切换,前后摄像头切换,铺满全屏问题,一次解决(附源码)

Android Opencv 4.2 摄像头二次开发之 横竖屏切换,前后摄像头切换,铺满全屏问题,一次解决 问题1.横竖屏切换崩溃问题 描述: 主要是原生的Opencv demo中没有解决这样的问题,横竖屏切换会导致屏幕不能铺满或者直接崩溃问题。 崩溃原因: 主要是org.opencv.android.CameraBridgeViewBase#mCacheBitmap 这个mCacheBitmap 大小Opencv 得到的CvCameraViewFrame 宽度高度不一样,导致在 org.opencv

Sand哥的博客 1587

android camera 横竖屏 问题

做 多媒体 相关应用时,会出现 屏幕显示 的 实际 图像不对应的关系,解决方法见代码, 不过 这个方法 只能解决 拍照问题,用 MediaRecord 摄像 横屏的问题解决不了(android 摄像头是旋转 90度后安装的) @SuppressLint("NewApi") public  void setCameraDisplayOrientation(Activity activity,

unknown712000的专栏 1610

android视频采集

视频画面的采集主要是使用各个平台提供的摄像头API来实现的, 在为摄像头设置了合适的参数之后,将摄像头实时采集的视频帧渲染到 屏幕上提供给用户预览,然后将该视频帧编码到一个视频文件中,其使 用的编码格式一般是H264。当然,最终我们还要配上音频,否则没有 音频文件的视频就成了早期的默片电影了。 本节将主要学习如何在AndroidiOS平台上利用各自平台提供的摄 像头API,采集出正确的视频帧并绘制到屏幕上,具体的编码将会在后 续进行讨论。 6.2.1 Android平台的视频

lucky的专栏 1435

android相机尺寸,Android相机的尺寸与屏幕尺寸不匹配

我已经编写了自己的相机活动,我在FrameLayout中展示了该照片的实时预览,但实况图像看起来并不自然,有点高,我认为它是因为FrameLayout的尺寸与相机尺寸不符。我应该怎么做才能解决它?Android相机的尺寸与屏幕尺寸不匹配这里是相机活动的xml文件:android:layout_width="fill_parent"android:layout_height="fill_paren...

weixin_32460203的博客 500

tvp var_tvp-var_tvpvar参考书籍_tvp模型_tvpvar代码_var_源码.zip

tvp var_tvp-var_tvpvar参考书籍_tvp模型_tvpvar代码_var_源码.zip

上一篇: Tinker关于clean后准基包消失的解决方案
下一篇: 如何撸一个ArrayList
你缺少想象力
博客等级 码龄11年 619粉丝 45原创
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值