文档章节

GridView & ListView (Android盒子开发)

SuShine
 SuShine
发布于 2015/09/14 19:11
字数 1536
阅读 988
收藏 8

一.GridView在Android4.4下关于焦点的bug的解决方式

Android4.4下,关于GridView有一个关于焦点的bug。这个bug并不容易被发现,但是在电视盒子的开发过程中就很明显。具体表现是,Gridview会一直持有一个焦点,只要有数据,就一直会有一个子View是Selected状态。而且,当数据从无到有的时候,GridView还会抢焦点。

最后解决这个bug的方式是这样的,建立一个自定义的GridView,重写一个方法,

@Override
public boolean isInTouchMode() {
    return !(hasFocus() && !super.isInTouchMode());
}

我并没有弄懂为啥,但是加上这句话确实就解决了这个bug。

二.选中项有放大效果的GirdView的实现

先在AnimaFactory类中包装静态缩放动画。

/**
 * 缩放动画,用于缩放控件
 * @param startScale 控件的起始尺寸倍率
 * @param endScale 控件的终点尺寸倍率
 * @return
 */
public static Animation zoomAnimation(float startScale, float endScale, int duration){
    ScaleAnimation anim = new ScaleAnimation(startScale, endScale, startScale, endScale,
            Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
    anim.setFillAfter(true);
    anim.setDuration(duration);
    return anim;
}

然后在自定义GridView中加入如下方法。

/**
 * 实现本类onFocusChangeListener时调用此方法
 * @param v
 * @param hasFocus
 */
public void onFocusChange(View v, boolean hasFocus) {
    if (hasFocus) {
        zoomInView(lastView);
    } else {
        zoomOutView(lastView);
    }
}

/**
 * 外面调用OnItemSelectedListener的时候,调用这个方法
 * @param parent
 * @param view
 * @param position
 * @param id
 */
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
    zoomInView(view);
    if (view != lastView) {
        zoomOutView(lastView);
    }
    lastView=view;
}

/**
 * 放大
 * @param v
 */
private void zoomInView(View v) {
    if (v != null) {
        v.startAnimation(AnimaFactory.zoomAnimation(1.0f, 1.1f, 100));
    }
}

/**
 * 缩小
 * @param v
 */
private void zoomOutView(View v) {
    if (v != null) {
        v.startAnimation(AnimaFactory.zoomAnimation(1.1f, 1.0f, 100));
    }
}

其中,onSelected方法的调用效果是,把正在选中的View放大,把上一个选中的View即lastView缩小。然后lastView更新为当前选中的View。

这个方法在外面给GridView设置OnSelectedListener的时候调用。

同理,设置OnFocusChangeListener中要调用的onFucusChange方法。

这里还有一点要说的,虽然选中项放大了,但是它并不一定被画在最前面。为了保证不会被挡住,我们还要加一个方法。

/**
 * @description: <修改默认加载顺序(核心代码)>
 * @see android.view.ViewGroup#getChildDrawingOrder(int, int)
 * @param childCount 当前屏幕中显示的item个数
 * @param i 在数组中的位置,从0开始到childCount-1
 * @return 加载顺序
 */
@Override
protected int getChildDrawingOrder(int childCount, int i) {
    if (this.getSelectedItemPosition() != -1) {
        if (i + this.getFirstVisiblePosition() == this.getSelectedItemPosition()) {// 这是原本要在最后一个刷新的item
            return childCount - 1;
        }
        if (i == childCount - 1) {// 这是最后一个需要刷新的item
            return this.getSelectedItemPosition() - this.getFirstVisiblePosition();
        }
    }
    return i;
}

这段代码加上后,要在构造方法中加一句,

setChildrenDrawingOrderEnabled(true);

来保证加载顺序正确。

三.重置数据setList()方法中要注意的

有两种重置数据的方法,如果在Adapter中传入的数据,那么直接给gridView调用setAdapter即能重置数据。

