转载:http://blog.csdn.net/wzlas111/article/details/39741091

Android TV上的焦点凸显特效相信大家都看到过,那么我们就来实现它吧,首先上张效果图。

Android TV上的焦点切换效果_第1张图片

先说一下实现原理,主要通过重写RelativeLayout实现item,之后在其中加入scalanimation动画效果。刚开始处理时,还是发现了一些问题,比如item放大后会被其他item遮挡,如何添加选中边框等等,以及动画的实现等等。下面放上实现细节。

首先是item的代码:

[html] view plain copy
  1. <viewxmlns:android="http://schemas.android.com/apk/res/android"
  2. android:id="@+id/item"
  3. android:layout_width="@dimen/home_channel_item_width"
  4. android:layout_height="@dimen/home_channel_item_height"
  5. class="com.eastelsoft.tv.widget.home.HomeItemContainer"
  6. android:clickable="true"
  7. android:focusable="true"
  8. android:focusableInTouchMode="true"
  9. android:clipChildren="false"
  10. android:clipToPadding="false">
  11. <com.eastelsoft.tv.widget.ESImageView
  12. android:id="@+id/img"
  13. android:layout_width="fill_parent"
  14. android:layout_height="fill_parent"
  15. android:background="@drawable/holder_nor"
  16. android:duplicateParentState="true"
  17. android:scaleType="fitXY"/>
  18. <!---->
  19. <com.eastelsoft.tv.widget.ESImageView
  20. android:id="@+id/hover"
  21. android:layout_width="fill_parent"
  22. android:layout_height="fill_parent"
  23. android:contentDescription="@string/desc"
  24. android:duplicateParentState="true"
  25. android:scaleType="fitXY"
  26. android:src="@drawable/sl_image_home_navigator"/>
  27. <TextView
  28. android:id="@+id/text"
  29. android:layout_width="fill_parent"
  30. android:layout_height="wrap_content"
  31. android:layout_alignParentBottom="true"
  32. android:layout_marginBottom="@dimen/home_item_text_margin"
  33. android:layout_marginLeft="@dimen/home_item_text_margin"
  34. android:layout_marginRight="@dimen/home_item_text_margin"
  35. android:ellipsize="marquee"
  36. android:gravity="bottom|right|center"
  37. android:includeFontPadding="false"
  38. android:marqueeRepeatLimit="5"
  39. android:maxWidth="@dimen/px310"
  40. android:shadowColor="#88333333"
  41. android:shadowDx="2.0"
  42. android:shadowDy="2.0"
  43. android:shadowRadius="2.0"
  44. android:singleLine="true"
  45. android:textColor="#ffffffff"/>
  46. </view>

这里定义了一个自定义view,代码在后面放上,每个item里添加了一个img,用于放置内容图片,一个hover,用于显示选中的边框,以及一个text,显示一些文字说明。

hover的src是一个selector drawable,当未focus时,它的背景是tansparent,当focus,放入外框图片。

自定义的HomeItemContainer 代码:

