Android TV Overscan

本文来自网易云社区

作者:孙有军

 

开发的TV应用发现在部分电视上可以显示完整,而其他部分电视显示不全,周围都会遮挡了。

 

原因

这是因为部分老的电视有一个overscan的概览,什么叫overscan呐?官方解释如下:

During the evolution of TV technology, overscan originally described an area of TV content outside of a safe zone that most TVs could reliably display. Even on some of today’s HDTV flat screens, areas outside that zone may not be visible.

整个展示的界面是外面整个矩形框,而可见区域是内部的矩形框,因此如果你布局的内容紧邻边界,就会导致部分电视不能完整显示整个内容。

 

解决方案

上面的问题,我们怎么解决呐?这里给出两种解决方案。

 

设置调整

虽然老的电视有overscan的概念,内容显示不全,但是电视可以设置他的显示内容距离电视边框的距离,这里主要依靠人为的手动设置,方式如下:

一般都是选择遥控板的设置,进入设置界面,选择显示,边距调整

经过上述方式的调整,可以设置内容与边框有一定的距离,这样可以让所有的内容都显示出来。

难点:该方式必须要用户手动调整,如果不调整则显示内容被遮挡体验效果比较差

 

UI调整

既然让大家都采用手动调整是比较困难的,那有没有从应用层面来解决该问题的方法,有,肯定有,官方的文档也给出了解决方案:

Build a 5% margin into your TV screen designs to account for overscan area the TV may not display correctly. On a 1920 x 1080 screen, this margin should be a minimum of 27 pixels from the top and bottom edges and a minimum of 48 pixels from the right and left edges of the picture.

上面的意思是,在设计界面的时候,就空出四周的overscan距离,以1920*1080为例上下27px,左右48px,让显示的内容完全处于安全区域,周围都是无关内容区域。

缺点:如果设计的内容需要靠近边界,比如说底部有一个导航条,可以显示与影藏,这种时候就需要贴近边界进行设计。如果再设计的时候空出一部分,那在overscan的电视上展示较好,无overscan的电视展示就比较差,如果不空,这效果相反

 

自适应?

既然上面的两种方案都是有缺点的

  • 全部让用户手动设置不显示

  • 空出部分内容,在有的时候会显示效果比较差

那有没有一种方法来解决上面面临的问题?能够根据电视状况自动缩放内容,在有overscan的电视上,拿到overscan的值,设置显示内容与边界为overscan的值,在没有overscan的电视上保持内容不调整。

 

方案探索

首先我们看代码,看看代码中是否有overscan的值,经过一番查找,在Android中有一个Display类,他包含了很多显示信息,其中有一个字段为DisplayInfo,DisplayInfo包含了其他的一些显示信息。其中有四个字段如下:

/*** Describes the characteristics of a particular logical display.* @hide*/public final class DisplayInfo implements Parcelable {....    /*** @hide* Number of overscan pixels on the left side of the display.*/public int overscanLeft;    /*** @hide* Number of overscan pixels on the top side of the display.*/public int overscanTop;    /*** @hide* Number of overscan pixels on the right side of the display.*/public int overscanRight;    /*** @hide* Number of overscan pixels on the bottom side of the display.*/public int overscanBottom;    public DisplayInfo() {}....
}

这里我们省略了其他的代码,可以看到包含有overscanLeft, overscanTop,overscanRight,overscanBottom,这就是Overscan的值,到这里感觉有希望。既然有这四个值,那我们获取到这四个值再设置会界面应该就能达到我们想要的效果。

 

读取overscan

从上面的代码中我们可以看到DisplayInfo是被hide掉的,四个值也是被hide掉的,说明从正常的先拿到Display,再拿到DisplayInfo,之后再获取四个值是不行的了,那我们反射来获取该值,代码如下:

public static Rect getOverScan() {    if (overScan == null) {overScan = new Rect();        try {WindowManager manager = (WindowManager) AppProfile.getContext().getSystemService(Context.WINDOW_SERVICE);Display display = manager.getDefaultDisplay();Class clazz = Display.class;Field mDisplayInfo = clazz.getDeclaredField("mDisplayInfo");mDisplayInfo.setAccessible(true);Object displayInfo = mDisplayInfo.get(display);Class displayInfoClazz = Class.forName("android.view.DisplayInfo");Field overscanLeft = displayInfoClazz.getDeclaredField("overscanLeft");overScan.left = overscanLeft.getInt(displayInfo);Field overscanTop = displayInfoClazz.getDeclaredField("overscanTop");overScan.top = overscanTop.getInt(displayInfo);Field overscanRight = displayInfoClazz.getDeclaredField("overscanRight");overScan.right = overscanRight.getInt(displayInfo);Field overscanBottom = displayInfoClazz.getDeclaredField("overscanBottom");overScan.bottom = overscanBottom.getInt(displayInfo);} catch (Exception e) {}}    return overScan;
}

首先获取到Display,之后在反射获取DisplayInfo,最后在读取四个值。

