载请标明出处: http://blog.csdn.net/sk719887916 ,作者: skay
   由于其他网站收录,导致你无法查看本系列原创文章请点击此处 安卓TV开发(四)实现主流智能TV视频播放器UI  ;

前言:移动智能设备的发展,推动了安卓另一个领域,包括智能电视和智能家居,以及可穿戴设备的大量使用,但是这些设备上的开发并不是和传统手机开发一样,特别是焦点控制和用户操作体验上有很大的区别,本系列博文主要通过用TV播放器的实现去了解下在智能设备上的开发一个APP,实现遥控器控制焦点移动,方向键模拟鼠标,并在线完成视频直播,手机当遥控器使用等相关功能。此UI也适用于车载设备和移动智能家具设备,。

上一篇中 安卓TV开发(四)实现主流智能TV视频播放器UI     初步学习了智能电视上UI的设计,且完成了在电视上可以控制的自定义View(FocusView),在上篇结尾中提到,他并不适合在手机上使用,并且也没实现点击遥控键(KEYCODE_DPAD_CENTER)的item事件,因此本篇也将会继续完善和修复此存在的问题。

一,实现遥控器Ok键Item点击事件

1  通过观察GridView的源码其实继承了 AdapterView<T extends Adapter>这个类,其中的item事件也是实现此类的 OnItemClickListener接口

源码如下:

 /*** Interface definition for a callback to be invoked when an item in this* AdapterView has been clicked.*/public interface OnItemClickListener {/*** Callback method to be invoked when an item in this AdapterView has* been clicked.* <p>* Implementers can call getItemAtPosition(position) if they need* to access the data associated with the selected item.** @param parent The AdapterView where the click happened.* @param view The view within the AdapterView that was clicked (this*            will be a view provided by the adapter)* @param position The position of the view in the adapter.* @param id The row id of the item that was clicked.*/void onItemClick(AdapterView<?> parent, View view, int position, long id);}

以上代码不难理解 AdapterView 提供个一个回调,在我们所用到的actity中或view去实现此接口。本次可以复用以上接口,使开发者习惯安卓系统的条目监听。但由于我们的view并未继承AdapterView,而在回调必须要传入一 AdapterView的父类,因此我们自定义自己的监听器。下面我们也给FocsView定义一个条目点击事件监听器。

/*** FocusView* Interface definition for a callback to be invoked when an item in this* FocusView item has been clicked.* @author liuyongkui.* @param <T>*/public interface OnItemClickListener<T> {/*** @param mFocusView*   FoucusView.* @param view*   focus View item.* @param col*    col Num.* @param row*    row Num.* @param id*    item id.*/void onItemClick(FocusView mFocusView, View focusView,FocusItemModle<TvModle> focusItem, int Postion, int row, int col, int id);}

同理为了开发者自定义效果,我们也为focusVIew的子条目心新增一个选中事件监听器。

/*** FocusView* Interface definition for a callback to be invoked when an item in this* FocusView item has been Selected.* @author liuyongkui.* @param <T>*/public interface OnItemSelectedListener <T> {/*** @param <T>* @param mFocusView*   FoucusView.* @param view*   focus View item.* @param col*    col Num.* @param row*    row Num.* @param id*    item id.*/public void onItemSelected(FocusView metroView, View view, T modle, int col, int row, long id);}

2 上列代码发现我用了一个接口泛型,此处原因是为了提高接口的扩展性,比如 开发中你定义的MusicModle ,以上的监听就会有问题了 会拋类型转换异常,因此当我们再给接口传什么Modle,回调的时候就会返回相应的modle.

等完成了接口圆原型,再定义他为FocusView内部属性

        /** items mOnItemSelectedListener*/private OnItemSelectedListener mOnItemSelectedListener;/**  items mOnItemClickListener */private OnItemClickListener mOnItemClickListener;
 @SuppressWarnings("rawtypes")public OnItemSelectedListener<?> getmOnItemSelectedListener() {return mOnItemSelectedListener;}public void setOnItemSelectedListener(OnItemSelectedListener mOnItemSelectedListener) {this.mOnItemSelectedListener =  mOnItemSelectedListener;}

3  完成以上工作,考虑在何时调用此接口,通过要实现的目标就能知道答案,肯定是在用户点击Ok键时触发此回调,接着重写onKeyUp()事件