[java] view plain copy
  1. publicclassHomeItemContainerextendsRelativeLayout{
  2. privateRectmBound;
  3. privateDrawablemDrawable;
  4. privateRectmRect;
  5. privateAnimationscaleSmallAnimation;
  6. privateAnimationscaleBigAnimation;
  7. publicHomeItemContainer(Contextcontext){
  8. super(context);
  9. init();
  10. }
  11. publicHomeItemContainer(Contextcontext,AttributeSetattrs,intdefStyle){
  12. super(context,attrs,defStyle);
  13. init();
  14. }
  15. publicHomeItemContainer(Contextcontext,AttributeSetattrs){
  16. super(context,attrs);
  17. init();
  18. }
  19. protectedvoidinit(){
  20. setWillNotDraw(false);
  21. mRect=newRect();
  22. mBound=newRect();
  23. mDrawable=getResources().getDrawable(R.drawable.poster_shadow_4);//nav_focused_2,poster_shadow_4
  24. setChildrenDrawingOrderEnabled(true);
  25. }
  26. @Override
  27. protectedvoidonAttachedToWindow(){
  28. super.onAttachedToWindow();
  29. }
  30. @Override
  31. publicvoiddraw(Canvascanvas){
  32. super.draw(canvas);
  33. }
  34. @Override
  35. protectedvoidonDraw(Canvascanvas){
  36. if(hasFocus()){
  37. System.out.println("HomeItemContainerfocus:true");
  38. super.getDrawingRect(mRect);
  39. mBound.set(-39+mRect.left,-39+mRect.top,39+mRect.right,39+mRect.bottom);
  40. mDrawable.setBounds(mBound);
  41. canvas.save();
  42. mDrawable.draw(canvas);
  43. canvas.restore();
  44. }
  45. super.onDraw(canvas);
  46. }
  47. @Override
  48. protectedvoidonFocusChanged(booleangainFocus,intdirection,RectpreviouslyFocusedRect){
  49. super.onFocusChanged(gainFocus,direction,previouslyFocusedRect);
  50. if(gainFocus){
  51. bringToFront();
  52. getRootView().requestLayout();
  53. getRootView().invalidate();
  54. zoomOut();
  55. }else{
  56. zoomIn();
  57. }
  58. }
  59. privatevoidzoomIn(){
  60. if(scaleSmallAnimation==null){
  61. scaleSmallAnimation=AnimationUtils.loadAnimation(getContext(),R.anim.anim_scale_small);
  62. }
  63. startAnimation(scaleSmallAnimation);
  64. }
  65. privatevoidzoomOut(){
  66. if(scaleBigAnimation==null){
  67. scaleBigAnimation=AnimationUtils.loadAnimation(getContext(),R.anim.anim_scale_big);
  68. }
  69. startAnimation(scaleBigAnimation);
  70. }
  71. }




注意onFocusChanged方法,为防止item被其他item遮挡,先调用bringToFront方法,使此item处于最上层,之后调用父view的方法进行重新绘制,其实注意一点,item必须处于同一父view中,否则requestLayout和invalidate可能会不起作用,只适用于RelativeLayout布局,经测试LinearLayout不适用。

顺便放上一个scaleanimation缩小的效果代码:

[html] view plain copy
  1. <?xmlversion="1.0"encoding="utf-8"?>
  2. <setxmlns:android="http://schemas.android.com/apk/res/android"
  3. android:fillAfter="false"
  4. android:fillBefore="true"
  5. android:shareInterpolator="false">
  6. <scale
  7. android:duration="200"
  8. android:fromXScale="1.1"
  9. android:fromYScale="1.1"
  10. android:interpolator="@android:anim/accelerate_decelerate_interpolator"
  11. android:pivotX="50.0%"
  12. android:pivotY="50.0%"
  13. android:repeatCount="0"
  14. android:toXScale="1.0"
  15. android:toYScale="1.0"/>
  16. </set>


里面的属性就不详细介绍了,有兴趣的可以自己谷歌。

最后放上item的父view:

