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

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

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

首先是item的代码:

  1. <view xmlns: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 代码:

  1. public class HomeItemContainer extends RelativeLayout {
  2. private Rect mBound;
  3. private Drawable mDrawable;
  4. private Rect mRect;
  5. private Animation scaleSmallAnimation;
  6. private Animation scaleBigAnimation;
  7. public HomeItemContainer(Context context) {
  8. super(context);
  9. init();
  10. }
  11. public HomeItemContainer(Context context, AttributeSet attrs, int defStyle) {
  12. super(context, attrs, defStyle);
  13. init();
  14. }
  15. public HomeItemContainer(Context context, AttributeSet attrs) {
  16. super(context, attrs);
  17. init();
  18. }
  19. protected void init() {
  20. setWillNotDraw(false);
  21. mRect = new Rect();
  22. mBound = new Rect();
  23. mDrawable = getResources().getDrawable(R.drawable.poster_shadow_4);//nav_focused_2,poster_shadow_4
  24. setChildrenDrawingOrderEnabled(true);
  25. }
  26. @Override
  27. protected void onAttachedToWindow() {
  28. super.onAttachedToWindow();
  29. }
  30. @Override
  31. public void draw(Canvas canvas) {
  32. super.draw(canvas);
  33. }
  34. @Override
  35. protected void onDraw(Canvas canvas) {
  36. if (hasFocus()) {
  37. System.out.println("HomeItemContainer focus : 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. protected void onFocusChanged(boolean gainFocus, int direction, Rect previouslyFocusedRect) {
  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. private void zoomIn() {
  60. if (scaleSmallAnimation == null) {
  61. scaleSmallAnimation = AnimationUtils.loadAnimation(getContext(), R.anim.anim_scale_small);
  62. }
  63. startAnimation(scaleSmallAnimation);
  64. }
  65. private void zoomOut() {
  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缩小的效果代码:

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <set xmlns: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:

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <RelativeLayout xmlns: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就可以实现放大而不被遮挡了。

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

Android TV上的焦点切换效果的更多相关文章

  1. Android:给ViewPager添加切换效果

    原文参照开发者官网:http://developer.android.com/training/animation/screen-slide.html#viewpager 以App的引导页为例: 首先 ...

  2. android TV选中时高亮凸显效果

    链接: http://pan.baidu.com/s/1pLjAFQ7 密码: xb8g <ignore_js_op> 360手机助手截图0410_18_02_01.png (335.64 ...

  3. Android下Fragment的动画切换效果

    效果图如下: 源码链接   :    请戳这里

  4. React-Native解决ListView 在Android手机上无吸顶效果

    stickySectionHeadersEnabled={true} stickyHeaderIndices={[0]}

  5. Android实现程序前后台切换效果

    本文演示如何在Android中实现程序前后台切换效果. 在介绍程序实现之前,我们先看下Android中Activities和Task的基础知识. 我们都知道,一个Activity 可以启动另一个Act ...

  6. Android TV listView焦点平滑移动

    先上TV上效果图 Mark下思路: package com.test.ui; import java.lang.reflect.Method; import android.annotation.Su ...

  7. 两行代码搞定Android视图扩散切换效果

    用最简单的方式来实现Android视图扩散切换效果. 一.概述 这两天时间动手撸了个视图扩散切换效果的控制器,API兼容至Android4.0,更方便我们在视图切换过程中有炫酷的过渡效果.本来是想实现 ...

  8. Android TV开发总结(五)TV上屏幕适配总结

    前言:前面几篇总结一些TV上的小Sample,开源到GitHub:https://github.com/hejunlin2013/TVSample, 点击链接,可以持续关注.今天总结下TV上屏幕适配. ...

  9. Android 自定义 ViewPager 打造千变万化的图片切换效果

    转载请标明出处:http://blog.csdn.net/lmj623565791/article/details/38026503 记得第一次见到ViewPager这个控件,瞬间爱不释手,做东西的主 ...

随机推荐

  1. App测试工具

    1.App性能测试与安全测试工具 性能测试工具:Itest(众测平台) 安全测试:Utest

  2. 64位windows系统安装javaee6.0不成功解决方案

    64位windows系统安装javaee6.0不成功解决方案 (2013-01-19 14:59:51) 转载▼ 标签: 杂谈   could not find the required versio ...

  3. js 点击 隐藏弹出层

    document.onmousedown = function(e){ var ev = document.all ? window.event : e; var _con = $("#ci ...

  4. python学习 (三十五) logging

    1  demo import logging # log level: # DEBUG # INFO # Warning # Error # CRITICAL logging.basicConfig( ...

  5. 查看进程id

    #!/usr/bin/env python # encoding: utf-8  # Date: 2018/6/16 from multiprocessing import Processimport ...

  6. 浅谈Java引用和Threadlocal的那些事

      这篇文章主要介绍了Java引用和Threadlocal的那些事,小编觉得挺不错的,现在分享给大家,也给大家做个参考.一起跟随小编过来看看吧 1 背景 某一天在某一个群里面的某个群友突然提出了一个问 ...

  7. JavaScript知识总结--引用类型(Object-Array-Function-Global-Math)

    对象(引用类型的值)是引用类型的一个实例,新对象是使用new操作符后跟一个构造函数来创建的.构造函数本身就是一个函数,该函数用于创建新对象.ECMAScript提供了很多原生引用类型(Object,A ...

  8. IOS Background 之 Background Fetch

    http://www.ithao123.cn/content-1363653.html 定期更新数据的app,比如及时通信类,微博等app. 定期后台获取,等打开后获取的快一些. 30分钟后打开手,获 ...

  9. nginx root与alias区别

    引用于文章https://blog.csdn.net/line_aijava/article/details/71473793 root: Sets the root directory for re ...

  10. WPF 绑定以基础数据类型为集合的无字段名的数据源

    WPF 绑定以基础数据类型为集合的无字段名的数据源 运行环境:Window7 64bit,.NetFramework4.61,C# 6.0: 编者:乌龙哈里 2017-02-21 我们在控件的数据绑定 ...