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
總結
以上是生活随笔為你收集整理的Android TV Overscan的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 辅助排序和Mapreduce整体流程
- 下一篇: ACdream区域赛指导赛之手速赛系列(