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

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

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

一、GridView的介绍:

官网地址

a65f8883e58a29ccc841d500b45d997a.png

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的常用方法介绍:

常用参数:

51c531e23e9fcc7e1908dd81ac699b65.png

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,重写一些方法。

9c5c3ed1bf921dfc353863a29bf5fbc0.png

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的位置,我们定义一个全局的变量,如图:

6c21586cff70da082a904cbf806230a7.png

在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,来达到我们的目的。

如图:

0473faa5adc0e79daf0728a94812fc3c.png

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值