Android Focus 总结

焦点问题

Android TV 开发主要有以下方面的问题需要注意:

  1. 焦点问题,包括焦点获取和焦点方向控制;
  2. 动画处理,针对焦点选中地方用动画提示用户;
  3. 控件运用,android SDK提供了电视开发组件lenback用于电视应用。

由于tv应用和手机的交互方式有些小不同,比如没有滑动操作,导致上拉刷新、下拉加载动作不好触发;电视应用只能靠遥控器控制选择的焦点进行交互,了解焦点相关的属性就特别重要了。这个有点像手机中的设置——智能辅助——TalkBack(针对盲人把手机连接在一个有摇杆或者可以上下左右的键设备来控制手机)。

  • 可获取焦点的属性:android:focusable = ture|false|auto ;

注:auto 表示控件可获取焦点能力按照系统默认,在这个属性值android.R.styleable#View_focusable

  • View 类:requestFocus 、 clearFocus 强制获取/清除焦点;

运用:界面中有多个默认可以获取焦点的控件,editText有时候需要第一时间获取焦点,可以用requestFocus;

  • 控制焦点移动:android:nextFocusLeft/Up/Right/Down=“某个控件id” ;

场景:可以控制控件的下一次焦点移动的地方,达到特定的目的。

  • 控制焦点移动:android:nextFocusForwardId =“某个控件id” ;

场景:当焦点从该控件消失去到下一个特定的控件,可以对比上面的四个方法。

  •  监控遥控器按键事件 onKeyDown():

   作用:可以监听遥控器的上、下、左、右、确认、返回等事件,控制焦点行为;

  1. 获取当前页面焦点控件:a.acitivity.getCurrentFocus()     b.getWindow().getDecorView().findFocus()   / view.findFocus()
  2. 场景:返回当前界面获取焦点的view或某个view及其子控件中有没有获取焦点,没有返回null。       可以在开发调试的时候进行日志输出,知道焦点的实时情况,有助于开发;还需注意这三个方法需要 绘制完成之后

        new Handler().post(new Runnable( 调用方法).start);

  •    焦点监听 view setOnFocusChangeListener(); 

     场景:监听控件的焦点变化并作出相应的业务;比如说:电视应用需要对选定的view作出放大处理,失去焦点要恢复原来形状,可以在这里处理;                    

  •  全局监听焦点变化 getViewTreeObserver().addOnGlobalFocusChangeListener();

    场景:相比较上面单个view的监听,这是当前界面全局监听焦点变化的事件,在排查焦点问题时很有用;

  • getFocusable()、isFocused()、isFocusable()、hasFocusable()

     getFocusable ——获取view的焦点模式(auto,yes,false)

     isFocused——检查当前view是否获取到焦点

     isFocusable、hasFocusable——获取view能否获取焦点的能力(能或者不能)

  • Android:descendantFocusability =“bofore/after/blockDescendant”

      针对viewGroup 相对子控件谁先可以获取焦点的能力;

系统控件中默认获取焦点的控件有哪些? 

  • 列表类控件,listView,recycleView,gridView等等;
  • button及其子类控件,radioutton, CheckedBox
  • EdtiText 

一般的,viewGroup 默认不能获取焦点,这一点要注意,但列表类控件又很特别。(图片中llayout 为true, 默认是设置过的)。

1.容器控件的view 其 focusable 都为 false,除非你设置相应可以获取焦点。
2.列表类控件,会在初始化的时候设置setFocusableInTouchMode(true)。

讨论电视中焦点的移动原理

文章参考 https://blog.csdn.net/github_33304260/article/details/80849376  

结论:系统会遍历出所有isFocusable 的视图,然后根据方向和距离,并进行遍历比较,得到最近的视图作为下一个接收焦点的视图;如果用户指定nextFocusId, 则优先找到该视图接收焦点。

焦点选中效果

 public static void zoomOut(View view){
        AnimationSet animationSet = new AnimationSet(true);
        ScaleAnimation animation = new ScaleAnimation(1.0f, ANIMATION_SCALE, 1.0f, ANIMATION_SCALE,
                Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
        animation.setDuration(500);
        animation.setFillAfter(true);
        animationSet.addAnimation(animation);
        animationSet.setFillAfter(true);
        view.clearAnimation();
        view.startAnimation(animationSet);
    }


    public static void zoomIn(View view){
        AnimationSet animationSet = new AnimationSet(true);
        ScaleAnimation animation = new ScaleAnimation(ANIMATION_SCALE, 1.0f, ANIMATION_SCALE, 1.0f,
                Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
        animation.setDuration(500);
        animation.setFillAfter(true);
        animationSet.addAnimation(animation);
        animationSet.setFillAfter(true);
        view.startAnimation(animationSet);

    }
  .itemView.setOnFocusChangeListener(new View.OnFocusChangeListener() {
            @Override
            public void onFocusChange(View v, boolean hasFocus) {
                if(hasFocus){
                    AnimationUtil.zoomOut(v);
      添加选中边框色 
                   deviceAlarmMessageListHolder.mRelativeRootLayout.setBackground(mContext.getResources().getDrawable(R.drawable.alarm_item_selected_border_shage_bg));
                }else {
                    AnimationUtil.zoomIn(v);
                    deviceAlarmMessageListHolder.mRelativeRootLayout.setBackground(mContext.getResources().getDrawable(R.drawable.alarm_item_unselected_border_shage_bg));
                }
            }
        });

Google TV开发Leanback  

 https://developer.android.com/tv  是电视应用UI设计规范和一些建议文章;

优点:android.support.v17.leanback 软件包提供的 API 支持在电视设备上构建用户界面。它为电视应用提供了一些重要的小部件和现成的UI框架。比如可以自动聚焦屏幕中间的HorizontalGridView、VerticalGridView ;还提供了初次启动使用介绍OnboardingFragment 布局、抽屉目录导航界面BrowseFragment、展示Item的详情界面 DetailFragment、播放视频界面VideoFragment等等。

缺点:上述提供的已有的布局,其扩展性不太好,风格和样式较为固定,不能进行大的变化。或者是需要较多的代码才能实现,不是很划算。

分析:

BrowseFragment 的描述:
 * A fragment for creating Leanback browse screens. It is composed of a
 * RowsFragment and a HeadersFragment.
 * <p>
 * A BrowseFragment renders the elements of its {@link ObjectAdapter} as a set
 * of rows in a vertical list. The elements in this adapter must be subclasses
 * of {@link Row}.

MainFragmentRowsAdapter 中的RowPresenter.ViewHolder 已经定义好了数据源,即Row。Row包含了一个内部数据实体类HeaderItem,包含了private final String mName; private CharSequence mDescription; private CharSequence mContentDescription;所以当我们用BrowseFragment时候,就不必须使用这个样式的数据,无法去改变。

如果要想自定义数据源和布局,需要继承Presenter,在这里去实现。重写onCreateViewHolder 和 onBindViewHolder,
这里的Presenter 类似MVP思想中的P层,P持有了数据源和view对象,并在这里组装。还要注意,Presenter使用的是ObjectAdapter,不是通过Position进行数据绑定的,所以这一点比较特殊。
 

猜你喜欢

转载自blog.csdn.net/sjh_389510506/article/details/88238623