互联网网站文化网站设计师主要做什么
- 作者: 五速梦信息网
- 时间: 2026年03月21日 10:53
当前位置: 首页 > news >正文
互联网网站文化,网站设计师主要做什么,大数据精准客户,白云手机网站开发不分大屏产品需要有遥控器功能#xff0c;这里分享部分实战经验 文章目录 前言一、案例部分效果图二、项目基础架构三、焦点基础知识适配遥控器基础-焦点问题焦点管理明确焦点状态布局实现硬编码实现引入第三方自定义组件实现 焦点顺序作用 初始焦点 requestFocus 按键处理获取… 不分大屏产品需要有遥控器功能这里分享部分实战经验 文章目录 前言一、案例部分效果图二、项目基础架构三、焦点基础知识适配遥控器基础-焦点问题焦点管理明确焦点状态布局实现硬编码实现引入第三方自定义组件实现 焦点顺序作用 初始焦点 requestFocus 按键处理获取当前焦点 四、实际开发技能分享处理焦点注意实现RecycleView 案例分析 总结 前言
十多年的Android软件开发中基本上都是做方案上的软件产品。 对于 电视、投影、闺蜜机 上面的软件 都有遥控器控制的需求就需要自己的Android App能够受遥控器控制。 这里举一个案例分享一下开发中的部分经验。 也方便自己下次开发直接复用经验高效开发。 一、案例部分效果图
当前分享案例中部分效果图如下 二、项目基础架构
为什么要简单列举一下架构图其实不同的UI架构会遇到各种不一样的问题这里针对性的从列举项目上展示一下架构方便分析和理解部分阐明的问题 三、焦点基础知识
适配遥控器基础-焦点问题
焦点管理
软件App 适配遥控器需要用遥控器的功能实际上就是处理焦点问题。当UI获取焦点时候、用遥控器上下左右按键移动到某一个UI图标识货UI图标必须差异化显示出来表示选中状态进而遥控器点击ok 等实际上就是点击这个UI的操作。
明确焦点状态
确保UI元素有清晰的焦点视觉效果放大、边框、阴影等 如上描述其实就是一个UI组件选中的效果。 这里我理解有三种表现形式
布局实现
比如我们开发中常见的在获取焦点 state_focused true 时候给于不同的背景、颜色 等突出显示出来。
Buttonandroid:idid/buttonandroid:focusabletrueandroid:backgrounddrawable/button_background/!– drawable/button_background.xml –
selector xmlns:androidhttp://schemas.android.com/apk/res/androiditem android:state_focusedtrue android:drawabledrawable/button_focused/item android:drawabledrawable/button_normal/
/selector硬编码实现
这里举个例子如下设置UI组件的FocusChange 事件对获取焦点和失去焦点进行UI不同渲染达到焦点选中效果无交点正常显示效果。 binding.selectOk.setOnFocusChangeListener { v, hasFocus -val roundView: RoundTextView v as RoundTextViewif (hasFocus) {roundView.setStrokeWidthColor(5f, Color.parseColor(#EEEE00))} else {roundView.setStrokeWidthColor(5f, Color.parseColor(#00000000))}}holder.vb.root.setOnFocusChangeListener { v, hasFocus -val roundView: RoundConstraintLayout v as RoundConstraintLayoutif(hasFocus){roundView.setStrokeWidthColor(5f, Color.parseColor(#EEEE00))focusPospositionLog.d(TAG, focusPos:\({focusPos})RightAppInfoLiveData.value RightAppInfo(focusPos,mCenterAppDataList.size)}else{roundView.setStrokeWidthColor(5f, Color.parseColor(#00000000))Log.d(TAG,no focusPos:\){focusPos})focusPos-1RightAppInfoLiveData.value RightAppInfo(focusPos,mCenterAppDataList.size)}}引入第三方自定义组件实现
只是作为一个UI组件使用第三方组件和核心功能就是在获取焦点时候突出显示而已和 布局表现及 硬编码实现方式并无区别。
焦点顺序
设置合理的焦点移动顺序android:nextFocusUp/Down/Left/Right为什么要有这个东西呢 举例在架构图中分三页面无论那个页面都有很多UI组件如何实现遥控器按 上、下、左、右按键时候UI组件选中按照自己意愿活着业务定义来切换不同UI选中状态呢
这个时候焦点移动顺序就起到作用了下面列举一下实际用法其实就是在布局文件中设置的。
作用
实现UI焦点移动顺序对边角的UI组件指向自己这样就可以规避焦点不见了的问题规避反人类的体验。 实际使用 简单 如下 初始焦点 requestFocus
为什么会有这个方法 为什么需要 比如说 进行界面切换的时候如架构图中从一个界面切换到另外一个界面、点击一个图标进入另外一个界面。 在新的界面焦点在哪里是不确定的或者说在新的界面是没有焦点的。 那么最好初始化一个UI具备焦点。 这样遥控器按键时候直接上下左右进行切换规避没有焦点时候或者焦点不确定时候需要多按好多次 才有UI获取焦点显示出来体验和业务需要的。
比如架构图中第一页切换到第二页、第二页切换到第三页、第三页切换到第二页、第二页切换到第一页如何实现焦点初始化呢 在 页面onResume 方法中让指定的UI初始化一次焦点去获取焦点一次。 按键处理
我们为什么需要处理按键遥控器的本身其实就是KeyEvent 事件映射的其实就是物理按键的功能。 那么当keyevent 事件通过遥控器触发后做什么业务逻辑那就是上层需要处理的事情了。 这就是为什么我们需要按键处理了。 对于很多遥控器基本功能通用专用的KeyEvent 是通过定制实现(比如 点击遥控器一个按键就是要直接打开抖音、长按遥控器进行语音控制呀这些就是定制的功能)
下面代码列举了部分源码监听左右按键最核心的功能是 需要翻页的功能。 遥控器没有翻页的物理按键通过当前焦点是否是边角焦点结合按键监听方向实现是否翻页、翻到哪一页的功能。 override fun onKeyDown(keyCode: Int, event: KeyEvent?): Boolean {when (keyCode) {KeyEvent.KEYCODE_DPAD_UP - {Log.d(TAG, KEYCODE_DPAD_UP)val rootview window.decorViewval focusView rootview.findFocus()Log.i(TAG, 当前获取焦点的View\({focusView})//return true // 返回true表示事件已被处理val focused currentFocusfocusView?.let {if(viewPager.currentItem1(focusView.id R.id.cl_homeleft_second||focusView.id R.id.cl_homeleft_center||focusView.id R.id.cl_homeleft_first )){Log.d(TAG,KEYCODE_DPAD_UP 在vp 第2 页面但是焦点却在第一页面那么 request 一次)//homeCenterFragment.binding.clTouping.requestFocus()try{homeCenterFragment.viewBinding?.let { vBing-vBing.clTouping.requestFocus()}}catch (e:Exception){Log.d(TAG, 暂时 未初始化 homeCenterFragment.viewBinding )e.printStackTrace()}// viewPager.currentItem1}}}KeyEvent.KEYCODE_DPAD_DOWN - {Log.d(TAG, KEYCODE_DPAD_DOWN)val rootview window.decorViewval focusView rootview.findFocus()val focused currentFocusLog.i(TAG, 当前获取焦点的View\){focusView})focusView?.let {if(viewPager.currentItem1(focusView.id R.id.cl_homeleft_second||focusView.id R.id.cl_homeleft_center||focusView.id R.id.cl_homeleft_first )){Log.d(TAG,KEYCODE_DPAD_DOWN 在vp 第2 页面但是焦点却在第一页面那么 request 一次)//homeCenterFragment.binding.clTouping.requestFocus()// viewPager.requestFocus()try{homeCenterFragment.viewBinding?.let { vBing-vBing.clTouping.requestFocus()}}catch (e:Exception){Log.d(TAG, 暂时 未初始化 homeCenterFragment.viewBinding )e.printStackTrace()}//viewPager.currentItem1}}}KeyEvent.KEYCODE_DPAD_LEFT - {Log.d(TAG, KEYCODE_DPAD_LEFT)val rootview window.decorViewval focusView rootview.findFocus()Log.i(TAG, 当前获取焦点的View\({focusView})focusView?.let {if (resources.configuration.orientation Configuration.ORIENTATION_LANDSCAPE) {if(focusView.id R.id.cl_clock||focusView.id R.id.cl_touping||focusView.id R.id.cl_file){viewPager.currentItem0}else if(focusView.idR.id.cl_whiteboard){viewPager.currentItem1}if(viewPager.currentItem2){Log.d(TAG,homeRightFragment.centerAppAdapter.focusPos focusPos:\){homeRightFragment.centerAppAdapter.focusPos})// if(homeRightFragment.centerAppAdapter.focusPos%80){if((homeRightFragment.centerAppAdapter.focusPos)%80){viewPager.currentItem1}Log.d(TAG, 当前是在 vp currentItem 2 下)try {val rightAppInfo: RightAppInfo? viewModel.rightAppInfoLiveData.valueLog.d(TAG, rightAppInfo:\({Gson().toJson(rightAppInfo)})rightAppInfo?.let { it-if( it.index%80){viewPager.currentItem1}}} catch (e: Exception) {e.printStackTrace()}}} else if(resources.configuration.orientation Configuration.ORIENTATION_PORTRAIT) {if(focusView.id R.id.cl_clock||focusView.id R.id.cl_touping||focusView.id R.id.cl_bizhi||focusView.id R.id.cl_googleplay||focusView.id R.id.cl_file){viewPager.currentItem0}else if(focusView.idR.id.cl_whiteboard){viewPager.currentItem1}if(viewPager.currentItem2){Log.d(TAG,homeRightFragment.centerAppAdapter.focusPos focusPos:\){homeRightFragment.centerAppAdapter.focusPos})// if(homeRightFragment.centerAppAdapter.focusPos%40){if((homeRightFragment.centerAppAdapter.focusPos)%40){viewPager.currentItem1}Log.d(TAG, 当前是在 vp currentItem 2 下)try {val rightAppInfo: RightAppInfo? viewModel.rightAppInfoLiveData.valueLog.d(TAG, rightAppInfo:\({Gson().toJson(rightAppInfo)})rightAppInfo?.let { it-if( it.index%40){viewPager.currentItem1}}} catch (e: Exception) {e.printStackTrace()}}}}}KeyEvent.KEYCODE_DPAD_RIGHT - {Log.d(TAG, KEYCODE_DPAD_RIGHT )val rootview window.decorViewval focusView rootview.findFocus()Log.i(TAG, 当前获取焦点的View\){focusView})focusView?.let {if (resources.configuration.orientation Configuration.ORIENTATION_LANDSCAPE) {if(focusView.id R.id.cl_homeleft_second){viewPager.currentItem1}else if(focusView.id R.id.cl_home_listapp||focusView.id R.id.cl_touping||focusView.id R.id.cl_music){viewPager.currentItem2}} else if(resources.configuration.orientation Configuration.ORIENTATION_PORTRAIT) {if(focusView.id R.id.cl_homeleft_second||focusView.id R.id.cl_homeleft_center||focusView.id R.id.cl_homeleft_first ){viewPager.currentItem1}else if(focusView.id R.id.cl_home_listapp||focusView.id R.id.cl_music||focusView.id R.id.cl_touping||focusView.id R.id.cl_home_healsound){viewPager.currentItem2}}if(viewPager.currentItem1){Log.d(TAG, 当前是在 vp currentItem 1 下)try {val centerShutIndexInfo: CenterShutIndexInfo? viewModel.centerShutIndexInfoLiveData.valueLog.d(TAG, centerShutIndexInfo:\({Gson().toJson(centerShutIndexInfo)})centerShutIndexInfo?.let { it-if((it.index1)it.totalNum){viewPager.currentItem2}}} catch (e: Exception) {e.printStackTrace()}}}}}return super.onKeyDown(keyCode, event)}获取当前焦点
在开发遥控器控制过程中最重要的就是知道当前焦点是哪里这样才能分析各种不可变的bug只有找到了焦点的位置针对性解决焦点问题。
这里监听窗体的焦点事件在监听KeyEvent 事件响应地方也有相关代码的。 window.decorView.findFocus()?.let { focusedView -Log.d(TAG, decorView 焦点 View 信息: 类名: \){focusedView.javaClass.name})}
四、实际开发技能分享
假使你已经具备了上面的基础知识实际在项目项目中还是会被焦点问题搞得焦头烂额、无从下手遇到问题针对性解决。 这里给出自己的部分经验。
处理焦点注意实现
需要获取焦点UI组件设置为android:focusable“true” 不需要获取焦点的组件设置为 false给每个界面显示的时候设置初始化焦点如上 onResume 方法中给对应的UI组件 requestFocus() 一次给组件设置holder.vb.root.setOnFocusChangeListener 监听事件有焦点和无焦点情绪下显示不同效果。监听onKeyDown 事件结合自己的软件业务实现不同的业务需求。注意在边角的UI组件RecycleView 的部分情形下针对UI指定 上下左右焦点保持焦点不外溢、丢失。对Banner 类型UI组件自己根据实际问题来解决因为Banner 会轮训图片、视频 等导致焦点错乱丢失情况可以具体问题具体分析RecycleView 对于边角问题处理对于行位、行首、竖方向收尾、竖方向最后一位的焦点处理。 下面会具体分析。
RecycleView 案例分析
RecycleView 会有两种情况特别注意
比如你的RecycleView 焦点在四周恰好是左边、右边、上边、下边 需要拦截如果不拦截的话焦点丢失不见了需要判断RecycleView 焦点是否在四周哪个方向做对应的业务逻辑处理。比如网格布局情况下在最左边情形下需要翻页、在最右要拦截、最下边要拦截。
情形一网格布局情况下横屏竖屏显示情况下判断焦点是否在最左边如果最左边就用viewPager 翻页处理
情形而如下判断是否边角焦点处理对应业务比如底部不让事件传递焦点定在那里不然会失去焦点。 private fun handleLightViewTopBoundary(): Boolean {// 可以转移到其他View或保持焦点val first: View viewBinding.lightRyView.getChildAt(0)if (first ! null) {first.requestFocus()return true}return false}private fun handleLightViewRightBoundary(position: Int): Boolean {// 类似处理右边边界// val lastPos: Int viewBinding.lightRyView.getAdapter()!!.getItemCount() - 1val last: View viewBinding.lightRyView.findViewHolderForAdapterPosition(position)!!.itemViewif (last ! null) {last.requestFocus()return true}return false}private fun handleLightViewLeftBoundary(position: Int): Boolean {// 类似处理左边边界// val lastPos: Int viewBinding.lightRyView.getAdapter()!!.getItemCount() - 1val last: View viewBinding.lightRyView.findViewHolderForAdapterPosition(position)!!.itemViewif (last ! null) {last.requestFocus()return true}return false}private fun handleLightViewBottomBoundary(): Boolean {// 类似处理底部边界val lastPos: Int viewBinding.lightRyView.getAdapter()!!.getItemCount() - 1val last: View viewBinding.lightRyView.findViewHolderForAdapterPosition(lastPos)!!.itemViewif (last ! null) {last.requestFocus()return true}return false}
如下如果是底部最后一行了那么就不让事件传递这样就不会丢失焦点。 在上下左右焦点都是这么处理的就是判断 或者 在边焦点时候做其他业务处理。 总结
遥控器功能开发本身就是处理焦点的问题这里简要描述了焦点基本知识、实际开发案例、注意事项。简单的UI焦点处理事件很简单的默认就支持可能需要定制焦点选中UI对于RecycleView 、banner 嵌套在Fragmetn / Dialog 或者 自嵌套 的复杂UI情形焦点很容易没有规律掌握一些基本的处理方案很重要。 遇到问题针对性解决即可。
- 上一篇: 互联网网站设计泰安网络科技公司
- 下一篇: 互联网行业网站建设做网站优化推广的好处
相关文章
-
互联网网站设计泰安网络科技公司
互联网网站设计泰安网络科技公司
- 技术栈
- 2026年03月21日
-
互联网网站模板做蛋糕网站有哪些
互联网网站模板做蛋糕网站有哪些
- 技术栈
- 2026年03月21日
-
互联网网站建设网站只能在vps里打开
互联网网站建设网站只能在vps里打开
- 技术栈
- 2026年03月21日
-
互联网行业网站建设做网站优化推广的好处
互联网行业网站建设做网站优化推广的好处
- 技术栈
- 2026年03月21日
-
互网站开发维护成本高wordpress邮箱解析
互网站开发维护成本高wordpress邮箱解析
- 技术栈
- 2026年03月21日
-
互助盘网站建设网络服务商主要包括哪些
互助盘网站建设网络服务商主要包括哪些
- 技术栈
- 2026年03月21日
