更新记录

1.0.4(2025-07-22)

新增了属性,可指定上下左右键需要聚焦的下一个位置,避免安卓的就近跳转原则出现奇奇怪怪的跳转位置

1.0.3(2025-07-15)

更新文档

1.0.2(2025-07-14)

bug修复

查看更多

平台兼容性

uni-app x

Chrome Safari Android iOS 鸿蒙 微信小程序
- - 5.0 - - -

请打包自定义基座试用,标准基座无法运行

xf-tv-view

xf-tv-view 是一个专为 Android TV 平台设计的 Vue 组件,主要用于处理焦点管理和按键事件。该组件封装了 Android TV 设备的焦点逻辑和按键响应机制,方便在 UniAppX 中开发 TV 端应用时使用。

也可以开发其他需要按键控制支持的应用

该插件只支持安卓端uniapp-X,本插件以经过完整的影视TV APP开发及使用过,可放心使用,可完整实现遥控控制、快进快退等等逻辑(通过keyCallback回调实现逻辑)。

组件提供了焦点状态管理、焦点样式切换、按键事件回调等功能,支持自定义焦点样式、默认焦点设置以及按键事件的自定义处理。

使用本组件请尽量在子组件中封装及实现按钮等样式,不要在子组件中使用button等组件,这些组件本身也含有聚焦事件,会有冲突。如果非要使用,请设置button的id,并在xf-tv-view上设置focusId后自行尝试,作者并未试验过。

属性

属性名 类型 默认值 描述
focusId String null 关联的焦点元素 ID,用于获取对应的 Android View
focusClass String "" 获得焦点时的样式类名
unFocusClass String "" 失去焦点时的样式类名
defaultFocus Boolean false 是否默认获取焦点
keyCallback Function null 按键事件回调函数,用于处理自定义按键逻辑
disabledEnterKeyDown Boolean false 是否禁用 Enter 键按下事件
focusable Boolean true 是否可聚焦
elementId String null 组件id,未设置时会根据随机字符串生成
nextFocusDownId String null 填写组件id,指定下键时聚焦的下一个位置,为null时为安卓默认就近原则聚焦
nextFocusUpId String null 填写组件id,指定下键时聚焦的下一个位置,为null时为安卓默认就近原则聚焦
nextFocusLeftId String null 填写组件id,是否可指定下键时聚焦的下一个位置,为null时为安卓默认就近原则聚焦
nextFocusRightId String null 填写组件id,指定下键时聚焦的下一个位置,为null时为安卓默认就近原则聚焦

focusId说明

大多数情况下不需要设置focusId,在某些特殊情况下,比如在xf-tv-view下嵌入了video组件,那么你就需要给video组件设置设置id,并在xf-tv-view的focusId填入该id,这样在视频全屏时才能正确的获取遥控器在视频组件上事件,然后通过keyCallback回调处理快进快退播放等功能实现

keyCallback

多数情况下不需要使用到该回调,系统原生会处理上下左右的聚焦管理,你可以通过onEnterKeyDown事件直接处理对应功能。 用到该回调的情况一是上面提到的视频全屏时的复杂功能开发。二是系统的聚焦管理需要优化的情况下,特殊情况系统的聚焦管理会跳到不是很理想的位置,你就需要手动处理,或者通过设置nextFocusDownId等属性指定

组件事件

事件名 触发条件 回调参数 描述
focusChange 焦点状态改变时 hasFocus: Boolean 传递新的焦点状态
onTvFocus 获得焦点时 - 焦点获取事件
onTvBlur 失去焦点时 - 焦点丢失事件
onKeyDown 按键按下时 keyCode: Number 传递按下的按键码
onEnterKeyDown Enter 或方向键中心按下时 - Enter 键按下事件

组件方法

requestFocus():使组件获取焦点 调用示例:(this.$refs["xxxx"] as XfTvViewComponentPublicInstance).requestFocus()

setFocusable(enable : boolean) 设置组件是否可以对焦

示例代码