继续完善上篇中已实现的上下左右的键盘事件,

                case KeyEvent.KEYCODE_DPAD_CENTER:if(mOnItemClickListener != null) {mOnItemClickListener.onItemClick(this,focusItem.getFocusView(), focusItem, focusItem.getPostion(), focusItem.getRow(), focusIt                             em.getCol(), focusItem.getId());}break;}

当然到这里代码肯定会有报错,因此我的FocusITemModle 也要随之加入Position,ID等 由于本次代码无adapter,因此我个人是在focusView布局时setPosition,Id也是通通过行数和列数决定,

4 在activty中去实现此接口 ,和一般的listVIew,GrideVIew一样,但是导包必须到导入focusView的OnItemClickListener事件,值得注意的是 实现点此接口时需要我们传入object,在这里我传入: FocusItemModle<TvModle> ,和上篇有很大区别的是这次的FocusItemModle也适用了泛型,目的是为了代码灵活性。

FocusUIActivity extends Activity implements  OnItemClickListener<FocusItemModle<TvModle>>

        FocusView view = (FocusView) findViewById(R.id.focus_ui);view.setOnItemClickListener(this);

实现接口中的onItemClick()方法:

 @Overridepublic void onItemClick(FocusView mFocusView, View focusView,FocusItemModle<TvModle> focusItem, int Postion, int row, int col,long id) {Toast.makeText(getApplicationContext(), "row:" + row  + "col:" + col, 1).show();}

通过以上三步我们完善了在按键Ok时触发的事件,同理选择事件并不需要我们按键触发,而是当Item获得焦点时触发,学习了前面知识的朋友。一定会觉得再简单不过了,这里留给读者去完善。

二,实现触屏Item点击事件

  到此我们的代码还并不支持触摸点击,为了兼容手机我为此去实现触摸时触发onItemClick(),所以今天的难点又来了 因为我已经屏蔽了系统的触摸事件,因此继续完善OnTucH事件,首先拿到这样的一个实现需求,我们首先要想到 当用户点击屏幕的模块区域时通过点击的坐标,然后得到当我所在的view,然后触发OnItemClick()即可

1 首先写一个工具类,专门通过X,Y去获取点击的最小View

public final class ViewUtil {private ViewGroup view;private static Context context;/** instance */private static ViewUtil sInstance;private ViewUtil(ViewGroup view) {this.view = view;this.context =view.getContext();}/*** @return instance*/public static synchronized ViewUtil getInstance(ViewGroup view) {if (sInstance == null) {sInstance = new ViewUtil(view);}return sInstance;}/*** get Onclicked ItemView* 在重写ViewGroup使用* * @param X* @param Y* @return getView*/public static View getViewAtActivity(int x, int y) {// 从Activity里获取容器View root =((Activity)context).getWindow().getDecorView();return findViewByXY(root, x, y);}/*** get Onclicked ItemView* 在重写ViewGroup使用* * @param X* @param Y* @return getView*/public View getViewAtViewGroup(int x, int y) {return findViewByXY(view, x, y);}/*** @param view* @param x* @param y* @return*/private static View findViewByXY (View view, int x, int y) {View targetView = null;if (view instanceof ViewGroup) {// 父容器,遍历子控件ViewGroup v = (ViewGroup) view;for (int i = 0; i < v.getChildCount(); i++) {targetView = findViewByXY(v.getChildAt(i), x, y);if (targetView != null) {break;}}} else {targetView = getTouchTarget(view, x, y);}return targetView;}/*** @param view* @param x* @param y* @return*/private static View getTouchTarget(View view, int x, int y) {View targetView = null;ArrayList<View> TouchableViews = view.getTouchables();for (View child : TouchableViews) {if (isTouchPointInView(child, x, y)) {targetView = child;break;}}return targetView;}/**   * 判断view是否可以聚焦* @param view* @param x* @param y* @return*/private static boolean isTouchPointInView(View view, int x, int y) {int[] location = new int[2];view.getLocationOnScreen(location);int left = location[0];int top = location[1];int right = left + view.getMeasuredWidth();int bottom = top + view.getMeasuredHeight();if (view.isClickable() && y >= top && y <= bottom && x >= left&& x <= right) {return true;}return false;}}

2  当拿到当前的view了,但是回调需要一个Modle,因此定义一个集合,用来将view和model一一对应,当返回view,我们可以在集合里去拿出model,在FocuasView初始化onLayout布局的时,去初始化此集合。当触摸事件并且移动距离为零时,触发回调,因为上篇已经实现了触摸滑动翻页功能。

PS:转载请标明出处:http://blog.csdn.net/sk719887916,

