首先,给出整个代码的效果图:

这是整个壁纸库应用的效果图,项目地址在这里

一、GridView的介绍:

官网地址

Gridview是一个ViewGroup,它展示的是一个二维的,可滑动的表格.这个表格的item是自动插入的布局,默认使用一个ListAdapter容器。

1.GridView填充数据,这个东西网上的内容太多了,这里不再赘述,只是有一个点需要注意一下:

gridview在笔者实现放大和缩小动画效果的过程中,为了保持选中的item属于最后执行的效果,重写了一下Gridview的getChildDrawingOrder()方法;同时为了避免Gridview在测量item的时候过渡绘制,导致界面卡顿,重写了onMeasure()方法,这里对此作出解释。

代码如下:

/**

* Created by fengjw on 2018/3/12.

*/

public class MyGridView extends GridView {

public boolean isOnMeasure;

public MyGridView(Context context, AttributeSet attrs) {

super(context, attrs);

setChildrenDrawingOrderEnabled(true); //这里设置为true才能调用getChildDrawingOrder()方法

}

@Override

public void setSelection(int position) {

Constants.debug("MyGridView setSelection position : " + position);

Constants.position = position;

super.setSelection(position);

}

@Override

protected void setChildrenDrawingOrderEnabled(boolean enabled) {

super.setChildrenDrawingOrderEnabled(enabled);

}

@Override

protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

isOnMeasure = true;

super.onMeasure(widthMeasureSpec, heightMeasureSpec);

}

@Override

protected void onLayout(boolean changed, int l, int t, int r, int b) {

isOnMeasure = false;

super.onLayout(changed, l, t, r, b);

}

@Override

protected int getChildDrawingOrder(int childCount, int i) {

if (this.getSelectedItemPosition() != -1){ //不选中默认为-1(INVALID_POSITION),一般从0开始

if (i + this.getFirstVisiblePosition() == this.getSelectedItemPosition()){//getFirstVisiblePosition获得的是第一个item的位置

return childCount - 1;

}

if (i == childCount - 1){

return this.getSelectedItemPosition() - this.getFirstVisiblePosition();

}

}

return i;

}

}【关于避免过度测绘的问题, 请看这里】

一般来说,GridView的绘制顺序是自上而下的,这样会导致后面的item覆盖了前面的item,所以我们就重写getChildDrawingOrder()方法来改变绘制的顺序。

实现的逻辑是这样的:当我们选中某个item的时候,当前item 也就是i+this.getFirstVisiblePosition的值如果等于选中的position,那么就return childCount -1;也就是最后一个item;不然的话就返回当前的item。这样就会让最后一个绘制的item是我们选择的item。

2.GridView的常用方法介绍:

常用参数:

columnWidth:设置每列固定宽度

gravity:设置每个item的中心

horizontalSpacing:定义水平行间距

numColumns:设置每列显示的数目

stretchMode:定义如何使用多余的空空间.

verticalSpacing:定义垂直行间距

get常用方法:

getNumColumns:得到grid每列的数目

set常用方法:

setNumColumns:设置每列显示的数目

setOnKeyListener:gridview作为一个view的按键监听

setOnItemClickListener:gridview内部item的点击监听

setOnItemSelectedListener:gridview内部选中的监听

setAdapter:设置adapter

setFocusable:设置gridview是否获得焦点

另一个是gridview的刷新:

gridview的刷新主要通过两种方式:

a.setAdapter来刷新容器内容

b.使用容器依赖的Adapter的notifyDataSetChanged().

二、GridView的使用:

1.首先设置一个GridView在资源文件中,并使用自定义MyGridView来extends GridView,重写一些方法。

scrollbars:设置为none,不让侧边的滚动条出现。

listSelector设置的目的是为了消除选中的item的背景黄色。

2.在onCreate中设置Gridiveiw的属性,因为是TV开发,我们这里主要注意焦点的位置及处理。

private void initGridView() {

mGridAdapter = new GridAdapter(this, mList, gridview);

gridview.setAdapter(mGridAdapter);

gridview.setOnKeyListener(new GridViewOnKeyListener());

gridview.setOnItemClickListener(new GridViewOnItemClickListener());

gridview.setOnItemSelectedListener(new GridViewOnItemSelectedListener());

}

如最开始的UI效果图,我们在离开gridview和进入gridview的时候,要手动进行focus的设置。为了记录原来离开时Focus的位置,我们定义一个全局的变量,如图:

在onItemSelectedListener中,我们每次进行一次改变当前item的操作,都记录一下position:

private class GridViewOnItemSelectedListener implements AdapterView.OnItemSelectedListener{

@Override

public void onItemSelected(AdapterView> parent, View view, int position, long id) {

Constants.debug("onItemSelected position : " + position);

Constants.position = position;

currentSelectPosition = position;

mGridAdapter.setSelection(position);

}

@Override

public void onNothingSelected(AdapterView> parent) {

Constants.debug("onNothingSelected");

mGridAdapter.setSelection(-2);

}

}

而每次按键的时候,都会响应onKey()操作,我们在GridView的onkey监听中做一下position的处理:

private class GridViewOnKeyListener implements View.OnKeyListener{

@Override

public boolean onKey(View v, int keyCode, KeyEvent event) {

Constants.debug("GridViewOnKeyListener onKey()");

if (event.getAction() == KeyEvent.ACTION_DOWN){

if (keyCode == KeyEvent.KEYCODE_DPAD_UP ){//这里是按键向上的操作

if (currentSelectPosition == 3){ //当前选中的position

mGridAdapter.setSelection(-2);

mMainTopMarketRlRoot.setFocusable(false);

mMainTopHomeRlRoot.setFocusable(false);

mMainArrowUpRlRoot.setVisibility(View.INVISIBLE);

mMainArrowDownRlRoot.setVisibility(View.INVISIBLE);

wifiFg.getView().setFocusable(true);

}

if (currentSelectPosition >= 0 && currentSelectPosition <= 2){

Constants.debug(".........");

// Constants.position = -2;

// currentSelectPosition = -2;

mGridAdapter.setSelection(-2);

mMainTopMarketRlRoot.setFocusable(true);

mMainTopHomeRlRoot.setFocusable(false);

mMainArrowUpRlRoot.setVisibility(View.INVISIBLE);

mMainArrowDownRlRoot.setVisibility(View.INVISIBLE);

}else if (currentSelectPosition > 11){

mMainArrowUpRlRoot.setVisibility(View.VISIBLE);

mMainArrowDownRlRoot.setVisibility(View.INVISIBLE);

}else if (currentSelectPosition >= 8 && currentSelectPosition <=11){

mMainArrowUpRlRoot.setVisibility(View.VISIBLE);

mMainArrowDownRlRoot.setVisibility(View.VISIBLE);

}else if (currentSelectPosition >= 4 && currentSelectPosition <=7){

mMainArrowUpRlRoot.setVisibility(View.INVISIBLE);

mMainArrowDownRlRoot.setVisibility(View.VISIBLE);

}

}

if (keyCode == KeyEvent.KEYCODE_DPAD_DOWN){

if (currentSelectPosition >= 8 && currentSelectPosition <= 11){

mMainArrowUpRlRoot.setVisibility(View.VISIBLE);

mMainArrowDownRlRoot.setVisibility(View.INVISIBLE);

}else if (currentSelectPosition >= 4 && currentSelectPosition <= 7){

mMainArrowUpRlRoot.setVisibility(View.VISIBLE);

mMainArrowDownRlRoot.setVisibility(View.VISIBLE);

}

}

}

return false;

}

}

同时,我们要更新GridView内容,通过在GridAdapter中设置一个方法体来实现:

public void setSelection(int position){

selectItem = position;

Constants.debug("selectItem : " + selectItem);

settingPosition = mPreference.loadSharedPreferences("settingPosition", -2);

Constants.debug("----------------------");

Constants.debug("settingPosition : " + settingPosition);

Constants.debug("----------------------");

super.notifyDataSetChanged();//刷新adapter

}

刷新adapter会调用getView方法,从而实现数据的改变操作。

同理,当我们在进入GridView的时候,设置GridView的setFocusable为true,并调用GridAdapter的setSelection方法来达到更新效果。

三、fragment焦点改变的问题

UI效果图第一张的右上角的图标在获得焦点后无法通过监听key值来更改Focus,发现该控件为fragment有很大关系。

所以,我选择了一种方法,通过监听window层的onKeyDown事件来处理,并通过获得当前Focus的View Id方式来手动更改焦点的位置,代码如下:

public boolean onKeyDown(int keyCode, KeyEvent event) {

Constants.debug("onKeyDown");

View rootview = this.getWindow().getDecorView();

int focusId = rootview.findFocus().getId();//这里是获得当前focus id的方法

Constants.debug("focusId : " + focusId);

if (focusId == R.id.root_main_top_wifi_fg){

if (keyCode == KeyEvent.KEYCODE_DPAD_LEFT){

wifiFg.getView().setFocusable(false);

mMainTopHomeRlRoot.setFocusable(false);

mMainTopMarketRlRoot.setFocusable(true);

gridview.setFocusable(false);

}

if (event.getAction() == KeyEvent.ACTION_DOWN && keyCode == KeyEvent.KEYCODE_DPAD_DOWN){

wifiFg.getView().setFocusable(false);

mMainTopHomeRlRoot.setFocusable(false);

mMainTopMarketRlRoot.setFocusable(false);

gridview.setFocusable(true);

gridview.requestFocus();

currentSelectPosition = Constants.position;

mGridAdapter.setSelection(Constants.position);

mMainArrowUpRlRoot.setVisibility(View.INVISIBLE);

mMainArrowDownRlRoot.setVisibility(View.VISIBLE);

}

}

return super.onKeyDown(keyCode, event);//不阻断按键时间的传递

}

总结:GridView不难,但是要快速上手,还是需要理解一些基础性的东西才行。

========================================

补充:2018.06.08

解决了onCreate gridview的时候,第一个item选中无法放大的方法:

执行onItemSelection的时候,选中第一个item默认会执行放大的动画,但是在第一次启动有Gridview的界面并默认让第一个item持有focus的时候,大多数情况下并不会有该动画,这其实是GridView设计上的一个缺陷。解决方法很简单:

我们调用Gridiview支持的方法会发现,每次当GridView第一次获得焦点的时候,都首次会执行一个onFocusChange的方法,那么我们在这里从新执行setSelection(0),并通过notifyDataSetChanged刷新adapter,来达到我们的目的。

如图:

android 壁纸库,Android TV壁纸库之GridView使用及焦点处理相关推荐

  1. Android RecyclerView之代替ListView与GridView

    RecyclerView是Android 5.0的新特性,可以直接代替ListView与GridView,并且能够实现瀑布流的布局,感觉RecyclerView使用的好处就是它不关心布局,只关心资源的 ...

  2. 【Android】android TV开发

    google翻译[https://www.jianshu.com/p/c216849986ed] Ⅰ.开始使用电视应用 为了使您的应用在电视设备上获得成功,您必须设计出可以在10英尺远的地方轻松理解的 ...

  3. Android根据屏幕大小动态适配GridView

    前言: 最近有个需求上面有图片,下面是个类似九宫格的列表,列表下面还有文字,刚开始只有3列还可以布满,后面改了需求有4列,在小屏手机就没有铺满,第4列看不到了,修改图片和文字长宽也没适配,后面想到利用 ...

  4. hd live tv android,HD Live TV

    Watch HD LIVE TV HD free on your Phone and Tablet from across the world. "HD Live TV" is u ...

  5. Android 从 Android 本地图库选择多个图片

    原文地址 本文说明如何从 Android 本地图库选择多个图片.作者考虑很多解决方案. 演示从 Android 本地图库选择多个图片,有两个方法可以实现从图库中选择多个图片: 用 Intent 获取多 ...

  6. Android之Android实现浮层的上下滑动(支持内部添加View)

    前言 我K,今天居然是情人节,对于资深的单身狗来说,简直是个噩耗,今天注定是各种秀恩爱,心塞中.... 话题到此结束,管他什么情人节,今天给大家带来的是一个浮层的上下滑动,浮层滑动时分三种状态:全部显 ...

  7. 【Android】 Android中适配器简介

    1. BaseAdapter的使用实例 BaseAdapter baseAdapter = new BaseAdapter() {@Overridepublic View getView(int po ...

  8. android 视频预览,预览视频  |  Android 开发者  |  Android Developers

    如需鼓励用户访问您的 TV 应用中的深层链接,预览视频是一种不错的方法. 预览内容可以是简短的视频剪辑,也可以是完整的电影预告片. 在创建预览时,请注意以下准则: 不要在预览中显示广告.如果您在客户端 ...

  9. kodi remote android,使用Android和iOS在Win10系统中设置Kodi Remote方法

    Kodi是一个流行的流媒体应用程序,兼容windows操作系统和大多数其他设备,如Android,iOS,Linux等.Kodi是家庭娱乐的理想选择,基本上设计用于大屏幕.如果要在windows桌面上 ...

最新文章

  1. [JavaScript] 探索JS中的函数秘密
  2. 华人小哥开发“CG工坊”,帮你快速入门计算机图形学 | GitHub热榜
  3. 关于js css html加载顺序整理
  4. TCP/IP:IP多播选路
  5. .NET Core 跨平台物联网框架 ServerSuperIO.Core,一套设备驱动通吃嵌入式、上位机、云服务...
  6. c语言语言教程0基础_C语言基础
  7. uva 12108 Extraordinarily Tired Students(特别困的学生)
  8. 【Luogu3926】SAC E#1 - 一道不可做题 Jelly
  9. 【C/C++】C++重复率最高、最经典面试题/笔试题【持续更新】
  10. robo3t怎么插入数据_使用Robo 3T操作MongoDB数据库
  11. 微信公众号主体注销了,怎么办理账号迁移和公证?
  12. 区块链在供应链金融中的应用分析
  13. python连接数据库mysql失败_mysql数据库连接失败是什么原因
  14. buflab-计算机系统实验
  15. 怎么给图片换背景?点开收货一些新方法
  16. 雅虎免费邮箱开通POP3和自动转发的方法
  17. STM32控制电机简易教程
  18. 计算机开机需要注意什么,笔记本电脑第一次开机注意事项
  19. Java基本类型介绍
  20. CSS基础(3)- 选择器

热门文章

  1. 02_Windows和VMware下的Linux共享文件的实现
  2. 数字麦克风PDM信号采集与STM32 I2S接口应用(一)
  3. 课设 c语言编译学籍管理系统,C语言课设之学生学籍管理系统
  4. 怎么实现自己的第一个小目标?
  5. 攻防世界nice_bgm
  6. windows下更改文件创建修改访问时间
  7. delphi身份证验证
  8. 中文自然语言处理可能是 NLP 中最难的?
  9. 忽略了导热硅脂等于祸害电脑
  10. php配置支持m3u8,PHP实现m3u8并发下载