也可以直接反射获取Display下的getOverscanInsets函数, getOverscanInsets函数如下:

 /*** @hide* Return a rectangle defining the insets of the overscan region of the display.* Each field of the rectangle is the number of pixels the overscan area extends* into the display on that side.*/public void getOverscanInsets(Rect outRect) {synchronized (this) {updateDisplayInfoLocked();outRect.set(mDisplayInfo.overscanLeft, mDisplayInfo.overscanTop,mDisplayInfo.overscanRight, mDisplayInfo.overscanBottom);}
}

反射获取方式如下:

public static Rect getOverScan1() {Rect overScan = new Rect();    try {WindowManager manager = (WindowManager) AppProfile.getContext().getSystemService(Context.WINDOW_SERVICE);Display display = manager.getDefaultDisplay();Class clazz = Display.class;Method getOverscanInsets = clazz.getMethod("getOverscanInsets", Rect.class);getOverscanInsets.invoke(display, overScan);LogUtil.free(overScan.toString());} catch (Exception e) {}    return overScan;
}

我们采用上面方法在debug状态下读取了一下DisplayInfo的内容:

Display id 0: DisplayInfo{"内置屏幕", app 1280 x 720, real 1280 x 720, largest app 1280 x 1255, smallest app 720 x 695, 50.0 fps, rotation0, density 160 (160.0 x 160.0) dpi, layerStack 0, type BUILT_IN, FLAG_SECURE, FLAG_SUPPORTS_PROTECTED_BUFFERS}, DisplayMetrics{density=1.0, width=1280, height=720, scaledDensity=1.0, xdpi=160.0, ydpi=160.0}, isValid=true

反射后获取,发现并没有overscan的值,很遗憾四个值都是0。可是我测试的电视是有overscan的。代码写错了?

我采用命令来设置overscan的内容:

adb shell wm overscan  10,20,30,40

分别设置overscan的值为10, 20, 30, 40,之后我再一次获取DisplayInfo的值,内容如下:

Display id 0: DisplayInfo{"内置屏幕", app 1280 x 720, real 1280 x 720, overscan (10,20,30,40), largest app 1280 x 1255, smallest app 720 x 695, 50.0 fps, rotation0, density 160 (160.0 x 160.0) dpi, layerStack 0, type BUILT_IN, FLAG_SECURE, FLAG_SUPPORTS_PROTECTED_BUFFERS}, DisplayMetrics{density=1.0, width=1280, height=720, scaledDensity=1.0, xdpi=160.0, ydpi=160.0}, isValid=true

这里可以看到明确有overscan的内容,并且就是我们命令设置的值,这就尴尬了,系统默认值获取不到,手动设置可以获取。希望之路破灭。

 

总结

如果有人实现了自适应的方式,麻烦请告知一下。目前只能采取UI界面调整的方式来避免该问题。

 

网易云免费体验馆,0成本体验20+款云产品! 

 

更多网易研发、产品、运营经验分享请访问网易云社区

 

相关文章:
【推荐】 消息推送平台高可用实践(下)
【推荐】 【你离硅谷只差一步】网易中国创业家大赛项目火热征集中
【推荐】 解读滑块验证码(滑动验证码)与图形验证码的破解难度

转载于:https://www.cnblogs.com/163yun/p/9711834.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/570388.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

jsp页面中出现“String cannot be resolved to a type”

右键你的项目,Build Path–>Configure Build Path 按照步骤1–>2 –>3。 然后就大功告成了。

Druid学习之路 (四)Druid的数据采集格式

作者:Syn良子 出处:https://www.cnblogs.com/cssdongl/p/9715735.html 转载请注明出处 Druid的数据采集格式 Druid可以采集非标准化的数据诸如JSON,CSV或者以某种分隔符隔开的TSV格式,当然还支持自定义格式.虽然大部分的文档使用JSON格式,但是通过druid来…

“Found interface com.mysql.jdbc.Connection, but class was expected ”

In mysql-connecter-java-5.0 Statement is a class. in 5.1, it’s an interface. The code you write shouldn’t care too much. But if you compile against the new version, then run against the old version, you’ll have this problem. 我项目中用的是5.1的版本&am…

1. 冒泡与选择排序及其比较

冒泡排序 1. 思想 冒泡排序&#xff08;Bubble Sort&#xff09;是一种交换排序&#xff0c;基本思路是&#xff1a;两两比较相邻记录的关键字&#xff0c;如果反序则交换&#xff0c;直到没有反序的记录为止。 2. 实现 2.1 初学常用的一种 public static <T extends Compar…

Java如何实现分页

先阐述一下具体的思路&#xff1a; 第一步&#xff1a;编写一个分页的类里面包含了&#xff08;第一页&#xff0c;最后一页&#xff0c;下一页&#xff0c;上一页&#xff0c;当前页&#xff0c;页码等等&#xff09;对象和方法。第二步&#xff1a;进行分页的业务处理。 &g…

删除服务中的mysql服务

