安卓TV开发《2》开发TV应用

本节将会总结下TV开发中的注意点,如何管理TV控制器,如何构建TV布局、如何创建TV导航。

一、处理TV硬件

为啥要处理TV硬件呢?因为TV不像其他安卓设备一样支持触摸屏,照相机、GPS之类的。这些硬件功能在TV上统统被阉割,,,,为了能够开发出更好的应用我们还是有必要了解下这些差异,处理下这些硬件。

1、检查运行环境

安卓的api在TV、Phone等安卓设备上都可以使用的。这时在进行TV开发时,或者你想做个TV手机都支持的app时,这时便需要区分运行环境啦,这样才能针对不同的环境做出不同的解决方案。如下通过UiModeManager 我们就能判断app是否运行在TV上。

 UiModeManager uiModeManager = (UiModeManager) getSystemService(UI_MODE_SERVICE);
 
 Log.i(TAG, "onCreate: "+(uiModeManager.getCurrentModeType()== 

                           Configuration.UI_MODE_TYPE_TELEVISION));
 
 // 下面是Configuration类中定义的部分常量,想了解更多可以查阅下这个类。
 
 public static final int UI_MODE_TYPE_CAR = 0x03;// 汽车
 public static final int UI_MODE_TYPE_WATCH = 0x06;// 手表                          
2、TV不支持的硬件功能
硬件 对应字符串
触摸屏 android.hardware.touchscreen
触摸屏模拟器 android.hardware.faketouch
电话 android.hardware.telephony
相机 android.hardware.camera
近距离无线通信 (NFC) android.hardware.nfc
GPS android.hardware.location.gps
麦克风 android.hardware.microphone
传感器 android.hardware.sensor
纵向屏幕 android.hardware.screen.portrait

ps:
1、某些 TV 控制器具有麦克风,但与此处所述的麦克风硬件功能并不相同。控制器麦克风是完全受支持的。

2、如需查看功能、子功能及其描述符的完整列表,请参阅功能参考
3、上述的字符串都被封装到PackageManager这个类中的常量字段上。可以方便开发者快速调用。

(1)对不支持硬件的处理–声明为非必须支持

如果你开发一款应用,既支持TV,也支持手机。但是你在手机使用到了上述的硬件功能时,你可以吧这些功能声明为TV非必须。

<uses-feature android:name="android.hardware.touchscreen"
            android:required="false"/>
            
    <uses-feature android:name="android.hardware.faketouch"
            android:required="false"/>
            
    <uses-feature android:name="android.hardware.telephony"
            android:required="false"/>
            
    <uses-feature android:name="android.hardware.camera"
            android:required="false"/>
            
    <uses-feature android:name="android.hardware.nfc"
            android:required="false"/>
            
    <uses-feature android:name="android.hardware.location.gps"
            android:required="false"/>
            
    <uses-feature android:name="android.hardware.microphone"
            android:required="false"/>
            
    <uses-feature android:name="android.hardware.sensor"
            android:required="false"/>

ps:
1、如果将硬件功能的值设为 true 来将其声明为必需功能,就会导致您的应用无法安装在 TV 设备上或出现在 Android TV 主屏幕启动器中。
2、某些功能具有子功能,比如 android.hardware.camera.front。请务必将您的应用中也使用的任何子功能标记为 required=“false”。

3、如何判断设备是否支持硬件
 if (getPackageManager().hasSystemFeature(PackageManager.FEATURE_TOUCHSCREEN)) {
    
    
            Log.d(TAG, "设备支持触屏");
            // todo
        }else{
    
    
            Log.d(TAG, "设备不支持触屏");
        }

如上栗子,使用PackageManager提供的方法即可。

4、注意某些权限隐含硬件功能
权限 隐含硬件功能
RECORD_AUDIO android.hardware.microphone
CAMERA android.hardware.camera 和 android.hardware.camera.autofocus
ACCESS_COARSE_LOCATION android.hardware.location和android.hardware.location.network
ACCESS_FINE_LOCATION android.hardware.location和android.hardware.location.gps

1、如果您的应用请求上面列出的某项功能,请在清单中为这项隐含的硬件功能添加 uses-feature 声明,指明它并非必需功能

2、注意:如果您的应用以 Android 5.0(API 级别 21)或更高版本为目标平台且使用 ACCESS_COARSE_LOCATION 或 ACCESS_FINE_LOCATION 权限,那么即使 TV 设备没有网卡或 GPS 接收器,用户仍然可以在 TV 设备上安装您的应用。

5、TV上定位的支持

原生api已经被阉割,provider只能使用 netWork啦!但是由于TV上TV厂商没有默认集成高德地图、百度地图、google地图,的服务。所以使用原生api无法获得location对象。要想定位可以集成第三方sdk。

二、TV怎样与用户交互

手机与人最主要的交互方式就是触摸啦!然而TV却不是这样,由于TV的大屏体验,所以一般要求用户在10 英尺以外的地方尽情的欣赏。这时遥控器、游戏手柄等硬件设备就成了交互的媒介。