[html] view plain copy
  1. <?xmlversion="1.0"encoding="utf-8"?>
  2. <RelativeLayoutxmlns:android="http://schemas.android.com/apk/res/android"
  3. android:layout_width="match_parent"
  4. android:layout_height="match_parent"
  5. android:orientation="horizontal"
  6. android:padding="10dp"
  7. android:clipChildren="false"
  8. android:clipToPadding="false">
  9. <include
  10. android:id="@+id/channel_0"
  11. android:layout_width="@dimen/home_channel_item_width"
  12. android:layout_height="@dimen/home_channel_item_height"
  13. layout="@layout/home_page_channel_item"
  14. android:layout_alignParentLeft="true"
  15. android:layout_alignParentTop="true"
  16. android:layout_margin="3dp"/>
  17. <include
  18. android:id="@+id/channel_1"
  19. android:layout_width="@dimen/home_channel_item_width"
  20. android:layout_height="@dimen/home_channel_item_height"
  21. layout="@layout/home_page_channel_item"
  22. android:layout_below="@id/channel_0"
  23. android:layout_alignLeft="@id/channel_0"/>
  24. <include
  25. android:id="@+id/channel_2"
  26. android:layout_width="@dimen/home_channel_item_width"
  27. android:layout_height="@dimen/home_channel_item_height"
  28. layout="@layout/home_page_channel_item"
  29. android:layout_toRightOf="@id/channel_0"
  30. android:layout_alignTop="@id/channel_0"
  31. android:layout_marginRight="3dp"
  32. android:layout_marginBottom="3dp"/>
  33. <include
  34. android:id="@+id/channel_3"
  35. android:layout_width="@dimen/home_channel_item_width"
  36. android:layout_height="@dimen/home_channel_item_height"
  37. layout="@layout/home_page_channel_item"
  38. android:layout_alignLeft="@id/channel_2"
  39. android:layout_below="@id/channel_2"/>
  40. <include
  41. android:id="@+id/channel_4"
  42. android:layout_width="@dimen/home_channel_item_width"
  43. android:layout_height="@dimen/home_channel_item_height"
  44. layout="@layout/home_page_channel_item"
  45. android:layout_toRightOf="@id/channel_2"
  46. android:layout_alignTop="@id/channel_2"
  47. android:layout_marginRight="3dp"
  48. android:layout_marginBottom="3dp"/>
  49. <include
  50. android:id="@+id/channel_5"
  51. android:layout_width="@dimen/home_channel_item_width"
  52. android:layout_height="@dimen/home_channel_item_height"
  53. layout="@layout/home_page_channel_item"
  54. android:layout_alignLeft="@id/channel_4"
  55. android:layout_below="@id/channel_4"/>
  56. <include
  57. android:id="@+id/channel_6"
  58. android:layout_width="@dimen/home_channel_item_width"
  59. android:layout_height="@dimen/home_channel_item_height"
  60. layout="@layout/home_page_channel_item"
  61. android:layout_toRightOf="@id/channel_4"
  62. android:layout_alignTop="@id/channel_4"
  63. android:layout_marginRight="3dp"
  64. android:layout_marginBottom="3dp"/>
  65. <include
  66. android:id="@+id/channel_7"
  67. android:layout_width="@dimen/home_channel_item_width"
  68. android:layout_height="@dimen/home_channel_item_height"
  69. layout="@layout/home_page_channel_item"
  70. android:layout_alignLeft="@id/channel_6"
  71. android:layout_below="@id/channel_6"/>
  72. <include
  73. android:id="@+id/channel_8"
  74. android:layout_width="@dimen/home_channel_item_width"
  75. android:layout_height="@dimen/home_channel_item_height"
  76. layout="@layout/home_page_channel_item"
  77. android:layout_toRightOf="@id/channel_6"
  78. android:layout_alignTop="@id/channel_6"
  79. android:layout_marginRight="3dp"
  80. android:layout_marginBottom="3dp"/>
  81. <include
  82. android:id="@+id/channel_9"
  83. android:layout_width="@dimen/home_channel_item_width"
  84. android:layout_height="@dimen/home_channel_item_height"
  85. layout="@layout/home_page_channel_item"
  86. android:layout_alignLeft="@id/channel_8"
  87. android:layout_below="@id/channel_8"/>
  88. </RelativeLayout>

这里我定义了10个item,注意RelativeLayout的两个属性,clipChildren设置false,让children view可以超出自身所设置的大小,clipToPadding设置为false,让children view可以使用padding 的位置进行绘制,有了这2个属性,item就可以实现放大而不被遮挡了。

好了,焦点特效的教程就说到这里了,有问题可以在评论中反馈。

更多相关文章

  1. Android JUnit Test——批量运行测试代码
  2. listview 属性 小结
  3. 在 Android 使用 Support Annotations 注解优化代码
  4. Android判断网络连接是否可用(代码)
  5. Android属性动画完全解析(上),初识属性动画的基本用法
  6. Android中使用代码开关GPS、移动网络(GPRS)、WiFi
  7. Android 使用反射机制获取或设置系统属性(SystemProperties)

随机推荐

  1. 裸辞之后,我心里发慌了!
  2. 入职系列|新入职一家公司如何快速熟悉工作
  3. 我用python破解了同事的加密压缩包!
  4. 天猫双11数据过于完美?我们用python来看看
  5. 说点掏心窝子的话。
  6. 我被创业导师 PUA 了!
  7. 别再问如何用Python提取PDF内容了!
  8. 入职工作之后,我才明白的事。
  9. Python数据分析实战:缺失值处理
  10. 数据分析实战:母婴商品分析