版本号2仅仅是简单的实现了当手指按下的时候listView的Item向左移动一定的距离,并没有随着手指的左右移动而左右滚动。在这个版本号3.0中将会实现随着手指的移动而滚动的目标:当手指向左移动的时候。listView向左滚动;当手指向右移动的时候。listView向右滚动;在開始进入正题之前,先说说预备的知识和涉及到的方法。

在version2.0之前加入View的时候用的都是addView终于辗转调用了addViewInner方法,经过查询viewGroup的源代码发现有一个addViewInLayout方法。api的说明例如以下:Adds a view during layout,this is usefule if in your onLayout method.而我们这个横向listView正好是在onLayout里面加入的View,所以从如今開始加入View的时候就改为addViewInLayout了。ViewGrouup里面提供一个View的数组mChildren,在addView方法中调用了addVew(view view,index)index默认传的是-1。表明加入到View数组mChildren最后面。

而addViewInLaout的方法的第二个參数就是这个index,假设index为负数的话就把该View方法数组的最后面(实际代码处理中就是数组的插入操作,非常easy的源代码),当index为正数的时候就把该View插入到数组中的index的位置,相应的View数组mChildren里面的元素后移。当然相应的删除View的时候也有removeViewInLayout方法;事实上getChildAt(int index)就是从数组mChildrenCount获取返回相应索引的View,所以左右滑动的核心思想就出来了:

1)当向左滚动的时候,把右边即将要滚动出来的View加入到mChildren数组的最后面。在页面上的显示为在屏幕的右边的View,同一时候提供一个rightIndex来表示adapter.getView的position。即addViewInlayout(view,-1,view.getLayoutParams,true),

2)当向右滚动的时候。把左边即将滚动出来的View加入的mChildren数组的最前面数组0的位置,在页面上的显示为在屏幕左边的View,同事提供一个left来表示adapter.getView 的position參数。

即addViewInlayout(view,0,view.getLayoutParams,true)。用代码体现例如以下