另一种,是在Adapter中,写setList方法来传入数据。比如:

public void setList(List<VideoObject> list){
    notifyDataSetInvalidated();
    mList=list;
    notifyDataSetChanged();
}

notifiDataSetChange()方法比较好理解,因为重置数据后要刷新数据。那notifyDataSetInvalidated()起什么作用呢?它的作用是通知Adatper旧数据无效。如果不写这行代码,在重置数据的时候,可能会出现数组越界异常。

四.关于分页加载数据

因为电视盒子没有触屏,是通过遥控控制焦点来操作系统的。所以分页加载不是通过“下拉刷新”,而是通过焦点判断。而判断语句,在OnSelectedChangeListener中实现。

首先,要写代码来确定要需要请求数据的那一行的行数。这里我设为lastLineNum。

lastLineNum = (list.size() - 1) / gridView.getNumColumns();

这里的list是获取的数据,接下来设置监听。

gridView.setOnItemSelectedListener(new OnItemSelectedListener() {
    @Override
    public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
        gridView.onItemSelected(parent, view, position, id);
        // 如果是分页加载最后一排,则要求分页数据
        if (lastLineNum != 0 && position / gridView.getNumColumns() == lastLineNum) {
            //在这里请求数据并更新视图
        }
        @Override
        public void onNothingSelected(AdapterView<?> parent) {

        }
});

请求数据更新视图,就在Adapter中addList,然后notifyDataSetChange就可以了。

五.获取正在显示的数据位置以及出现bug的修正方式

GridView和ListView都有一个方法是getFirstVisiblePosition(),是获取第一个正在显示的数据的位置。但是这个方法有个缺陷,就是当数据,只显示一半甚至更少的时候,这个方法判断它已经显示了。然而它并没有完全显示。

我当时要实现的功能是当ListView上侧有数据没有显示的时候,上侧有一个箭头,而ListView下侧有数据没有显示的时候,下侧有一个箭头。这两个箭头都是ImageView。

后来解决这个缺陷是用下面的这种方式。

lvChildCategory.setOnScrollListener(new OnScrollListener() {
    public void onScrollStateChanged(AbsListView view, int scrollState) {

    }
    public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
        if (totalItemCount == 0 || visibleItemCount == 0) {
            //当无数据显示的时候,上下侧两个箭头均不显示
            ivArrayUp.setVisibility(View.INVISIBLE);
            ivArrayDown.setVisibility(View.INVISIBLE);
            return;
        } else {
            //当有数据显示的时候
            if (firstVisibleItem > 0) {
                //当第一个显示的数据不是第一个数据时,箭头显示
                ivArrayUp.setVisibility(View.VISIBLE);
            } else {
                //当第一个显示的数据是第一个数据的时候,加判断
                //第一个数据的上坐标
                int firstTop = view.getChildAt(0).getTop();
                //ListView的上坐标
                int paddingTop = view.getListPaddingTop();
                //如果第一个数据的上坐标没超过了ListView的边界,那么上箭头不显示
                int spaceAbove = paddingTop - firstTop;
                if (spaceAbove <= 0)
                    ivArrayUp.setVisibility(View.INVISIBLE);
            }
            //下箭头与上箭头同理
            if (firstVisibleItem + visibleItemCount < totalItemCount) {
                ivArrayDown.setVisibility(View.VISIBLE);
            } else {
                int lastBottom = view.getChildAt(view.getChildCount() - 1).getBottom();
                int paddingBottom = view.getListPaddingBottom();
                if (lastBottom <= (view.getHeight() - paddingBottom))
                    ivArrayDown.setVisibility(View.INVISIBLE);
            }
        }
    }
});

即获取子View的上坐标和ListView的上坐标来判断。解决此缺陷。

六.GridView的视图小细节

GridView中,selector会影响子布局的排版。一般并不明显,但是如果selector是一层比较厚的阴影的话,子布局加上selector则会缩水一圈。