1、方向键基本控制按钮

1、普通的应用时,您可以使用方向键:上、下、左、右、返回、确认。等按键与TV进行交互。
2、如果是游戏app,您还应该支持更多的手柄按键。
ps:下表就是常见的KeyEvent,我们可以重写这个事件处理下相应的逻辑。例如DrawerLayout在手机上一般右滑动打开,左滑动关闭。在TV上我们应该处理逻辑,让用户点击上下左右中的右键时打开,左键关闭。

KeyEvent 行为
BUTTON_B、BACK 返回
BUTTON_SELECT、BUTTON_A、ENTER、DPAD_CENTER、KEYCODE_NUMPAD_ENTER 选择
DPAD_UP、DPAD_DOWN、DPAD_LEFT、DPAD_RIGHT 导航
BUTTON_SELECT、BUTTON_A、ENTER、DPAD_CENTER、KEYCODE_NUMPAD_ENTER 播放
BUTTON_START、BUTTON_SELECT、BUTTON_A、ENTER、DPAD_CENTER、KEYCODE_NUMPAD_ENTER 暂停
BUTTON_R1 跳到下一个
BUTTON_L1 跳到上一个
DPAD_RIGHT、BUTTON_R2、AXIS_RTRIGGER、AXIS_THROTTLE 快进
DPAD_LEFT、BUTTON_L2、 AXIS_LTRIGGER、AXIS_BRAKE 快退
(没有与“停止”关联的 KeyEvent) 停止
2、提供适当的返回按钮行为

返回按钮不应充当开关按钮。例如,不要将它用于打开和关闭菜单。它应当仅用于通过面包屑导航方式返回到玩家之前所在的屏幕,例如:游戏过程 > 游戏暂停屏幕 > 游戏主屏幕 > Android 主屏幕。

3、详情参考

三、构建TV布局

TV 屏幕的通常观看距离约为 10 英尺,这就要求您的布局界面以简洁为主啦。一下便是TV布局设计的一些建议。

1、主题背景的建议

(1)Leanback 主题背景

Leanback androidx 库包含 Theme.Leanback,它是 TV Activity 的主题背景,可提供一致的视觉风格。我们强烈建议您将此主题背景用于使用 androidx leanback 类构建的任何 TV 应用

 <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:supportsRtl="true"
        
        android:theme="@style/Theme.Leanback">

注意:leanback 主题背景不包含操作栏,因为 Android TV 应用中没有操作栏。如果您的应用使用 BrowseSupportFragment 之类的 Support Fragment,您的 Activity 必须扩展 FragmentActivity。不要使用 AppCompatActivity,它会尝试设置操作栏的主题背景并产生以下错误:

java.lang.RuntimeException: Unable to start activity ComponentInfo{
    
    ...} :
    java.lang.IllegalStateException: You need to use a Theme.AppCompat theme (or descendant) with this
    activity.

(2)NoTitleBar 主题背景

标题栏是手机和平板电脑上 Android 应用的标准界面元素,但它并不适合 TV 应用。如果您未使用 androidx leanback 类,则应将此主题背景应用于您的 TV Activity,以禁止显示标题栏。

activity
        android:name="com.example.android.TvActivity"
        android:label="@string/app_name"
        android:theme="@android:style/Theme.NoTitleBar">
        ...

      </activity>
2、构建TV布局遵守准则
  • 构建屏幕方向为横向的布局。TV 屏幕始终以横屏模式显示
  • 将屏幕导航控件置于屏幕的左侧或右侧,将节省下的垂直空间留给内容。
  • 利用 Fragment 创建按若干部分组织的界面,并利用 GridView(而非 ListView)等视图组,以更充分地利用屏幕的水平空间。
  • 利用 RelativeLayout 或 LinearLayout 等视图组来布置视图。此方法让系统能够根据 TV 屏幕的尺寸、对齐、宽高比和像素密度来调整视图的位置
  • 在布局控件之间添加足够的外边距,以避免造成界面杂乱无章。
3、过扫描

TV 布局有一些独特的要求,因为 TV 标准不断发展演变,并且用户希望 TV 能够始终向观众呈现全屏画面。为此,TV 设备可能会裁剪应用布局的外边缘以确保填满整个显示屏。此行为通常称为“过扫描”

(1)要求

必须始终对用户可见的屏幕元素应放置在过扫描安全区域内,并且保持可见直接控件margain上下27dp、左右48dp。

(2)栗子

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

       <!-- Screen elements that can render outside the overscan safe area go here -->

       <!-- Nested RelativeLayout with overscan-safe margin -->
       <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
           android:layout_width="match_parent"
           android:layout_height="match_parent"
           android:layout_marginTop="27dp"
           android:layout_marginBottom="27dp"
           android:layout_marginLeft="48dp"
           android:layout_marginRight="48dp">

          <!-- Screen elements that need to be within the overscan safe area go here -->

       </RelativeLayout>
    </RelativeLayout>