以管理员身份运行命令提示符&#xff0c;然后输入sc delete mysql 这里的mysql是你服务中的mysql名&#xff08;有些可能是mysql5&#xff0c;或者之类&#xff09;。

2018.09.28 hdu5435A serious math problem(数位dp)

传送门 数位dp卡常题。 写了一发dfs版本的发现过不了233。 于是赶紧转循环版本。 预处理出f数组。f[i][j]f[i][j]f[i][j]表示前i位数异或和为j的方案数。 然后每次直接数位dp就行了。 代码&#xff1a; #include<bits/stdc.h> #define mod 1000000007 #define N 100005 #…

在有原来的数据的情况下,恢复数据库的数据

只要把mysql安装目录下的data文件中的ibdata1&#xff08;储存文件的数据&#xff09;替换&#xff0c;再把你的库名的文件&#xff08;只是表结构&#xff09;加进去。

photoshop切图

1.传统切图 &#xff08;1&#xff09;打开一个psd文件&#xff0c;选择ps左边菜单栏的裁剪工具&#xff0c;选择切片工具。首先我们对这个psd文件进行分析&#xff0c;有意识的将其划分成几个选区&#xff0c;然后通过鼠标的拖拽用切片工具将我们所需要的图案切下来&#xff0…

怎么在cmd中进入D盘下的文件夹

从cmd中进入D盘&#xff0c;在光标处输入“d:”(大小写都可以)&#xff0c;按enter进入。 进入D盘根目录后&#xff0c;如果想找到work文件夹可以在光标处输入“cd work”即可。

postgresql 高可用 etcd + patroni 之六 callback bind vip

os: centos 7.4 postgresql: 9.6.9 etcd: 3.2.18 patroni: 1.4.4 本篇blog介绍下 etcd patroni 发生切换时使用 callback 来重新设定 master 的 vip。 主要是方便自有机房或托管的&#xff0c;云环境貌似不能绑定固定的vip。 patroni 的一些参数 官方文档描述在callback时又这…

${ctx} 的那些事

JSP中路径路径繁多&#xff0c;采用绝对路径&#xff0c;${pageContext.request.contextPath} 作用&#xff1a;取出部署的应用程序名&#xff0c;这样不管如何部署&#xff0c;所有路径都是正确的。 可以在jsp中定义&#xff1a; <% taglib uri”http://Java.sun.com/js…

linux文件管理 - 系统目录结构

几乎所有的计算机操作系统都是用目录结构组织文件。具体来说就是在一个目录中存放子目录和文件, 而在子目录中又会进一步存放子目录和文件&#xff0c;以此类推形成一个树状的文件结构&#xff0c;由于其结构很像一棵树的分支, 所以该结构又被称为“目录树”。 Linux系统中也沿…

JSP传值

当从点击JSP页面中的链接时&#xff0c;会执行相关操作&#xff0c;把后台所需要的参数传递过去。 最常见的是通过form表单的形式传递。如下代码所示 <s:form action"LoginAction.action" method"post"><s:textfield label"用户名" n…

nginx反向代理获取用户真实ip

nginx做反向代理时,默认的配置后端获取到的ip都是来自于nginx,如何转发用户的真实ip到后端程序呢?如是是java后端,用request.getRemoteAddr();获取到的是nginx的ip地址,而不是用户的真实ip. 修改nginx配置,如下: upstream www.xxx.com {ip_hash;server serving-server1.com:80…

Action 跳转的方法和详解

在实际项目中&#xff0c;我们难免遇到页面跳转&#xff0c;传参&#xff0c;action与action之间的跳转&#xff0c;我们这时候则需要一些方法来完成&#xff0c;如下代码所示&#xff1a; <action name"login" class"loginAction.class"><resul…

java和C++有什么异同

相同点&#xff1a; java和C都是面向对象语言&#xff0c;都使用了面向对象的基本思想&#xff08;抽象、封装、继承、多态&#xff09;&#xff0c;都具有面向对象的基本特性&#xff08;继承、组合等&#xff09;。 不同点&#xff1a; ①&#xff1a;java为解释性语言&#…

Hibernate 语句总结

关系映射数据库Hibernate使用详解&#xff1a; 在hql语句中&#xff0c;from后面接的不是表名&#xff0c;是实体名&#xff0c;from User 注&#xff1a;User是实体名&#xff0c;不是数据库中的表名。 查询并返回表中的数量&#xff1a; String sql "select count(*…

DataGrid数据绑定

后台数据绑定 用户场景是生成报表&#xff0c;展示公司各员工每个月的绩效 数据结构 包括报表和单个员工绩效两个实体 public class Report {/// <summary>/// 统计时间/// </summary>public string StatisticalDate { get; set; }public List<ReportDetail>…

String.valueOf() 和 toString的区别

当我们使用对象转换为String类型时 在使用toString()方法中&#xff0c;因为java.lang.Object类里已有public方法.toString()&#xff0c;所以对任何严格意义上的java对象都可以调用此方法。但在使用时要注意&#xff0c;必须保证object不是null值&#xff0c;否则将抛出NullP…