• Android TV 开发(5)


    本文来自网易云社区

    作者:孙有军


    问题3:TV launcher中没有入口图标

    如果需要出现入口图标,你必须要在AndroidManifest中配置action为android.intent.action.MAIN,category为android.intent.category.LAUNCHER的Activity。该配置与上面的LEANBACK_LAUNCHER不冲突,可以对入口Activity配置LAUNCHER,之后一个页面配置LEANBACK_LAUNCHER,配置如下:

    <activity
        android:name=".WelcomeActivity"
        android:label="@string/app_name"
        android:screenOrientation="landscape">
        <intent-filter>
            <action android:name="android.intent.action.MAIN"/>
    
            <category android:name="android.intent.category.LEANBACK_LAUNCHER"/>
        </intent-filter></activity>


    问题4:TV launcher中的图标不清晰,太糊

    如果直接将手机app的launcher图标直接使用到TV中,则图标会拉伸,由于TV的图标往往都比较大,拉伸后就会变糊,因此需要重新切launcher图标,手机里面是4848, 7272,9696等,而tv需要更大的尺寸,虽然没有在官方找到建议的尺寸,但是这里推荐一个尺寸180180,可以多个文件夹都放同一个图标,这样界面加载的图标就会变得清晰。



    问题5:遥控器导航下一个不是自己希望导航的控件

    系统中如果界面中有多个可focus的控件,上下左右导航,则会找到与当前控件最邻近的控件作为下一个选中的控件,因此如果你确切想指定下一个导航的控件,则可以指定下一个控件的ID,只要该id在当前显示的界面中,比如向上 view1.setNextFocusUpId(R.id.dial_tab);


    问题6:官方VerticalGridFragment加载后,默认选中第一个,但是第一个占据了整个界面。

    该问题应该是官方的一个bug,如果不是第一次加载VerticalGridFragment,则不会出现该问题,并且我尝试了多个版本的,都会出现该问题,原因是选中后系统会在在选中的控件后插入两帧NonOverlappingView,插入的布局代码如下:


    <merge xmlns:android="http://schemas.android.com/apk/res/android">
        <android.support.v17.leanback.widget.NonOverlappingView      
          android:id="@+id/lb_shadow_normal"       
           android:layout_width="match_parent"      
             android:layout_height="match_parent"      
               android:background="@drawable/lb_card_shadow_normal" />
        <android.support.v17.leanback.widget.NonOverlappingView      
          android:id="@+id/lb_shadow_focused"      
            android:layout_width="match_parent"        
            android:layout_height="match_parent"        
            android:background="@drawable/lb_card_shadow_focused"     
               android:alpha="0" />
    
    </merge>

    该布局插入了两帧NonOverlappingView,每一帧都使用了一个.9图标作为背景,而当系统第一次加载时,最终第一个选中的控件宽高计算错误,计算成了一个16777211类似的一个值,远远超出了界面的大小,解决方案如下:

    方案1,将布局中的match_parent改为wrap_content 方案2,对VerticalGridFragment中使用的VerticalGridPresenter设置ShadowEnabled,如gridPresenter.setShadowEnabled(false); 方案3,替换掉.9图片


    问题7:VerticalGridFragment加载后,选中放大效果不居中

    在VerticalGridFragment,如果ArrayObjectAdapter使用的是自己实现的Presenter,而Presenter使用的不是系统提供的ImageCardView,则会导致选中效果不居中,当选中效果放大后会向右向下覆盖,而不是在当前位置放大覆盖四周。

    该问题,我查了对应的style、只有针对ImageCardView的style,我也还没有仔细研究怎么调整,不过这里给出一个避免的方案,对VerticalGridPresenter选中后的高亮效果选择为不放大,如new VerticalGridPresenter(FocusHighlight.ZOOM_FACTOR_NONE)。


    问题8:VerticalGridFragment顶层控件不能向上导航

    比如在联系人列表页第一行时,遥控器向上不能导航,比如不能导航到拨号,好友控件,该问题其实是被系统给拦截了。系统的VerticalGridFragment加载了lb_vertical_grid_fragment布局,该布局包含了一个BrowseFrameLayout,对 BrowseFrameLayout设置了setOnFocusSearchListener。如下:

       private void setupFocusSearchListener() {
            BrowseFrameLayout browseFrameLayout = (BrowseFrameLayout) getView().findViewById(
                    R.id.grid_frame);
            browseFrameLayout.setOnFocusSearchListener(getTitleHelper().getOnFocusSearchListener());
        }

    当系统在VerticalGridPresenter最顶层时,向上找最近一个控件时,发现当前布局已经没有控件,则会向父布局查找,代码如下:

    public View focusSearch(View focused, int direction) {   
     if (isRootNamespace()) {        
     // root namespace means we should consider ourselves the top of the
            // tree for focus searching; otherwise we could be focus searching
            // into other tabs.  see LocalActivityManager and TabHost for more info
            return FocusFinder.getInstance().findNextFocus(this, focused, direction);
        } else if (mParent != null) {       
         return mParent.focusSearch(focused, direction);
        }    return null;
    }

    而VerticalGridPresenter的父布局则是BrowseFrameLayout,因此最终执行的是上面设置的getTitleHelper().getOnFocusSearchListener(),我们去看看改listener:

    private final BrowseFrameLayout.OnFocusSearchListener mOnFocusSearchListener =      
          new BrowseFrameLayout.OnFocusSearchListener() {   
               @Override
            public View onFocusSearch(View focused, int direction) {      
                  if (focused != mTitleView && direction == View.FOCUS_UP) {        
                          return mTitleView;
                }           
                 final boolean isRtl = ViewCompat.getLayoutDirection(focused) ==
                        View.LAYOUT_DIRECTION_RTL;          
                          final int forward = isRtl ? View.FOCUS_LEFT : View.FOCUS_RIGHT;       
                               if (mTitleView.hasFocus() && direction == View.FOCUS_DOWN || direction == forward) {   
                                            return mSceneRoot;
                }        
                    return null;
            }
    };

    发现问题所在没有,当focused != mTitleView && direction == View.FOCUS_UP时,强制指定了mTitleView,就算没有没有显示title,效果也一样。我认为这应该算系统的一个bug,那怎么解决呐?

    我们可以重写一个一模一样的lb_vertical_grid_fragment,自己写的布局会覆盖掉系统的布局,再将BrowseFrameLayout重写成我们自己的BrowseFrameLayout。如下

    public class BrowseFrameLayout extends android.support.v17.leanback.widget.BrowseFrameLayout {    public BrowseFrameLayout(Context context) {        super(context);
        }    public BrowseFrameLayout(Context context, AttributeSet attrs) {        super(context, attrs);
        }    public BrowseFrameLayout(Context context, AttributeSet attrs, int defStyle) {        super(context, attrs, defStyle);
        }    /**
         * Sets a {@link OnFocusSearchListener}.
         */
        public void setOnFocusSearchListener(OnFocusSearchListener listener) {
    
        }
    }


    问题9:VerticalGridFragment内容未占满整个屏幕

     <!--BrowseFragment, RowsFragment, DetailsFragment padding 左边的距离</item>-->
    <item name="browsePaddingStart">@dimen/lb_browse_padding_start</item>
    <!--BrowseFragment, RowsFragment, DetailsFragment padding 右边的距离</item>-->
    <item name="browsePaddingEnd">@dimen/lb_browse_padding_end</item>
    <!--BrowseFragment padding 顶部的距离</item>-->
    <item name="browsePaddingTop">@dimen/lb_browse_padding_top</item>
    <!--BrowseFragment padding 底部的距离</item>-->
    <item name="browsePaddingBottom">@dimen/lb_browse_padding_bottom</item>
    <!--start margin of RowsFragment inside BrowseFragment when HeadersFragment is visible</item>-->
    <item name="browseRowsMarginStart">@dimen/lb_browse_rows_margin_start</item>
    <!--top margin of RowsFragment inside BrowseFragment when BrowseFragment title is visible</item>-->
    <item name="browseRowsMarginTop">@dimen/lb_browse_rows_margin_top</item>

    如果你使用的是BrowseFragment,则控制上述的边距,如果你使用的是VerticalGridFragment, 则复写itemsVerticalGridStyle,他也使用了上述定义的值,也可以直接设置具体的值:

    <style name="ItemsVerticalGridStyle" parent="@style/Widget.Leanback.GridItems.VerticalGridView">
        <item name="horizontalMargin">@dimen/gap_12_dp</item>
        <item name="verticalMargin">@dimen/gap_12_dp</item>
    
        <item name="android:focusable">true</item>
        <item name="android:focusableInTouchMode">true</item>
        <item name="android:paddingStart">?attr/browsePaddingStart</item>
        <item name="android:paddingEnd">?attr/browsePaddingEnd</item>
        <item name="android:paddingBottom">@dimen/lb_vertical_grid_padding_bottom</item>
        <item name="android:paddingTop">?attr/browseRowsMarginTop</item>
        <item name="android:gravity">center_horizontal</item>
        <item name="focusOutFront">true</item>
    </style>

    样式调整

    如果你需要对VerticalGridFragment的某些样式进行调整,你可以重新定义一个Theme继承自Theme.Leanback,这里我们大致写其中几个效果。可以控制VerticalGridFragment的内容的四周的边距,也可以控制ImageCardView的视觉效果。

    <style name="AppTheme" parent="@style/Theme.Leanback">
    
        <!--BrowseFragment, RowsFragment, DetailsFragment padding 左边的距离</item>-->
        <item name="browsePaddingStart">@dimen/lb_browse_padding_start</item>
        <!--BrowseFragment, RowsFragment, DetailsFragment padding 右边的距离</item>-->
        <item name="browsePaddingEnd">@dimen/lb_browse_padding_end</item>
        <!--BrowseFragment padding 顶部的距离</item>-->
        <item name="browsePaddingTop">@dimen/lb_browse_padding_top</item>
        <!--BrowseFragment padding 底部的距离</item>-->
        <item name="browsePaddingBottom">@dimen/lb_browse_padding_bottom</item>
        <!--start margin of RowsFragment inside BrowseFragment when HeadersFragment is visible</item>-->
        <item name="browseRowsMarginStart">@dimen/lb_browse_rows_margin_start</item>
        <!--top margin of RowsFragment inside BrowseFragment when BrowseFragment title is visible</item>-->
        <item name="browseRowsMarginTop">@dimen/lb_browse_rows_margin_top</item>
        <!--fading edge length of start of browse row when HeadersFragment is visible</item>-->
        <item name="browseRowsFadingEdgeLength">@dimen/lb_browse_rows_fading_edge</item>
    
        <item name="baseCardViewStyle">@style/BaseCardViewStyle</item>
    
        <item name="overlayDimMaskColor">@color/transparent</item>
        <item name="overlayDimActiveLevel">@fraction/lb_view_active_level</item>
        <!--控制每一个item 背景投影</item>-->
        <item name="overlayDimDimmedLevel">0%</item>
    
        <item name="itemsVerticalGridStyle">@style/ItemsVerticalGridStyle</item>
    </style>
    
    <style name="BaseCardViewStyle" parent="@style/Widget.Leanback.BaseCardViewStyle">
        <item name="cardForeground">@color/transparent</item>
        <item name="cardBackground">@color/transparent</item>
    </style>
    
    <style name="ItemsVerticalGridStyle" parent="@style/Widget.Leanback.GridItems.VerticalGridView">
        <item name="horizontalMargin">@dimen/gap_12_dp</item>
        <item name="verticalMargin">@dimen/gap_12_dp</item>
    
        <item name="android:focusable">true</item>
        <item name="android:focusableInTouchMode">true</item>
        <item name="android:paddingStart">?attr/browsePaddingStart</item>
        <item name="android:paddingEnd">?attr/browsePaddingEnd</item>
        <item name="android:paddingBottom">@dimen/lb_vertical_grid_padding_bottom</item>
        <item name="android:paddingTop">?attr/browseRowsMarginTop</item>
        <item name="android:gravity">center_horizontal</item>
        <item name="focusOutFront">true</item>
    </style>
    
    <style name="ImageCardViewInfoAreaStyle" parent="@style/Widget.Leanback.ImageCardView.InfoAreaStyle">
        <item name="android:background">@null</item>
    </style>
    
    <style name="ImageCardViewStyle" parent="@style/Widget.Leanback.ImageCardViewStyle">
        <item name="cardBackground">@color/transparent</item>
    </style>


    网易云免费体验馆,0成本体验20+款云产品! 


    更多网易研发、产品、运营经验分享请访问网易云社区


    相关文章:
    【推荐】 认识用户访谈
    【推荐】 SpringBoot入门(四)——自动配置

  • 相关阅读:
    测试人员在软件开发过程中的任务是什么?
    python关于文件操作
    字符编码
    内置方法
    数据类型的基本使用
    Python的流程控制
    Python与用户相交互
    编程语言的发展史
    计算机的五大组成
    可迭代对象 迭代器对象 生成器对象
  • 原文地址:https://www.cnblogs.com/163yun/p/9707622.html
Copyright © 2020-2023  润新知