(3)注意:如果您使用 androidx leanback 类(如 BrowseFragment 或相关微件),请勿对布局应用过扫描外边距,因为这些布局已经纳入了过扫描安全外边距。

4、字体建议
  • 使用 Android 的标准字号:
    <TextView
          android:id="@+id/atext"
          android:layout_width="wrap_content"
          android:layout_height="wrap_content"
          android:gravity="center_vertical"
          android:singleLine="true"
          android:textAppearance="?android:attr/textAppearanceMedium"/>
5、TV 布局建议
  • TV 布局应以 1920 x 1080 像素的屏幕尺寸为目标
  • 请尽可能以九宫格图片元素的形式提供图片
6、应该避免使用的
  • 复用布局
  • ActionBar
  • ViewPager
7、处理大图

建议您使用 Glide 库来获取、解码和显示应用中的位图。
更多参考: Android 图形最佳做法

8、提供有效广告

1、建议为30s以内,可以通过控制键关闭跳过之类的。
2、Android TV 不提供网络浏览器。您的广告不得试图启动网络浏览器或者重定向到未经批准用于 Android TV 设备的 Google Play 商店内容。
3、您可以使用 WebView 类来登录社交媒体服务。

四、创建TV导航

使用遥控器进行导航!!!
使用遥控器进行导航!!!
使用遥控器进行导航!!!

1、启用方向键导航

在这里插入图片描述

Android 框架会自动处理布局元素之间的方向导航。如上系统会默认为第一个按钮,这时我们通过遥控器上下左右就可以导航到按钮2。您通常无需对应用执行任何额外的操作。不过,您应该对通过方向键控制器导航进行全面测试,以发现任何导航问题。请遵循以下准则来测试您应用的导航系统是否能够在 TV 设备上与方向键很好地搭配使用:

  • 确保用户可使用方向键控制器导航到屏幕上的所有可见控件.
  • 对于获得焦点的滚动列表,请确保可使用方向键的向上键和向下键滚动列表,并可使用 Enter 键选择列表中的项目。验证用户是否可选择列表中的元素,以及选择元素时是否列表仍会滚动
  • 确保控件间的切换简单明了并且可以预测
2、修改方向导航

虽然Android 框架会自动处理布局元素之间的方向导航,但是如果您决定希望用户以特定方式在布局中导航,则可以为控件设置显式方向导航

(1)Android 界面微件的所有可用导航属性

控件属性 功能
nextFocusDown 定义当用户向下导航时下一个获得焦点的视图。
nextFocusLeft 定义当用户向左导航时下一个获得焦点的视图。
nextFocusRight 定义当用户向右导航时下一个获得焦点的视图。
nextFocusUp 定义当用户向上导航时下一个获得焦点的视图。

要使用其中一个显式导航属性,请将值设为布局中另一个微件的 ID(android:id 值)。您应将导航顺序设为循环,以便最后一个控件能够指引焦点回到第一个控件。

(2)栗子 按钮1->按钮3->按钮2->按钮1

在这里插入图片描述

<?xml version="1.0" encoding="utf-8"?>
<androidx.appcompat.widget.LinearLayoutCompat xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity"
    android:orientation="vertical"
    android:gravity="center">

   <androidx.appcompat.widget.AppCompatButton
       android:id="@+id/btn1"
       android:layout_width="wrap_content"
       android:layout_height="wrap_content"
       android:text="按钮1"
       tools:ignore="HardcodedText"
       android:nextFocusDown="@id/btn3"/>
    <androidx.appcompat.widget.AppCompatButton
        android:id="@+id/btn2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="按钮2"
        tools:ignore="HardcodedText"
        android:nextFocusDown="@id/btn1"/>
    <androidx.appcompat.widget.AppCompatButton
        android:id="@+id/btn3"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="按钮3"
        tools:ignore="HardcodedText"
        android:nextFocusDown="@id/btn2"/>

</androidx.appcompat.widget.LinearLayoutCompat>
3、提供明确的焦点和选择

让用户导航到焦点的控件时,控件颜色尺寸凸出之类的,便于用户观看效果。体验交互。安卓给出了button栗子参考:

<!-- res/drawable/button.xml -->
    <?xml version="1.0" encoding="utf-8"?>
    <selector xmlns:android="http://schemas.android.com/apk/res/android">
        <item android:state_pressed="true"
              android:drawable="@drawable/button_pressed" /> <!-- pressed -->
        <item android:state_focused="true"
              android:drawable="@drawable/button_focused" /> <!-- focused -->
        <item android:state_hovered="true"
              android:drawable="@drawable/button_focused" /> <!-- hovered -->
        <item android:drawable="@drawable/button_normal" /> <!-- default -->
    </selector>


<Button
        android:layout_height="wrap_content"
        android:layout_width="wrap_content"
        android:background="@drawable/button" />

The end

猜你喜欢

转载自blog.csdn.net/qq_38350635/article/details/105496700