private void addRightChildViews(int dianceX) {// 2.让屏幕尽可能的显示Item。注意刚開始的时候是没有View rightChildView = getChildAt(getChildCount() - 1);// 获取此childView右边框距离parentView左边框的距离int rightEdge = rightChildView != null ? rightChildView.getRight() : 0;while (rightEdge + dianceX < getWidth()&& rightIndex < listAdapter.getCount()) {View child = listAdapter.getView(rightIndex, null, null);child = measureChild(child);addViewInLayout(child, -1, child.getLayoutParams(), true);rightEdge += child.getMeasuredWidth();rightIndex++;}}private void addLeftChildViews(int dianceX) {View leftChildView = getChildAt(0);int leftEdge = leftChildView != null ?

leftChildView.getLeft() : 0;         while (leftEdge + dianceX > 0 && leftIndex >= 0) {             View child = listAdapter.getView(leftIndex, null, null);             child = measureChild(child);             addViewInLayout(child, 0, child.getLayoutParams(), true);             leftEdge -= child.getMeasuredWidth();             leftIndex--;            //此处省略了一个重要的代码         }     }

该篇博客就是环绕着这两个核心思路进行拓展和改动进而实现左右滚动的。

在版本号2.0中向左移动的时候须要在合适的时机移除左边符合某些条件的View(详细见简单的横向ListView实现(version 2.0) 相同,在想右滚动的时候也须要把超出右边屏幕的View从Viewgroup里面删除出去(当child.getLeft()+移动偏移量大于parent.getWidth()的时候进行删除):简而言之就是向左滚动时。须要删除滚动过后左边的看不见View。当向右滚动时,须要删除滚动过后右边的看不见的View。用代码表演示样例如以下:


/* 删除看不见的view*/private void removeAnvisiableViews(int dianceX) {// 移除左边看不到的viewView firtVisiableView = getChildAt(0);if (firtVisiableView != null&& dianceX + firtVisiableView.getRight() <= 0) {removeViewInLayout(firtVisiableView);leftIndex++;//此处省略了一行重要的代码}// 移除右边看不到的viewView lastVisialbeView = getChildAt(getChildCount() - 1);if (lastVisialbeView != null&& lastVisialbeView.getLeft() + dianceX >= getWidth()) {removeViewInLayout(lastVisialbeView);rightIndex--;}}

到此为止在考虑左右滚动的条件下什么时候加入左边的View、什么时候加入右边的View以及在什么时候删除左右两边看不见的View的思路以及代码都实现了。之前的版本号的滚动值都是写死的。如今这个版本号将用GestureDetector来处理手指的移动,至于GestureDetector的使用方法在这里不再赘述。网上好多资料能够查阅在.SimpleOnGestureListener()里面有一个 onScroll(MotionEvent e1, MotionEvent e2,  float distanceX, float distanceY)方法。由于是水平滚动。所以第三个參数distanceX使我们所须要的,该參数指的是距离上次调用onScroll方法的时候x轴滚动的距离。所以在代码中我用变量distanceX来记录下了:

    public boolean onScroll(MotionEvent e1, MotionEvent e2,float distanceX, float distanceY) {//记录滚动的距离HListView.this.distanceX= (int) distanceX;// 仍然须要重绘requestLayout();return true;};

这里有个须要注意的小地方,手指向左的时候distanceX>0,而手指向右的时候distanceX<0.所以在用的时候我们要取反,所以在onLayout里面这么调用(较版本号2.0之前对这种方法进行了重构处理):

@Overrideprotected void onLayout(boolean changed, int left, int top, int right,int bottom) {if (listAdapter == null) {return;}removeAnvisiableViews(-distanceX);addRightChildViews(-distanceX);addLeftChildViews(-distanceX);layoutChildViews(-distanceX);}

到此为止基本上该说的都说了,执行一把试试,我屮艸芔茻,发现动不了。怎么回事?各种抓耳挠腮。终于吃饭的时候灵光一闪知道问题出如今哪儿了!

我们知道横向listView滚动的逻辑就是反复addView和removeView的操作,可是最重要的一点就是终于都要调用layoutChildViews方法进行处理,而在version2.0版本号的代码中layoutChildViews代码是这么样的:

int childLeft = 0;for(int i=0;i<getChildCount();i++) {View child = getChildAt(i);int childWidth = child.getMeasuredWidth();child.layout(childLeft, 0, childWidth+childLeft, child.getMeasuredHeight());//只是最好的写法是childLeft +=  childWidth+child.getPaddingRight();}

layout方法的第一个三处我们总是让它从0開始。!

!!问题就出在这儿。。!

简单的想象一下,当向右滚动的时候左边会出现半个Item的情况(或者不完整的Item)。怎么可能是从0開始呢。肯定会出现childLeft<0的情况。所以当处理左边第一个能够看见的子View的时候,layout第一个參数是随着滚动而发生变化的。并非固定为0的死的值!事实上上面的代码中我有写到:此处省略了一行重要的代码,事实上这行代码就是解决问题的!

我在类里面定义了个leftOffset=0的变量来进行控制表示下一个即将加入的子View的起始位置(注意要加上distanceX),(这个变量的作用想了半天不好用语言描写叙述,郁闷).当调用addleftChildView方法的时候每加入一个View时对该变量进行leftOffset -= child.getMeasuredWidth();。

对应的当删除左边的一个View的时候leftOffset += child.getMeasuredWidth();所以layoutchildView的代码改动为:

private void layoutChildViews(int distanceX) {if(getChildCount()==0) {return;}leftOffset += distanceX;int childLeft = leftOffset;for (int i = 0; i < getChildCount(); i++) {View child = getChildAt(i);int childWidth = child.getMeasuredWidth();child.layout(childLeft, 0, childWidth + childLeft,child.getMeasuredHeight());// 只是最好的写法是childLeft += childWidth + child.getPaddingRight();}}

执行一把。OK,爽歪歪!version3.0到此位置完毕了。只是功能仍然不够完好:比方当左边已经是第一个Item的时候仍然能够想右边滚动。同理当右边是最后一个View的时候仍然能够向左滚动、相同的当手指离开的时候没有惯性滚动,比方每次getView的时候都须要对xml文件进行解析,没有非常好的重用已经解析过的xml等,这些丰富的功能将在下一个版本号中实现。(此处为源码)

转载于:https://www.cnblogs.com/liguangsunls/p/7089381.html

简单的横向ListView实现(version 3.0)相关推荐

  1. 简单的横向ListView实现(version 4.0)

    这个版本号的博客写起来颇费口舌.有些代码自己语言组织能力有限,感觉描写叙述起来非常费劲,前前后后改了五六遍稿子还是不尽人意 ,只是我还是坚持写出来自己当初的思路,假设看得不明确的地方我在文章最后仍然会 ...

  2. Android UI开发: 横向ListView(HorizontalListView)及一个简单相册的完整实现 (附源码下载)

    本文内容: 1.横向ListView的所有实现思路; 2.其中一个最通用的思路HorizontalListView,并基于横向ListView开发一个简单的相册: 3.实现的横向ListView在点击 ...

  3. Android横向ListView功能实现

    --在开发类似新闻功能的App过程中需要在新闻页面展示新闻附件,附件一多的话一行展示不完,换行又不好看,为此需要做像今日头条导航栏那样可以横向滑动的列表,不同点在于附件数量是动态添加的 可能有一个 也 ...

  4. 横向ListView(一) ——开篇,基础逻辑实现

    2019独角兽企业重金招聘Python工程师标准>>> 第一次写博文,写得不好的地方还望各位看客见谅 为了学习自定义软件开发,且定制出满足自己需求的控件(不需要将就地使用第三方源码) ...

  5. HorizontalListView 横向listview

    tag:HorizontalListView 横向listview  仿 优酷 播放列表 由于优酷的客户端很酷,最近在做视频列表的时候客户要求做出类似效果,开始打算用Gallery的,不过后来发现横向 ...

  6. Android 横向滚动列表 (类似横向ListView)

    示例: 布局代码***.xml: <?xml version="1.0" encoding="utf-8"?> <LinearLayout x ...

  7. 张高兴的 UWP 开发笔记:横向 ListView

    ListView 默认的排列方向是纵向 ( Orientation="Vertical" ) ,但如果我们需要横向显示的 ListView 怎么办? Blend for Visua ...

  8. java51_Java运行 Unsupported major.minor version 51.0 错误

    今天写了简单的Java程序,运行的时候不知道为啥出现这个问题 happy@happy-HP-Compaq-dx7518-MT:~/Study/CrazyJava$ java FieldTest Exc ...

  9. 横向ListView(四) —— 添加滚动条

    2019独角兽企业重金招聘Python工程师标准>>> 在前面的文章已经介绍了横向ListView的基础实现及头尾视图的添加等的实现,这篇文章将介绍为横向ListView添加滚动条: ...

最新文章

  1. JavaScript的toString()和valueOf()函数
  2. R语言入门学习笔记 - 对R软件的认识
  3. springBoot 项目 jar/war打包 并运行
  4. 2019蓝桥杯省赛b组
  5. Sacrilege –自定义SWT滚动条
  6. java 检索ldap,从LDAP(Java)检索信息
  7. Weblogic跨域session冲突解决办法
  8. java linux urlencode_Javascript下的urlencode编码解码方法decodeURIComponent()
  9. MyBatis的XML配置文件(一)
  10. 18.卷1(套接字联网API)---路由套接字
  11. 拦截导弹问题(Noip1999)
  12. Java的常用集合框架
  13. 个人静态博客页面模板
  14. 【ML】使用支持向量回归器进行时间序列预测
  15. matlab 几何布朗运动 股价,股票价格几何布朗运动模型的理论错误及纠正
  16. win10系统迁移到新的硬盘
  17. Markdown_常用语法总结
  18. 简单的记录一下使用HAL库的SPI外挂W25Q32
  19. 传鸿蒙操作系统掌舵人王成录已从华为离职
  20. 为什么计算机无法读取u盘,电脑无法识别读取U盘怎么办?逐一排查解决问题

热门文章

  1. Java中实现DES加解密的一个类
  2. 在 Delphi 下使用 DirectSound (4): 设置音量、相位、播放频率和播放位置
  3. 约瑟夫问题-学习笔记
  4. 洛谷P4199 万径人踪灭(manacher+FFT)
  5. Ubuntu安装webmin
  6. Solaris的syslog机制
  7. KVM虚拟化环境搭建
  8. Socket SSL通讯
  9. 在原有Android项目中快速集成React Native
  10. maven项目编译漏掉src/main/java下的xml配置文件