<template>
    <!-- #ifdef APP -->
    <scroll-view style="flex:1">
    <!-- #endif -->

        <view>简单使用,组件默认提供了确定键的事件</view>
        <view style="display: flex;flex-direction: row;flex-wrap: wrap;">
            <!-- 简单使用 -->
            <xf-tv-view v-for="(item,index) in exampleData" style="padding: 10px;width: 230rpx;"
                focus-class="border-red" :un-focus-class="index==3?'border-green':''" :default-focus="index==5"
                :focusable="index!=6" @onEnterKeyDown="handlerTvEnter(item) " :disabledEnterKeyDown="index==7">
                <text>{{item}}</text>
            </xf-tv-view>
        </view>
        <view style=""></view>
        <view style="margin-top: 20px;">完整事件拦截,拦截元素的所有按键事件自行处理</view>
        <xf-tv-view elementId="abcdg" style="padding: 10px;width: 230rpx;" focus-class="border-red"
            un-focus-class="border-green" :keyCallback="keyEventCallBack">
            <view>
                <image class="logo" src="/static/logo.png"></image>
                <text>完整事件拦截示例</text>
            </view>
        </xf-tv-view>

        <view style="margin-top: 20px;">指定上下左右按键的下一个聚焦对象</view>
        <xf-tv-view style="padding: 10px;width: 230rpx;" focus-class="border-red" nextFocusLeftId="11111"
            nextFocusRightId="22222" nextFocusUpId="33333" nextFocusDownId="44444">
            <text>聚焦这里时试试上下左右按键</text>
        </xf-tv-view>
        <xf-tv-view elementId="11111" style="padding: 10px;width: 230rpx;" focus-class="border-red">
            <text>左键跳着里</text>
        </xf-tv-view>
        <xf-tv-view elementId="22222" style="padding: 10px;width: 230rpx;" focus-class="border-red">
            <text>右键跳着里</text>
        </xf-tv-view>
        <xf-tv-view elementId="33333" style="padding: 10px;width: 230rpx;" focus-class="border-red">
            <text>上键跳这里</text>
        </xf-tv-view>
        <xf-tv-view elementId="44444" style="padding: 10px;width: 230rpx;" focus-class="border-red">
            <text>下键跳这里</text>
        </xf-tv-view>

    <!-- #ifdef APP -->
    </scroll-view>
    <!-- #endif -->
</template>

<script>
    import KeyEvent from 'android.view.KeyEvent';
    export default {
        data() {
            return {
                title: 'Hello',
                exampleData: [
                    "示例1",
                    "示例2",
                    "示例3",
                    "示例4",
                    "示例5",
                    "示例6",
                    "示例7",
                    "示例8",
                    "示例9",
                ]
            }
        },
        onLoad() {

        },
        methods: {
            handlerTvEnter(item : string) {
                uni.showToast({
                    title: item
                })
            },
            keyEventCallBack(event : KeyEvent) {
                //KeyEvent事件码请参阅https://developer.android.google.cn/reference/android/view/KeyEvent

                //调用组件的方示例
                //(this.$refs["xxxx"] as XfTvViewComponentPublicInstance).requestFocus()
                console.log(event);
                if (KeyEvent.ACTION_DOWN == event.getAction()) { //当为按下动作时自行
                    if (KeyEvent.KEYCODE_ENTER == event.getKeyCode() || KeyEvent.KEYCODE_DPAD_CENTER == event.getKeyCode()) {
                        uni.showToast({
                            title: "按键按下了"
                        })

                    }

                }
                //该方法返回true则会拦截系统默认的事件处理器
                //例如 系统默认上下左右导航键是会移动聚焦对象的 可自行设置为true体验
                return false;
            },
        }
    }
</script>

<style>
    .logo {
        height: 100px;
        width: 100px;
        margin: 100px auto 25px auto;
    }

    .title {
        font-size: 18px;
        color: #8f8f94;
        text-align: center;
    }

    .border-red {
        border: 5px solid red;
    }

    .border-green {
        border: 5px solid green;
    }
</style>

隐私、权限声明

1. 本插件需要申请的系统权限列表:

2. 本插件采集的数据、发送的服务器地址、以及数据用途说明:

3. 本插件是否包含广告,如包含需详细说明广告表达方式、展示频率:

使用中有什么不明白的地方,就向插件作者提问吧~ 我要提问