       //将点击的view和item modle关联起来protected HashMap< View, FocusItemModle<TvModle>> maps = new HashMap<View, FocusItemModle<TvModle>>();

初始化maps

 @Overrideprotected void onLayout(boolean changed, int l, int t, int r, int b) {final int itemCount = mFocusItems.size();if (itemCount != getChildCount())throw new IllegalArgumentException("contain unrecorded child");for (int i = 0; i < itemCount; i++) {final FocusItemModle item = mFocusItems.get(i);final View childView = item.getFocusView();maps.put(childView ,item);if (childView.getVisibility() != View.GONE) {final int childLeft = getPaddingLeft() + (mColWidth + mGapWidth) * item.getCol();final int childTop = getPaddingTop() + (mRowHeight + mGapHeight) * item.getRow();final int childWidth = (mColWidth + mGapWidth) * item.getColSpan() - mGapWidth;final int childHeight = (mRowHeight + mGapHeight) * item.getRowSpan() - mGapHeight;childView.layout(childLeft, childTop, childLeft + childWidth,childTop + childHeight);}}}

3 onTouchEvent()事件里继续处理触摸非滑动逻辑,在第二篇 MotionEvent.ACTION_UP 代码中完善,实现回调onItemClick()

 case MotionEvent.ACTION_UP:final VelocityTracker velocityTracker = mVelocityTracker;velocityTracker.computeCurrentVelocity(1000);int velocityX = (int) velocityTracker.getXVelocity();int velocityY = (int) velocityTracker.getYVelocity();int row = mCurRow;int col = mCurCol;if (velocityX > SNAP_VELOCITY && mCurCol > 0) {col--;} else if (velocityX < -SNAP_VELOCITY && mCurCol < mColsCount - 1) {col++;}if (velocityY > SNAP_VELOCITY && mCurRow > 0) {row--;} else if (velocityY < -SNAP_VELOCITY && mCurRow < mRowsCount - 1) {row++;}if (row == mCurRow && col == mCurCol) {if (velocityX == 0 && velocityY == 0) {snapToDestination();}else {mOnX = (int) event.getRawX();mOnY = (int) event.getRawY();Log.e(TAG, "rawX =" +mOnX + "  rawY ="+ mOnY);//sendMotionEvent(mOnX,mOnY, KeyEvent.ACTION_UP);View onClickItem = getViewAtViewGroup(mOnX,mOnY);FocusItemModle<TvModle> onClickItemModle = maps.get(onClickItem);if(mOnItemClickListener != null && onClickItem != null) {Log.e(TAG, "View 2=" +mOnX + "  rawY 2 ="+ mOnY);row =  onClickItemModle.getCol();col =  onClickItemModle.getCol();mOnItemClickListener.onItemClick(this,onClickItem, onClickItemModle,onClickItemModle.getRow(), onClickItemModle.getPostion(), onClickItemModle.getCol(), onClickItemModle.getId());snapTo(row, col);}}}else {snapTo(row, col);if (mFocusListener != null)mFocusListener.scrollto(row, col);} if (mVelocityTracker != null) {mVelocityTracker.recycle();mVelocityTracker = null;}mTouchState = TOUCH_STATE_REST;break;

到此一切就绪了,模拟器效果:

效果:

  

综合以上代码 ,发现我们的View还是存在缺陷,上文就发现,因为没有adapter,导致我们的代码繁琐,并且也不符合一个集合框架(listView,GridView)的开发习惯和

实现逻辑。下篇我会通过上面的代码来优化,完成FcousView和Adapter结合,完成高效的UI框架,使得开发者自定义宽高,翻页动画,显示可见条数,和子item布局,下篇也会成为就是TV视图文章中的终结篇,之后将进行多媒体和直播流的相关知识,欢迎大家阅读。

转载请标明出处:http://blog.csdn.net/sk719887916,作者:skay

源码下载: https://github.com/Tamicer/FocusView

更多技术文章请关注本人微信公众号:

安卓TV开发(五) 移动智能终端UI之实现主流TV焦点可控UI相关推荐

  1. 安卓TV开发(三) 移动智能设备之实现主流TV电视盒子焦点可控UI

    前言:移动智能设备的发展,推动了安卓另一个领域,包括智能电视和智能家居,以及可穿戴设备的大量使用,但是这些设备上的开发并不是和传统手机开发一样,特别是焦点控制和用户操作体验上有很大的区别,本系列博文主 ...

  2. 安卓TV开发(七) 移动智能终端多媒体之在线解析网页视频源

    载请标明出处:http://blog.csdn.net/sk719887916/article/details/40049137,作者:skay 结束了所有UI绘制的学习,智能设备常用的应用音视频类, ...

  3. 安卓TV开发《2》开发TV应用

    本节将会总结下TV开发中的注意点,如何管理TV控制器,如何构建TV布局.如何创建TV导航. 一.处理TV硬件 为啥要处理TV硬件呢?因为TV不像其他安卓设备一样支持触摸屏,照相机.GPS之类的.这些硬 ...

  4. 安卓应用开发顶级框架大盘点,总有一款适合你

    作者 | Slava Vaniukov 译者 | 苏本如,责编 | 夕颜 封图 | CSDN下载自视觉中国 出品 | CSDN(ID:CSDNnews) 随着软件开发向移动应用的转变,越来越多的企业意 ...

  5. 一文讲解安卓应用软件开发有什么优势?

    Android系统软件是目前市场上比较常见的应用软件,为了更好地适应市场的需求,很多企业都开发了自己独有的安卓系统软件,安卓应用软件开发一般要花多少钱?还有什么好处呢? 一文讲解安卓应用软件开发有什么 ...

  6. apple tv 开发_如何跨多台Apple TV同步Apple TV的主屏幕

    apple tv 开发 If you have more than one Apple TV in your household, you probably know how annoying it ...

  7. 安卓TV开发(八) 移动智能终端多媒体爬虫技术 获取加载网页视频源

    转载请标明出处:http://blog.csdn.net/sk719887916/article/details/40049137,作者:skay 从上一篇学习中,学习了多媒体技术中的怎么去用josu ...

  8. 安卓TV开发(九) Android模拟事件 遥控器变身成鼠标来操作TV

    本文出处:http://blog.csdn.net/sk719887916/article/details/40348853,作者:skay      阅读此文建议先阅读 安卓Tv开发(二)移动智能电 ...

  9. Android TV Demo 工程,其中包含 TV 常用的自定义控件,飞框效果实现,外边框效果实现,UI 控件焦点自动处理,使 TV 开发更简单,更高效。

    TVLibraryDemo 项目地址:zhangtiansheng/TVLibraryDemo  简介:Android TV Demo 工程,其中包含 TV 常用的自定义控件,飞框效果实现,外边框效果 ...

最新文章

  1. vector 容器 动态数组总结
  2. dom4j的读写XML文件
  3. Ajax之同步请求和异步请求的区别
  4. Java基础day6
  5. P4777-[模板]扩展中国剩余定理(EXCRT)
  6. leetcode 368. 最大整除子集(dp)
  7. JDK源码(11)-Long、Short
  8. 结对编程,到底是双剑合璧还是脚趾抠地?
  9. jdbc至sql server的两种常见方法
  10. java实现评论功能_Java实现评论回复功能的完整步骤
  11. 职场五大能力之学习能力
  12. 微信小程序:九宫格抽奖
  13. Android 系统各版本新特性总结
  14. stata实现经济生态的空间杜宾模型
  15. C语言 经典例题 无重复三位数
  16. Android键盘的显示和隐藏
  17. 计算机多媒体课程教师教学心得,多媒体教学的心得体会_多媒体教学教师心得...
  18. 【基础】计算机网络相关的内容
  19. Python控制tek示波器(1)
  20. 暑假好看的日剧来啦~~

热门文章

  1. 新浪公开抵抗盛大入主 捍卫自己的独立经营权
  2. fpga——浮点数加减法
  3. python制作软件授权_python类的授权方式
  4. api php usdt 以太坊_PHP调用以太坊JSON-RPC接口创建钱包
  5. node笔记_读写excel
  6. php中json_encode和json_decode的用法
  7. OSChina 周日乱弹 —— 去应聘男友吧
  8. 加速下载必知必会-国内的镜像网站备忘
  9. codeforces 708A - Letters Cyclic Shift
  10. Opencv 给灰度图上颜色