要解决这个问题,可以调整GirdView的horizontalSpacing和verticalSpacing属性,分别表示子布局横向间隙和纵向间隙,这两个值是可以设置为负数的。如果子布局加上selector后缩水太严重,这两个值调整为负数能解决这个问题。

同时,GridView的子布局宽度是无法调整的,也是要通过设置numColumns和horizontalSpacing来调整宽度。

本文转载自:http://blog.csdn.net/henryjax/article/details/47999941

SuShine
粉丝 131
博文 621
码字总数 159427
作品 0
朝阳
后端工程师
私信 提问
【压岁干货】精彩技术博客+优秀源码集锦

虽然2015年已经过了一月有余,但在中国,好像只有过了春节才算进入新的一年。眼看着这也春节倒计时了,大家好像又都忙了起来,赶项目赶项目…… 从DevStore整理了一些优秀的技术博客和源码作...

牵着蜗牛去西藏
2015/02/04
1K
4
Android入门第八篇之GridView(九宫图)

GridView 跟ListView都是比较常用的多控件布局,而GridView更是实现九宫图的首选!本文就是介绍如何使用GridView实现九宫图。 GridView的用法很多,网上介绍最多的方法就是自己实现一个Image...

鉴客
2011/12/14
1K
0
Android开发:ScrollView嵌套GridView的解决办法

前些日子在开发中用到了需要ScrollView嵌套GridView的情况,由于这两款控件都自带滚动条,当他们碰到一起的时候便会出问题,即GridView会显示不全。 解决办法,自定义一个GridView控件 publ...

小0426小
2013/05/30
551
0
解决ListView,GridView,Gallery的Adapter中的getView多次调...

ListView,GridView,Gallery 这三个控件的加载自定义的内容的时候,你要加载三次,但是当你打印的时候,却发现他运行的不止三次,那时因为什么呢? 这是android机制中要计算高的时候出现的一些...

雨焰
2012/05/25
6.1K
2
android 中 scollView中嵌套GridView显示UI不全

的解决办法 前些日子在开发中用到了需要ScrollView嵌套GridView的情况,由于这两款控件都自带滚动条,当他们碰到一起的时候便会出问题,即GridView会显示不全。 解决办法,自定义一个GridVie...

xiahuawuyu
2013/01/07
3.9K
0

没有更多内容

加载失败,请刷新页面

加载更多

Raspberry Pi 树莓派 搭建java8环境

更新软件源 apt-get upgradeapt-get update 移除自带的openjdk(如果有的话) apt-get remove openjdk* 安装oracle jdk,地址: https://www.oracle.com/technetwork/java/javase/downl......

ChangeZ
29分钟前
79
0
树莓派3b 安装openwrt

https://downloads.openwrt.org/releases/19.07.0/targets/brcm2708/bcm2710/openwrt-19.07.0-brcm2708-bcm2710-rpi-3-squashfs-factory.img.gz 插入并启动树莓派3B+,顺便接上键盘和显示器,......

FalconChen
48分钟前
71
0
OSChina 周一乱弹 —— 有些运动也常用到膝盖

Osc乱弹歌单(2020)请戳(这里) 【今日歌曲】 @薛定谔的兄弟 :分享洛神有语创建的歌单「我喜欢的音乐」: 《火宵の月・テーマ~ピアノソロ》- 中村由利子 手机党少年们想听歌,请使劲儿戳(...

小小编辑
今天
109
0
Redis持久化机制

RDB存储 RDB方式的持久化是通过快照完成的,当符合一定条件时Redis会自动将内存中的所有数据生成一份副本并存储在硬盘上。 Redis会在一下集中情况下对数据进行快照: 根据配置规则进行快照;...

XuePeng77
今天
81
0
float精度计算测试

package mainimport ("fmt""github.com/go-ozzo/ozzo-dbx"_ "github.com/go-sql-driver/mysql")type DecimalDemo struct {Id intAmount float64}func main() {db, _......

醉人的笑容你有没有
今天
127
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部