private void todo() {//这是一个很长的字符串String str ="最重要的修改就是这些了,不过在其它一些地方还做了一些小的改动。观察第75行,这里是把被移出屏幕的子View添加到RecycleBin当中,其实也就是说明这个View已经被回收了。那么还记得我们刚刚添加的全局变量mColumnViews吗?它用于缓存每一列的子View,那么当有子View被回收的时候,mColumnViews中也需要进行删除才可以。在第76行,先调用getTag()方法来获取该子View的所处于哪一列,然后调用remove()方法将它移出。第96行处的逻辑是完全相同的,只不过一个是向上移动,一个是向下移动,这里就不再赘述。最重要的修改就是这些了,不过在其它一些地方还做了一些小的改动。观察第75行,这里是把被移出屏幕的子View添加到RecycleBin当中,其实也就是说明这个View已经被回收了。那么还记得我们刚刚添加的全局变量mColumnViews吗?它用于缓存每一列的子View,那么当有子View被回收的时候,mColumnViews中也需要进行删除才可以。在第76行,先调用getTag()方法来获取该子View的所处于哪一列,然后调用remove()方法将它移出。第96行处的逻辑是完全相同的,只不过一个是向上移动,一个是向下移动,这里就不再赘述。最重要的修改就是这些了,不过在其它一些地方还做了一些小的改动。观察第75行,这里是把被移出屏幕的子View添加到RecycleBin当中,其实也就是说明这个View已经被回收了。那么还记得我们刚刚添加的全局变量mColumnViews吗?它用于缓存每一列的子View,那么当有子View被回收的时候,mColumnViews中也需要进行删除才可以。在第76行,先调用getTag()方法来获取该子View的所处于哪一列,然后调用remove()方法将它移出。第96行处的逻辑是完全相同的,只不过一个是向上移动,一个是向下移动,这里就不再赘述。最重要的修改就是这些了,不过在其它一些地方还做了一些小的改动。观察第75行,这里是把被移出屏幕的子View添加到RecycleBin当中,其实也就是说明这个View已经被回收了。那么还记得我们刚刚添加的全局变量mColumnViews吗?它用于缓存每一列的子View,那么当有子View被回收的时候,mColumnViews中也需要进行删除才可以。在第76行,先调用getTag()方法来获取该子View的所处于哪一列,然后调用remove()方法将它移出。第96行处的逻辑是完全相同的,只不过一个是向上移动,一个是向下移动,这里就不再赘述。最重要的修改就是这些了,不过在其它一些地方还做了一些小的改动。观察第75行,这里是把被移出屏幕的子View添加到RecycleBin当中,其实也就是说明这个View已经被回收了。那么还记得我们刚刚添加的全局变量mColumnViews吗?它用于缓存每一列的子View,那么当有子View被回收的时候,mColumnViews中也需要进行删除才可以。在第76行,先调用getTag()方法来获取该子View的所处于哪一列,然后调用remove()方法将它移出。第96行处的逻辑是完全相同的,只不过一个是向上移动,一个是向下移动,这里就不再赘述。最重要的修改就是这些了,不过在其它一些地方还做了一些小的改动。观察第75行,这里是把被移出屏幕的子View添加到RecycleBin当中,其实也就是说明这个View已经被回收了。那么还记得我们刚刚添加的全局变量mColumnViews吗?它用于缓存每一列的子View,那么当有子View被回收的时候,mColumnViews中也需要进行删除才可以。在第76行,先调用getTag()方法来获取该子View的所处于哪一列,然后调用remove()方法将它移出。第96行处的逻辑是完全相同的,只不过一个是向上移动,一个是向下移动,这里就不再赘述。最重要的修改就是这些了,不过在其它一些地方还做了一些小的改动。观察第75行,这里是把被移出屏幕的子View添加到RecycleBin当中,其实也就是说明这个View已经被回收了。那么还记得我们刚刚添加的全局变量mColumnViews吗?它用于缓存每一列的子View,那么当有子View被回收的时候,mColumnViews中也需要进行删除才可以。在第76行,先调用getTag()方法来获取该子View的所处于哪一列,然后调用remove()方法将它移出。第96行处的逻辑是完全相同的,只不过一个是向上移动,一个是向下移动,这里就不再赘述。最重要的修改就是这些了,不过在其它一些地方还做了一些小的改动。观察第75行,这里是把被移出屏幕的子View添加到RecycleBin当中,其实也就是说明这个View已经被回收了。那么还记得我们刚刚添加的全局变量mColumnViews吗?它用于缓存每一列的子View,那么当有子View被回收的时候,mColumnViews中也需要进行删除才可以。在第76行,先调用getTag()方法来获取该子View的所处于哪一列,然后调用remove()方法将它移出。第96行处的逻辑是完全相同的,只不过一个是向上移动,一个是向下移动,这里就不再赘述。最重要的修改就是这些了,不过在其它一些地方还做了一些小的改动。观察第75行,这里是把被移出屏幕的子View添加到RecycleBin当中,其实也就是说明这个View已经被回收了。那么还记得我们刚刚添加的全局变量mColumnViews吗?它用于缓存每一列的子View,那么当有子View被回收的时候,mColumnViews中也需要进行删除才可以。在第76行,先调用getTag()方法来获取该子View的所处于哪一列,然后调用remove()方法将它移出。第96行处的逻辑是完全相同的,只不过一个是向上移动,一个是向下移动,这里就不再赘述。最重要的修改就是这些了,不过在其它一些地方还做了一些小的改动。观察第75行,这里是把被移出屏幕的子View添加到RecycleBin当中,其实也就是说明这个View已经被回收了。那么还记得我们刚刚添加的全局变量mColumnViews吗?它用于缓存每一列的子View,那么当有子View被回收的时候,mColumnViews中也需要进行删除才可以。在第76行,先调用getTag()方法来获取该子View的所处于哪一列,然后调用remove()方法将它移出。第96行处的逻辑是完全相同的,只不过一个是向上移动,一个是向下移动,这里就不再赘述。最重要的修改就是这些了,不过在其它一些地方还做了一些小的改动。观察第75行,这里是把被移出屏幕的子View添加到RecycleBin当中,其实也就是说明这个View已经被回收了。那么还记得我们刚刚添加的全局变量mColumnViews吗?它用于缓存每一列的子View,那么当有子View被回收的时候,mColumnViews中也需要进行删除才可以。在第76行,先调用getTag()方法来获取该子View的所处于哪一列,然后调用remove()方法将它移出。第96行处的逻辑是完全相同的,只不过一个是向上移动,一个是向下移动,这里就不再赘述。最重要的修改就是这些了,不过在其它一些地方还做了一些小的改动。观察第75行,这里是把被移出屏幕的子View添加到RecycleBin当中,其实也就是说明这个View已经被回收了。那么还记得我们刚刚添加的全局变量mColumnViews吗?它用于缓存每一列的子View,那么当有子View被回收的时候,mColumnViews中也需要进行删除才可以。在第76行,先调用getTag()方法来获取该子View的所处于哪一列,然后调用remove()方法将它移出。第96行处的逻辑是完全相同的,只不过一个是向上移动,一个是向下移动,这里就不再赘述。最重要的修改就是这些了,不过在其它一些地方还做了一些小的改动。观察第75行,这里是把被移出屏幕的子View添加到RecycleBin当中,其实也就是说明这个View已经被回收了。那么还记得我们刚刚添加的全局变量mColumnViews吗?它用于缓存每一列的子View,那么当有子View被回收的时候,mColumnViews中也需要进行删除才可以。在第76行,先调用getTag()方法来获取该子View的所处于哪一列,然后调用remove()方法将它移出。第96行处的逻辑是完全相同的,只不过一个是向上移动,一个是向下移动,这里就不再赘述。最重要的修改就是这些了,不过在其它一些地方还做了一些小的改动。观察第75行,这里是把被移出屏幕的子View添加到RecycleBin当中,其实也就是说明这个View已经被回收了。那么还记得我们刚刚添加的全局变量mColumnViews吗?它用于缓存每一列的子View,那么当有子View被回收的时候,mColumnViews中也需要进行删除才可以。在第76行,先调用getTag()方法来获取该子View的所处于哪一列,然后调用remove()方法将它移出。第96行处的逻辑是完全相同的,只不过一个是向上移动,一个是向下移动,这里就不再赘述。最重要的修改就是这些了,不过在其它一些地方还做了一些小的改动。观察第75行,这里是把被移出屏幕的子View添加到RecycleBin当中,其实也就是说明这个View已经被回收了。那么还记得我们刚刚添加的全局变量mColumnViews吗?它用于缓存每一列的子View,那么当有子View被回收的时候,mColumnViews中也需要进行删除才可以。在第76行,先调用getTag()方法来获取该子View的所处于哪一列,然后调用remove()方法将它移出。第96行处的逻辑是完全相同的,只不过一个是向上移动,一个是向下移动,这里就不再赘述。接下来让我们回忆一下,ListView最基本的填充方式分为向下填充和向上填充两种,分别对应的方法是fillDown()和fillUp()方法,而这两个方法的触发点都是在fillGap()方法当中的,fillGap()方法又是由trackMotionScroll()方法根据子元素的位置来进行调用的,这个方法只要手指在屏幕上滑动时就会不停进行计算,当有屏幕外的元素需要进入屏幕时,就会调用fillGap()方法来进行填充。那么,trackMotionScroll()方法也许就应该是我们开始着手修改的地方了。其中mColumnCount表示瀑布流布局一共有几列,这里我们先让它分为两列显示,后面随时可以对它进行修改。当然,如果想扩展性做的好的话,也可以使用自定义属性的方式在XML里面指定显示的列数,不过这个功能就不在我们本篇文章的讨论范围之内了。mColumnViews创建了一个长度为mColumnCount的数组,数组中的每个元素都是一个泛型为View的ArrayList,用于缓存对应列的子View。mPosIndexMap则是用于记录每一个位置的子View应当放置在哪一列当中。OK,工作原理确认了之后,接下来的工作就是动手实现了。由于瀑布流这个扩展对ListView整体的改动非常大,我们没办法简单地使用继承来实现,所以只能先将ListView的源码抽取出来,然后对其内部的逻辑进行修改来实现功能,那么我们第一步的工作就是要将ListView的源码抽取出来。但是这个工作并不是那么简单的,因为仅仅ListView这一个单独的类是不能够独立工作的,我们如果要抽取代码的话还需要将AbsListView、AdapterView等也一起抽取出来,然后还会报各种错误都需要一一解决,我当时也是折腾了很久才搞定的。所以这里我就不带着大家一步步对ListView源码进行抽取了,而是直接将我抽取好的工程UIListViewTest上传到了CSDN,大家只需要点击 这里 进行下载就可以了,今天我们所有的代码改动都是在这个工程的基础上进行的。StringBuffer 上的主要操作是 append 和 insert 方法,可重载这些方法,以接受任意类型的数据。每个方法都能有效地将给定的数据转换成字符串,然后将该字符串的字符追加或插入到字符串缓冲区中。append 方法始终将这些字符添加到缓冲区的末端;而 insert 方法则在指定的点添加字符。例如,如果 z 引用一个当前内容是“start”的字符串缓冲区对象,则此方法调用 z.append(\"le\") 会使字符串缓冲区包含“startle”,而 z.insert(4, \"le\") 将更改字符串缓冲区,使之包含“starlet”。"+"最重要的修改就是这些了,不过在其它一些地方还做了一些小的改动。观察第75行,这里是把被移出屏幕的子View添加到RecycleBin当中,其实也就是说明这个View已经被回收了。那么还记得我们刚刚添加的全局变量mColumnViews吗?它用于缓存每一列的子View,那么当有子View被回收的时候,mColumnViews中也需要进行删除才可以。在第76行,先调用getTag()方法来获取该子View的所处于哪一列,然后调用remove()方法将它移出。第96行处的逻辑是完全相同的,只不过一个是向上移动,一个是向下移动,这里就不再赘述。最重要的修改就是这些了,不过在其它一些地方还做了一些小的改动。观察第75行,这里是把被移出屏幕的子View添加到RecycleBin当中,其实也就是说明这个View已经被回收了。那么还记得我们刚刚添加的全局变量mColumnViews吗?它用于缓存每一列的子View,那么当有子View被回收的时候,mColumnViews中也需要进行删除才可以。在第76行,先调用getTag()方法来获取该子View的所处于哪一列,然后调用remove()方法将它移出。第96行处的逻辑是完全相同的,只不过一个是向上移动,一个是向下移动,这里就不再赘述。最重要的修改就是这些了,不过在其它一些地方还做了一些小的改动。观察第75行,这里是把被移出屏幕的子View添加到RecycleBin当中,其实也就是说明这个View已经被回收了。那么还记得我们刚刚添加的全局变量mColumnViews吗?它用于缓存每一列的子View,那么当有子View被回收的时候,mColumnViews中也需要进行删除才可以。在第76行,先调用getTag()方法来获取该子View的所处于哪一列,然后调用remove()方法将它移出。第96行处的逻辑是完全相同的,只不过一个是向上移动,一个是向下移动,这里就不再赘述。最重要的修改就是这些了,不过在其它一些地方还做了一些小的改动。观察第75行,这里是把被移出屏幕的子View添加到RecycleBin当中,其实也就是说明这个View已经被回收了。那么还记得我们刚刚添加的全局变量mColumnViews吗?它用于缓存每一列的子View,那么当有子View被回收的时候,mColumnViews中也需要进行删除才可以。在第76行,先调用getTag()方法来获取该子View的所处于哪一列,然后调用remove()方法将它移出。第96行处的逻辑是完全相同的,只不过一个是向上移动,一个是向下移动,这里就不再赘述。最重要的修改就是这些了,不过在其它一些地方还做了一些小的改动。观察第75行,这里是把被移出屏幕的子View添加到RecycleBin当中,其实也就是说明这个View已经被回收了。那么还记得我们刚刚添加的全局变量mColumnViews吗?它用于缓存每一列的子View,那么当有子View被回收的时候,mColumnViews中也需要进行删除才可以。在第76行,先调用getTag()方法来获取该子View的所处于哪一列,然后调用remove()方法将它移出。第96行处的逻辑是完全相同的,只不过一个是向上移动,一个是向下移动,这里就不再赘述。最重要的修改就是这些了,不过在其它一些地方还做了一些小的改动。观察第75行,这里是把被移出屏幕的子View添加到RecycleBin当中,其实也就是说明这个View已经被回收了。那么还记得我们刚刚添加的全局变量mColumnViews吗?它用于缓存每一列的子View,那么当有子View被回收的时候,mColumnViews中也需要进行删除才可以。在第76行,先调用getTag()方法来获取该子View的所处于哪一列,然后调用remove()方法将它移出。第96行处的逻辑是完全相同的,只不过一个是向上移动,一个是向下移动,这里就不再赘述。最重要的修改就是这些了,不过在其它一些地方还做了一些小的改动。观察第75行,这里是把被移出屏幕的子View添加到RecycleBin当中,其实也就是说明这个View已经被回收了。那么还记得我们刚刚添加的全局变量mColumnViews吗?它用于缓存每一列的子View,那么当有子View被回收的时候,mColumnViews中也需要进行删除才可以。在第76行,先调用getTag()方法来获取该子View的所处于哪一列,然后调用remove()方法将它移出。第96行处的逻辑是完全相同的,只不过一个是向上移动,一个是向下移动,这里就不再赘述。最重要的修改就是这些了,不过在其它一些地方还做了一些小的改动。观察第75行,这里是把被移出屏幕的子View添加到RecycleBin当中,其实也就是说明这个View已经被回收了。那么还记得我们刚刚添加的全局变量mColumnViews吗?它用于缓存每一列的子View,那么当有子View被回收的时候,mColumnViews中也需要进行删除才可以。在第76行,先调用getTag()方法来获取该子View的所处于哪一列,然后调用remove()方法将它移出。第96行处的逻辑是完全相同的,只不过一个是向上移动,一个是向下移动,这里就不再赘述。最重要的修改就是这些了,不过在其它一些地方还做了一些小的改动。观察第75行,这里是把被移出屏幕的子View添加到RecycleBin当中,其实也就是说明这个View已经被回收了。那么还记得我们刚刚添加的全局变量mColumnViews吗?它用于缓存每一列的子View,那么当有子View被回收的时候,mColumnViews中也需要进行删除才可以。在第76行,先调用getTag()方法来获取该子View的所处于哪一列,然后调用remove()方法将它移出。第96行处的逻辑是完全相同的,只不过一个是向上移动,一个是向下移动,这里就不再赘述。最重要的修改就是这些了,不过在其它一些地方还做了一些小的改动。观察第75行,这里是把被移出屏幕的子View添加到RecycleBin当中,其实也就是说明这个View已经被回收了。那么还记得我们刚刚添加的全局变量mColumnViews吗?它用于缓存每一列的子View,那么当有子View被回收的时候,mColumnViews中也需要进行删除才可以。在第76行,先调用getTag()方法来获取该子View的所处于哪一列,然后调用remove()方法将它移出。第96行处的逻辑是完全相同的,只不过一个是向上移动,一个是向下移动,这里就不再赘述。最重要的修改就是这些了,不过在其它一些地方还做了一些小的改动。观察第75行,这里是把被移出屏幕的子View添加到RecycleBin当中,其实也就是说明这个View已经被回收了。那么还记得我们刚刚添加的全局变量mColumnViews吗?它用于缓存每一列的子View,那么当有子View被回收的时候,mColumnViews中也需要进行删除才可以。在第76行,先调用getTag()方法来获取该子View的所处于哪一列,然后调用remove()方法将它移出。第96行处的逻辑是完全相同的,只不过一个是向上移动,一个是向下移动,这里就不再赘述。最重要的修改就是这些了,不过在其它一些地方还做了一些小的改动。观察第75行,这里是把被移出屏幕的子View添加到RecycleBin当中,其实也就是说明这个View已经被回收了。那么还记得我们刚刚添加的全局变量mColumnViews吗?它用于缓存每一列的子View,那么当有子View被回收的时候,mColumnViews中也需要进行删除才可以。在第76行,先调用getTag()方法来获取该子View的所处于哪一列,然后调用remove()方法将它移出。第96行处的逻辑是完全相同的,只不过一个是向上移动,一个是向下移动,这里就不再赘述。最重要的修改就是这些了,不过在其它一些地方还做了一些小的改动。观察第75行,这里是把被移出屏幕的子View添加到RecycleBin当中,其实也就是说明这个View已经被回收了。那么还记得我们刚刚添加的全局变量mColumnViews吗?它用于缓存每一列的子View,那么当有子View被回收的时候,mColumnViews中也需要进行删除才可以。在第76行,先调用getTag()方法来获取该子View的所处于哪一列,然后调用remove()方法将它移出。第96行处的逻辑是完全相同的,只不过一个是向上移动,一个是向下移动,这里就不再赘述。最重要的修改就是这些了,不过在其它一些地方还做了一些小的改动。观察第75行,这里是把被移出屏幕的子View添加到RecycleBin当中,其实也就是说明这个View已经被回收了。那么还记得我们刚刚添加的全局变量mColumnViews吗?它用于缓存每一列的子View,那么当有子View被回收的时候,mColumnViews中也需要进行删除才可以。在第76行,先调用getTag()方法来获取该子View的所处于哪一列,然后调用remove()方法将它移出。第96行处的逻辑是完全相同的,只不过一个是向上移动,一个是向下移动,这里就不再赘述。最重要的修改就是这些了,不过在其它一些地方还做了一些小的改动。观察第75行,这里是把被移出屏幕的子View添加到RecycleBin当中,其实也就是说明这个View已经被回收了。那么还记得我们刚刚添加的全局变量mColumnViews吗?它用于缓存每一列的子View,那么当有子View被回收的时候,mColumnViews中也需要进行删除才可以。在第76行,先调用getTag()方法来获取该子View的所处于哪一列,然后调用remove()方法将它移出。第96行处的逻辑是完全相同的,只不过一个是向上移动,一个是向下移动,这里就不再赘述。接下来让我们回忆一下,ListView最基本的填充方式分为向下填充和向上填充两种,分别对应的方法是fillDown()和fillUp()方法,而这两个方法的触发点都是在fillGap()方法当中的,fillGap()方法又是由trackMotionScroll()方法根据子元素的位置来进行调用的,这个方法只要手指在屏幕上滑动时就会不停进行计算,当有屏幕外的元素需要进入屏幕时,就会调用fillGap()方法来进行填充。那么,trackMotionScroll()方法也许就应该是我们开始着手修改的地方了。其中mColumnCount表示瀑布流布局一共有几列,这里我们先让它分为两列显示,后面随时可以对它进行修改。当然,如果想扩展性做的好的话,也可以使用自定义属性的方式在XML里面指定显示的列数,不过这个功能就不在我们本篇文章的讨论范围之内了。mColumnViews创建了一个长度为mColumnCount的数组,数组中的每个元素都是一个泛型为View的ArrayList,用于缓存对应列的子View。mPosIndexMap则是用于记录每一个位置的子View应当放置在哪一列当中。OK,工作原理确认了之后,接下来的工作就是动手实现了。由于瀑布流这个扩展对ListView整体的改动非常大,我们没办法简单地使用继承来实现,所以只能先将ListView的源码抽取出来,然后对其内部的逻辑进行修改来实现功能,那么我们第一步的工作就是要将ListView的源码抽取出来。但是这个工作并不是那么简单的,因为仅仅ListView这一个单独的类是不能够独立工作的,我们如果要抽取代码的话还需要将AbsListView、AdapterView等也一起抽取出来,然后还会报各种错误都需要一一解决,我当时也是折腾了很久才搞定的。所以这里我就不带着大家一步步对ListView源码进行抽取了,而是直接将我抽取好的工程UIListViewTest上传到了CSDN,大家只需要点击 这里 进行下载就可以了,今天我们所有的代码改动都是在这个工程的基础上进行的。StringBuffer 上的主要操作是 append 和 insert 方法,可重载这些方法,以接受任意类型的数据。每个方法都能有效地将给定的数据转换成字符串,然后将该字符串的字符追加或插入到字符串缓冲区中。append 方法始终将这些字符添加到缓冲区的末端;而 insert 方法则在指定的点添加字符。例如,如果 z 引用一个当前内容是“start”的字符串缓冲区对象,则此方法调用 z.append(\"le\") 会使字符串缓冲区包含“startle”,而 z.insert(4, \"le\") 将更改字符串缓冲区,使之包含“starlet”。"+"最重要的修改就是这些了,不过在其它一些地方还做了一些小的改动。观察第75行,这里是把被移出屏幕的子View添加到RecycleBin当中,其实也就是说明这个View已经被回收了。那么还记得我们刚刚添加的全局变量mColumnViews吗?它用于缓存每一列的子View,那么当有子View被回收的时候,mColumnViews中也需要进行删除才可以。在第76行,先调用getTag()方法来获取该子View的所处于哪一列,然后调用remove()方法将它移出。第96行处的逻辑是完全相同的,只不过一个是向上移动,一个是向下移动,这里就不再赘述。最重要的修改就是这些了,不过在其它一些地方还做了一些小的改动。观察第75行,这里是把被移出屏幕的子View添加到RecycleBin当中,其实也就是说明这个View已经被回收了。那么还记得我们刚刚添加的全局变量mColumnViews吗?它用于缓存每一列的子View,那么当有子View被回收的时候,mColumnViews中也需要进行删除才可以。在第76行,先调用getTag()方法来获取该子View的所处于哪一列,然后调用remove()方法将它移出。第96行处的逻辑是完全相同的,只不过一个是向上移动,一个是向下移动,这里就不再赘述。最重要的修改就是这些了,不过在其它一些地方还做了一些小的改动。观察第75行,这里是把被移出屏幕的子View添加到RecycleBin当中,其实也就是说明这个View已经被回收了。那么还记得我们刚刚添加的全局变量mColumnViews吗?它用于缓存每一列的子View,那么当有子View被回收的时候,mColumnViews中也需要进行删除才可以。在第76行,先调用getTag()方法来获取该子View的所处于哪一列,然后调用remove()方法将它移出。第96行处的逻辑是完全相同的,只不过一个是向上移动,一个是向下移动,这里就不再赘述。最重要的修改就是这些了,不过在其它一些地方还做了一些小的改动。观察第75行,这里是把被移出屏幕的子View添加到RecycleBin当中,其实也就是说明这个View已经被回收了。那么还记得我们刚刚添加的全局变量mColumnViews吗?它用于缓存每一列的子View,那么当有子View被回收的时候,mColumnViews中也需要进行删除才可以。在第76行,先调用getTag()方法来获取该子View的所处于哪一列,然后调用remove()方法将它移出。第96行处的逻辑是完全相同的,只不过一个是向上移动,一个是向下移动,这里就不再赘述。最重要的修改就是这些了,不过在其它一些地方还做了一些小的改动。观察第75行,这里是把被移出屏幕的子View添加到RecycleBin当中,其实也就是说明这个View已经被回收了。那么还记得我们刚刚添加的全局变量mColumnViews吗?它用于缓存每一列的子View,那么当有子View被回收的时候,mColumnViews中也需要进行删除才可以。在第76行,先调用getTag()方法来获取该子View的所处于哪一列,然后调用remove()方法将它移出。第96行处的逻辑是完全相同的,只不过一个是向上移动,一个是向下移动,这里就不再赘述。最重要的修改就是这些了,不过在其它一些地方还做了一些小的改动。观察第75行,这里是把被移出屏幕的子View添加到RecycleBin当中,其实也就是说明这个View已经被回收了。那么还记得我们刚刚添加的全局变量mColumnViews吗?它用于缓存每一列的子View,那么当有子View被回收的时候,mColumnViews中也需要进行删除才可以。在第76行,先调用getTag()方法来获取该子View的所处于哪一列,然后调用remove()方法将它移出。第96行处的逻辑是完全相同的,只不过一个是向上移动,一个是向下移动,这里就不再赘述。最重要的修改就是这些了,不过在其它一些地方还做了一些小的改动。观察第75行,这里是把被移出屏幕的子View添加到RecycleBin当中,其实也就是说明这个View已经被回收了。那么还记得我们刚刚添加的全局变量mColumnViews吗?它用于缓存每一列的子View,那么当有子View被回收的时候,mColumnViews中也需要进行删除才可以。在第76行,先调用getTag()方法来获取该子View的所处于哪一列,然后调用remove()方法将它移出。第96行处的逻辑是完全相同的,只不过一个是向上移动,一个是向下移动,这里就不再赘述。最重要的修改就是这些了,不过在其它一些地方还做了一些小的改动。观察第75行,这里是把被移出屏幕的子View添加到RecycleBin当中,其实也就是说明这个View已经被回收了。那么还记得我们刚刚添加的全局变量mColumnViews吗?它用于缓存每一列的子View,那么当有子View被回收的时候,mColumnViews中也需要进行删除才可以。在第76行,先调用getTag()方法来获取该子View的所处于哪一列,然后调用remove()方法将它移出。第96行处的逻辑是完全相同的,只不过一个是向上移动,一个是向下移动,这里就不再赘述。最重要的修改就是这些了,不过在其它一些地方还做了一些小的改动。观察第75行,这里是把被移出屏幕的子View添加到RecycleBin当中,其实也就是说明这个View已经被回收了。那么还记得我们刚刚添加的全局变量mColumnViews吗?它用于缓存每一列的子View,那么当有子View被回收的时候,mColumnViews中也需要进行删除才可以。在第76行,先调用getTag()方法来获取该子View的所处于哪一列,然后调用remove()方法将它移出。第96行处的逻辑是完全相同的,只不过一个是向上移动,一个是向下移动,这里就不再赘述。最重要的修改就是这些了,不过在其它一些地方还做了一些小的改动。观察第75行,这里是把被移出屏幕的子View添加到RecycleBin当中,其实也就是说明这个View已经被回收了。那么还记得我们刚刚添加的全局变量mColumnViews吗?它用于缓存每一列的子View,那么当有子View被回收的时候,mColumnViews中也需要进行删除才可以。在第76行,先调用getTag()方法来获取该子View的所处于哪一列,然后调用remove()方法将它移出。第96行处的逻辑是完全相同的,只不过一个是向上移动,一个是向下移动,这里就不再赘述。最重要的修改就是这些了,不过在其它一些地方还做了一些小的改动。观察第75行,这里是把被移出屏幕的子View添加到RecycleBin当中,其实也就是说明这个View已经被回收了。那么还记得我们刚刚添加的全局变量mColumnViews吗?它用于缓存每一列的子View,那么当有子View被回收的时候,mColumnViews中也需要进行删除才可以。在第76行,先调用getTag()方法来获取该子View的所处于哪一列,然后调用remove()方法将它移出。第96行处的逻辑是完全相同的,只不过一个是向上移动,一个是向下移动,这里就不再赘述。最重要的修改就是这些了,不过在其它一些地方还做了一些小的改动。观察第75行,这里是把被移出屏幕的子View添加到RecycleBin当中,其实也就是说明这个View已经被回收了。那么还记得我们刚刚添加的全局变量mColumnViews吗?它用于缓存每一列的子View,那么当有子View被回收的时候,mColumnViews中也需要进行删除才可以。在第76行,先调用getTag()方法来获取该子View的所处于哪一列,然后调用remove()方法将它移出。第96行处的逻辑是完全相同的,只不过一个是向上移动,一个是向下移动,这里就不再赘述。最重要的修改就是这些了,不过在其它一些地方还做了一些小的改动。观察第75行,这里是把被移出屏幕的子View添加到RecycleBin当中,其实也就是说明这个View已经被回收了。那么还记得我们刚刚添加的全局变量mColumnViews吗?它用于缓存每一列的子View,那么当有子View被回收的时候,mColumnViews中也需要进行删除才可以。在第76行,先调用getTag()方法来获取该子View的所处于哪一列,然后调用remove()方法将它移出。第96行处的逻辑是完全相同的,只不过一个是向上移动,一个是向下移动,这里就不再赘述。最重要的修改就是这些了,不过在其它一些地方还做了一些小的改动。观察第75行,这里是把被移出屏幕的子View添加到RecycleBin当中,其实也就是说明这个View已经被回收了。那么还记得我们刚刚添加的全局变量mColumnViews吗?它用于缓存每一列的子View,那么当有子View被回收的时候,mColumnViews中也需要进行删除才可以。在第76行,先调用getTag()方法来获取该子View的所处于哪一列,然后调用remove()方法将它移出。第96行处的逻辑是完全相同的,只不过一个是向上移动,一个是向下移动,这里就不再赘述。最重要的修改就是这些了,不过在其它一些地方还做了一些小的改动。观察第75行,这里是把被移出屏幕的子View添加到RecycleBin当中,其实也就是说明这个View已经被回收了。那么还记得我们刚刚添加的全局变量mColumnViews吗?它用于缓存每一列的子View,那么当有子View被回收的时候,mColumnViews中也需要进行删除才可以。在第76行,先调用getTag()方法来获取该子View的所处于哪一列,然后调用remove()方法将它移出。第96行处的逻辑是完全相同的,只不过一个是向上移动,一个是向下移动,这里就不再赘述。接下来让我们回忆一下,ListView最基本的填充方式分为向下填充和向上填充两种,分别对应的方法是fillDown()和fillUp()方法,而这两个方法的触发点都是在fillGap()方法当中的,fillGap()方法又是由trackMotionScroll()方法根据子元素的位置来进行调用的,这个方法只要手指在屏幕上滑动时就会不停进行计算,当有屏幕外的元素需要进入屏幕时,就会调用fillGap()方法来进行填充。那么,trackMotionScroll()方法也许就应该是我们开始着手修改的地方了。其中mColumnCount表示瀑布流布局一共有几列,这里我们先让它分为两列显示,后面随时可以对它进行修改。当然,如果想扩展性做的好的话,也可以使用自定义属性的方式在XML里面指定显示的列数,不过这个功能就不在我们本篇文章的讨论范围之内了。mColumnViews创建了一个长度为mColumnCount的数组,数组中的每个元素都是一个泛型为View的ArrayList,用于缓存对应列的子View。mPosIndexMap则是用于记录每一个位置的子View应当放置在哪一列当中。OK,工作原理确认了之后,接下来的工作就是动手实现了。由于瀑布流这个扩展对ListView整体的改动非常大,我们没办法简单地使用继承来实现,所以只能先将ListView的源码抽取出来,然后对其内部的逻辑进行修改来实现功能,那么我们第一步的工作就是要将ListView的源码抽取出来。但是这个工作并不是那么简单的,因为仅仅ListView这一个单独的类是不能够独立工作的,我们如果要抽取代码的话还需要将AbsListView、AdapterView等也一起抽取出来,然后还会报各种错误都需要一一解决,我当时也是折腾了很久才搞定的。所以这里我就不带着大家一步步对ListView源码进行抽取了,而是直接将我抽取好的工程UIListViewTest上传到了CSDN,大家只需要点击 这里 进行下载就可以了,今天我们所有的代码改动都是在这个工程的基础上进行的。StringBuffer 上的主要操作是 append 和 insert 方法,可重载这些方法,以接受任意类型的数据。每个方法都能有效地将给定的数据转换成字符串,然后将该字符串的字符追加或插入到字符串缓冲区中。append 方法始终将这些字符添加到缓冲区的末端;而 insert 方法则在指定的点添加字符。例如,如果 z 引用一个当前内容是“start”的字符串缓冲区对象,则此方法调用 z.append(\"le\") 会使字符串缓冲区包含“startle”,而 z.insert(4, \"le\") 将更改字符串缓冲区,使之包含“starlet”。"+"最重要的修改就是这些了,不过在其它一些地方还做了一些小的改动。观察第75行,这里是把被移出屏幕的子View添加到RecycleBin当中,其实也就是说明这个View已经被回收了。那么还记得我们刚刚添加的全局变量mColumnViews吗?它用于缓存每一列的子View,那么当有子View被回收的时候,mColumnViews中也需要进行删除才可以。在第76行,先调用getTag()方法来获取该子View的所处于哪一列,然后调用remove()方法将它移出。第96行处的逻辑是完全相同的,只不过一个是向上移动,一个是向下移动,这里就不再赘述。最重要的修改就是这些了,不过在其它一些地方还做了一些小的改动。观察第75行,这里是把被移出屏幕的子View添加到RecycleBin当中,其实也就是说明这个View已经被回收了。那么还记得我们刚刚添加的全局变量mColumnViews吗?它用于缓存每一列的子View,那么当有子View被回收的时候,mColumnViews中也需要进行删除才可以。在第76行,先调用getTag()方法来获取该子View的所处于哪一列,然后调用remove()方法将它移出。第96行处的逻辑是完全相同的,只不过一个是向上移动,一个是向下移动,这里就不再赘述。最重要的修改就是这些了,不过在其它一些地方还做了一些小的改动。观察第75行,这里是把被移出屏幕的子View添加到RecycleBin当中,其实也就是说明这个View已经被回收了。那么还记得我们刚刚添加的全局变量mColumnViews吗?它用于缓存每一列的子View,那么当有子View被回收的时候,mColumnViews中也需要进行删除才可以。在第76行,先调用getTag()方法来获取该子View的所处于哪一列,然后调用remove()方法将它移出。第96行处的逻辑是完全相同的,只不过一个是向上移动,一个是向下移动,这里就不再赘述。最重要的修改就是这些了,不过在其它一些地方还做了一些小的改动。观察第75行,这里是把被移出屏幕的子View添加到RecycleBin当中,其实也就是说明这个View已经被回收了。那么还记得我们刚刚添加的全局变量mColumnViews吗?它用于缓存每一列的子View,那么当有子View被回收的时候,mColumnViews中也需要进行删除才可以。在第76行,先调用getTag()方法来获取该子View的所处于哪一列,然后调用remove()方法将它移出。第96行处的逻辑是完全相同的,只不过一个是向上移动,一个是向下移动,这里就不再赘述。最重要的修改就是这些了,不过在其它一些地方还做了一些小的改动。观察第75行,这里是把被移出屏幕的子View添加到RecycleBin当中,其实也就是说明这个View已经被回收了。那么还记得我们刚刚添加的全局变量mColumnViews吗?它用于缓存每一列的子View,那么当有子View被回收的时候,mColumnViews中也需要进行删除才可以。在第76行,先调用getTag()方法来获取该子View的所处于哪一列,然后调用remove()方法将它移出。第96行处的逻辑是完全相同的,只不过一个是向上移动,一个是向下移动,这里就不再赘述。最重要的修改就是这些了,不过在其它一些地方还做了一些小的改动。观察第75行,这里是把被移出屏幕的子View添加到RecycleBin当中,其实也就是说明这个View已经被回收了。那么还记得我们刚刚添加的全局变量mColumnViews吗?它用于缓存每一列的子View,那么当有子View被回收的时候,mColumnViews中也需要进行删除才可以。在第76行,先调用getTag()方法来获取该子View的所处于哪一列,然后调用remove()方法将它移出。第96行处的逻辑是完全相同的,只不过一个是向上移动,一个是向下移动,这里就不再赘述。最重要的修改就是这些了,不过在其它一些地方还做了一些小的改动。观察第75行,这里是把被移出屏幕的子View添加到RecycleBin当中,其实也就是说明这个View已经被回收了。那么还记得我们刚刚添加的全局变量mColumnViews吗?它用于缓存每一列的子View,那么当有子View被回收的时候,mColumnViews中也需要进行删除才可以。在第76行,先调用getTag()方法来获取该子View的所处于哪一列,然后调用remove()方法将它移出。第96行处的逻辑是完全相同的,只不过一个是向上移动,一个是向下移动,这里就不再赘述。最重要的修改就是这些了,不过在其它一些地方还做了一些小的改动。观察第75行,这里是把被移出屏幕的子View添加到RecycleBin当中,其实也就是说明这个View已经被回收了。那么还记得我们刚刚添加的全局变量mColumnViews吗?它用于缓存每一列的子View,那么当有子View被回收的时候,mColumnViews中也需要进行删除才可以。在第76行,先调用getTag()方法来获取该子View的所处于哪一列,然后调用remove()方法将它移出。第96行处的逻辑是完全相同的,只不过一个是向上移动,一个是向下移动,这里就不再赘述。最重要的修改就是这些了,不过在其它一些地方还做了一些小的改动。观察第75行,这里是把被移出屏幕的子View添加到RecycleBin当中,其实也就是说明这个View已经被回收了。那么还记得我们刚刚添加的全局变量mColumnViews吗?它用于缓存每一列的子View,那么当有子View被回收的时候,mColumnViews中也需要进行删除才可以。在第76行,先调用getTag()方法来获取该子View的所处于哪一列,然后调用remove()方法将它移出。第96行处的逻辑是完全相同的,只不过一个是向上移动,一个是向下移动,这里就不再赘述。最重要的修改就是这些了,不过在其它一些地方还做了一些小的改动。观察第75行,这里是把被移出屏幕的子View添加到RecycleBin当中,其实也就是说明这个View已经被回收了。那么还记得我们刚刚添加的全局变量mColumnViews吗?它用于缓存每一列的子View,那么当有子View被回收的时候,mColumnViews中也需要进行删除才可以。在第76行,先调用getTag()方法来获取该子View的所处于哪一列,然后调用remove()方法将它移出。第96行处的逻辑是完全相同的,只不过一个是向上移动,一个是向下移动,这里就不再赘述。最重要的修改就是这些了,不过在其它一些地方还做了一些小的改动。观察第75行,这里是把被移出屏幕的子View添加到RecycleBin当中,其实也就是说明这个View已经被回收了。那么还记得我们刚刚添加的全局变量mColumnViews吗?它用于缓存每一列的子View,那么当有子View被回收的时候,mColumnViews中也需要进行删除才可以。在第76行,先调用getTag()方法来获取该子View的所处于哪一列,然后调用remove()方法将它移出。第96行处的逻辑是完全相同的,只不过一个是向上移动,一个是向下移动,这里就不再赘述。最重要的修改就是这些了,不过在其它一些地方还做了一些小的改动。观察第75行,这里是把被移出屏幕的子View添加到RecycleBin当中,其实也就是说明这个View已经被回收了。那么还记得我们刚刚添加的全局变量mColumnViews吗?它用于缓存每一列的子View,那么当有子View被回收的时候,mColumnViews中也需要进行删除才可以。在第76行,先调用getTag()方法来获取该子View的所处于哪一列,然后调用remove()方法将它移出。第96行处的逻辑是完全相同的,只不过一个是向上移动,一个是向下移动,这里就不再赘述。最重要的修改就是这些了,不过在其它一些地方还做了一些小的改动。观察第75行,这里是把被移出屏幕的子View添加到RecycleBin当中,其实也就是说明这个View已经被回收了。那么还记得我们刚刚添加的全局变量mColumnViews吗?它用于缓存每一列的子View,那么当有子View被回收的时候,mColumnViews中也需要进行删除才可以。在第76行,先调用getTag()方法来获取该子View的所处于哪一列,然后调用remove()方法将它移出。第96行处的逻辑是完全相同的,只不过一个是向上移动,一个是向下移动,这里就不再赘述。最重要的修改就是这些了,不过在其它一些地方还做了一些小的改动。观察第75行,这里是把被移出屏幕的子View添加到RecycleBin当中,其实也就是说明这个View已经被回收了。那么还记得我们刚刚添加的全局变量mColumnViews吗?它用于缓存每一列的子View,那么当有子View被回收的时候,mColumnViews中也需要进行删除才可以。在第76行,先调用getTag()方法来获取该子View的所处于哪一列,然后调用remove()方法将它移出。第96行处的逻辑是完全相同的,只不过一个是向上移动,一个是向下移动,这里就不再赘述。最重要的修改就是这些了,不过在其它一些地方还做了一些小的改动。观察第75行,这里是把被移出屏幕的子View添加到RecycleBin当中,其实也就是说明这个View已经被回收了。那么还记得我们刚刚添加的全局变量mColumnViews吗?它用于缓存每一列的子View,那么当有子View被回收的时候,mColumnViews中也需要进行删除才可以。在第76行,先调用getTag()方法来获取该子View的所处于哪一列,然后调用remove()方法将它移出。第96行处的逻辑是完全相同的,只不过一个是向上移动,一个是向下移动,这里就不再赘述。接下来让我们回忆一下,ListView最基本的填充方式分为向下填充和向上填充两种,分别对应的方法是fillDown()和fillUp()方法,而这两个方法的触发点都是在fillGap()方法当中的,fillGap()方法又是由trackMotionScroll()方法根据子元素的位置来进行调用的,这个方法只要手指在屏幕上滑动时就会不停进行计算,当有屏幕外的元素需要进入屏幕时,就会调用fillGap()方法来进行填充。那么,trackMotionScroll()方法也许就应该是我们开始着手修改的地方了。其中mColumnCount表示瀑布流布局一共有几列,这里我们先让它分为两列显示,后面随时可以对它进行修改。当然,如果想扩展性做的好的话,也可以使用自定义属性的方式在XML里面指定显示的列数,不过这个功能就不在我们本篇文章的讨论范围之内了。mColumnViews创建了一个长度为mColumnCount的数组,数组中的每个元素都是一个泛型为View的ArrayList,用于缓存对应列的子View。mPosIndexMap则是用于记录每一个位置的子View应当放置在哪一列当中。OK,工作原理确认了之后,接下来的工作就是动手实现了。由于瀑布流这个扩展对ListView整体的改动非常大,我们没办法简单地使用继承来实现,所以只能先将ListView的源码抽取出来,然后对其内部的逻辑进行修改来实现功能,那么我们第一步的工作就是要将ListView的源码抽取出来。但是这个工作并不是那么简单的,因为仅仅ListView这一个单独的类是不能够独立工作的,我们如果要抽取代码的话还需要将AbsListView、AdapterView等也一起抽取出来,然后还会报各种错误都需要一一解决,我当时也是折腾了很久才搞定的。所以这里我就不带着大家一步步对ListView源码进行抽取了,而是直接将我抽取好的工程UIListViewTest上传到了CSDN,大家只需要点击 这里 进行下载就可以了,今天我们所有的代码改动都是在这个工程的基础上进行的。StringBuffer 上的主要操作是 append 和 insert 方法,可重载这些方法,以接受任意类型的数据。每个方法都能有效地将给定的数据转换成字符串,然后将该字符串的字符追加或插入到字符串缓冲区中。append 方法始终将这些字符添加到缓冲区的末端;而 insert 方法则在指定的点添加字符。例如,如果 z 引用一个当前内容是“start”的字符串缓冲区对象,则此方法调用 z.append(\"le\") 会使字符串缓冲区包含“startle”,而 z.insert(4, \"le\") 将更改字符串缓冲区,使之包含“starlet”。"+ "最重要的修改就是这些了,不过在其它一些地方还做了一些小的改动。观察第75行,这里是把被移出屏幕的子View添加到RecycleBin当中,其实也就是说明这个View已经被回收了。那么还记得我们刚刚添加的全局变量mColumnViews吗?它用于缓存每一列的子View,那么当有子View被回收的时候,mColumnViews中也需要进行删除才可以。在第76行,先调用getTag()方法来获取该子View的所处于哪一列,然后调用remove()方法将它移出。第96行处的逻辑是完全相同的,只不过一个是向上移动,一个是向下移动,这里就不再赘述。最重要的修改就是这些了,不过在其它一些地方还做了一些小的改动。观察第75行,这里是把被移出屏幕的子View添加到RecycleBin当中,其实也就是说明这个View已经被回收了。那么还记得我们刚刚添加的全局变量mColumnViews吗?它用于缓存每一列的子View,那么当有子View被回收的时候,mColumnViews中也需要进行删除才可以。在第76行,先调用getTag()方法来获取该子View的所处于哪一列,然后调用remove()方法将它移出。第96行处的逻辑是完全相同的,只不过一个是向上移动,一个是向下移动,这里就不再赘述。最重要的修改就是这些了,不过在其它一些地方还做了一些小的改动。观察第75行,这里是把被移出屏幕的子View添加到RecycleBin当中,其实也就是说明这个View已经被回收了。那么还记得我们刚刚添加的全局变量mColumnViews吗?它用于缓存每一列的子View,那么当有子View被回收的时候,mColumnViews中也需要进行删除才可以。在第76行,先调用getTag()方法来获取该子View的所处于哪一列,然后调用remove()方法将它移出。第96行处的逻辑是完全相同的,只不过一个是向上移动,一个是向下移动,这里就不再赘述。最重要的修改就是这些了,不过在其它一些地方还做了一些小的改动。观察第75行,这里是把被移出屏幕的子View添加到RecycleBin当中,其实也就是说明这个View已经被回收了。那么还记得我们刚刚添加的全局变量mColumnViews吗?它用于缓存每一列的子View,那么当有子View被回收的时候,mColumnViews中也需要进行删除才可以。在第76行,先调用getTag()方法来获取该子View的所处于哪一列,然后调用remove()方法将它移出。第96行处的逻辑是完全相同的,只不过一个是向上移动,一个是向下移动,这里就不再赘述。最重要的修改就是这些了,不过在其它一些地方还做了一些小的改动。观察第75行,这里是把被移出屏幕的子View添加到RecycleBin当中,其实也就是说明这个View已经被回收了。那么还记得我们刚刚添加的全局变量mColumnViews吗?它用于缓存每一列的子View,那么当有子View被回收的时候,mColumnViews中也需要进行删除才可以。在第76行,先调用getTag()方法来获取该子View的所处于哪一列,然后调用remove()方法将它移出。第96行处的逻辑是完全相同的,只不过一个是向上移动,一个是向下移动,这里就不再赘述。最重要的修改就是这些了,不过在其它一些地方还做了一些小的改动。观察第75行,这里是把被移出屏幕的子View添加到RecycleBin当中,其实也就是说明这个View已经被回收了。那么还记得我们刚刚添加的全局变量mColumnViews吗?它用于缓存每一列的子View,那么当有子View被回收的时候,mColumnViews中也需要进行删除才可以。在第76行,先调用getTag()方法来获取该子View的所处于哪一列,然后调用remove()方法将它移出。第96行处的逻辑是完全相同的,只不过一个是向上移动,一个是向下移动,这里就不再赘述。最重要的修改就是这些了,不过在其它一些地方还做了一些小的改动。观察第75行,这里是把被移出屏幕的子View添加到RecycleBin当中,其实也就是说明这个View已经被回收了。那么还记得我们刚刚添加的全局变量mColumnViews吗?它用于缓存每一列的子View,那么当有子View被回收的时候,mColumnViews中也需要进行删除才可以。在第76行,先调用getTag()方法来获取该子View的所处于哪一列,然后调用remove()方法将它移出。第96行处的逻辑是完全相同的,只不过一个是向上移动,一个是向下移动,这里就不再赘述。最重要的修改就是这些了,不过在其它一些地方还做了一些小的改动。观察第75行,这里是把被移出屏幕的子View添加到RecycleBin当中,其实也就是说明这个View已经被回收了。那么还记得我们刚刚添加的全局变量mColumnViews吗?它用于缓存每一列的子View,那么当有子View被回收的时候,mColumnViews中也需要进行删除才可以。在第76行,先调用getTag()方法来获取该子View的所处于哪一列,然后调用remove()方法将它移出。第96行处的逻辑是完全相同的,只不过一个是向上移动,一个是向下移动,这里就不再赘述。最重要的修改就是这些了,不过在其它一些地方还做了一些小的改动。观察第75行,这里是把被移出屏幕的子View添加到RecycleBin当中,其实也就是说明这个View已经被回收了。那么还记得我们刚刚添加的全局变量mColumnViews吗?它用于缓存每一列的子View,那么当有子View被回收的时候,mColumnViews中也需要进行删除才可以。在第76行,先调用getTag()方法来获取该子View的所处于哪一列,然后调用remove()方法将它移出。第96行处的逻辑是完全相同的,只不过一个是向上移动,一个是向下移动,这里就不再赘述。最重要的修改就是这些了,不过在其它一些地方还做了一些小的改动。观察第75行,这里是把被移出屏幕的子View添加到RecycleBin当中,其实也就是说明这个View已经被回收了。那么还记得我们刚刚添加的全局变量mColumnViews吗?它用于缓存每一列的子View,那么当有子View被回收的时候,mColumnViews中也需要进行删除才可以。在第76行,先调用getTag()方法来获取该子View的所处于哪一列,然后调用remove()方法将它移出。第96行处的逻辑是完全相同的,只不过一个是向上移动,一个是向下移动,这里就不再赘述。最重要的修改就是这些了,不过在其它一些地方还做了一些小的改动。观察第75行,这里是把被移出屏幕的子View添加到RecycleBin当中,其实也就是说明这个View已经被回收了。那么还记得我们刚刚添加的全局变量mColumnViews吗?它用于缓存每一列的子View,那么当有子View被回收的时候,mColumnViews中也需要进行删除才可以。在第76行,先调用getTag()方法来获取该子View的所处于哪一列,然后调用remove()方法将它移出。第96行处的逻辑是完全相同的,只不过一个是向上移动,一个是向下移动,这里就不再赘述。最重要的修改就是这些了,不过在其它一些地方还做了一些小的改动。观察第75行,这里是把被移出屏幕的子View添加到RecycleBin当中,其实也就是说明这个View已经被回收了。那么还记得我们刚刚添加的全局变量mColumnViews吗?它用于缓存每一列的子View,那么当有子View被回收的时候,mColumnViews中也需要进行删除才可以。在第76行,先调用getTag()方法来获取该子View的所处于哪一列,然后调用remove()方法将它移出。第96行处的逻辑是完全相同的,只不过一个是向上移动,一个是向下移动,这里就不再赘述。最重要的修改就是这些了,不过在其它一些地方还做了一些小的改动。观察第75行,这里是把被移出屏幕的子View添加到RecycleBin当中,其实也就是说明这个View已经被回收了。那么还记得我们刚刚添加的全局变量mColumnViews吗?它用于缓存每一列的子View,那么当有子View被回收的时候,mColumnViews中也需要进行删除才可以。在第76行,先调用getTag()方法来获取该子View的所处于哪一列,然后调用remove()方法将它移出。第96行处的逻辑是完全相同的,只不过一个是向上移动,一个是向下移动,这里就不再赘述。最重要的修改就是这些了,不过在其它一些地方还做了一些小的改动。观察第75行,这里是把被移出屏幕的子View添加到RecycleBin当中,其实也就是说明这个View已经被回收了。那么还记得我们刚刚添加的全局变量mColumnViews吗?它用于缓存每一列的子View,那么当有子View被回收的时候,mColumnViews中也需要进行删除才可以。在第76行,先调用getTag()方法来获取该子View的所处于哪一列,然后调用remove()方法将它移出。第96行处的逻辑是完全相同的,只不过一个是向上移动,一个是向下移动,这里就不再赘述。最重要的修改就是这些了,不过在其它一些地方还做了一些小的改动。观察第75行,这里是把被移出屏幕的子View添加到RecycleBin当中,其实也就是说明这个View已经被回收了。那么还记得我们刚刚添加的全局变量mColumnViews吗?它用于缓存每一列的子View,那么当有子View被回收的时候,mColumnViews中也需要进行删除才可以。在第76行,先调用getTag()方法来获取该子View的所处于哪一列,然后调用remove()方法将它移出。第96行处的逻辑是完全相同的,只不过一个是向上移动,一个是向下移动,这里就不再赘述。接下来让我们回忆一下,ListView最基本的填充方式分为向下填充和向上填充两种,分别对应的方法是fillDown()和fillUp()方法,而这两个方法的触发点都是在fillGap()方法当中的,fillGap()方法又是由trackMotionScroll()方法根据子元素的位置来进行调用的,这个方法只要手指在屏幕上滑动时就会不停进行计算,当有屏幕外的元素需要进入屏幕时,就会调用fillGap()方法来进行填充。那么,trackMotionScroll()方法也许就应该是我们开始着手修改的地方了。其中mColumnCount表示瀑布流布局一共有几列,这里我们先让它分为两列显示,后面随时可以对它进行修改。当然,如果想扩展性做的好的话,也可以使用自定义属性的方式在XML里面指定显示的列数,不过这个功能就不在我们本篇文章的讨论范围之内了。mColumnViews创建了一个长度为mColumnCount的数组,数组中的每个元素都是一个泛型为View的ArrayList,用于缓存对应列的子View。mPosIndexMap则是用于记录每一个位置的子View应当放置在哪一列当中。OK,工作原理确认了之后,接下来的工作就是动手实现了。由于瀑布流这个扩展对ListView整体的改动非常大,我们没办法简单地使用继承来实现,所以只能先将ListView的源码抽取出来,然后对其内部的逻辑进行修改来实现功能,那么我们第一步的工作就是要将ListView的源码抽取出来。但是这个工作并不是那么简单的,因为仅仅ListView这一个单独的类是不能够独立工作的,我们如果要抽取代码的话还需要将AbsListView、AdapterView等也一起抽取出来,然后还会报各种错误都需要一一解决,我当时也是折腾了很久才搞定的。所以这里我就不带着大家一步步对ListView源码进行抽取了,而是直接将我抽取好的工程UIListViewTest上传到了CSDN,大家只需要点击 这里 进行下载就可以了,今天我们所有的代码改动都是在这个工程的基础上进行的。StringBuffer 上的主要操作是 append 和 insert 方法,可重载这些方法,以接受任意类型的数据。每个方法都能有效地将给定的数据转换成字符串,然后将该字符串的字符追加或插入到字符串缓冲区中。append 方法始终将这些字符添加到缓冲区的末端;而 insert 方法则在指定的点添加字符。例如,如果 z 引用一个当前内容是“start”的字符串缓冲区对象,则此方法调用 z.append(\"le\") 会使字符串缓冲区包含“startle”,而 z.insert(4, \"le\") 将更改字符串缓冲区,使之包含“starlet”。";//转成字符串数组String[] strA=str.split("");Log.i("aa","字符串长度是:"+strA.length);long t1=System.currentTimeMillis();String result = "";for (String s : strA) {result = result + s;}Log.i("aa","使用String拼接耗时  "+(System.currentTimeMillis()-t1)+"  毫秒。");long t2=System.currentTimeMillis();StringBuilder sb=new StringBuilder();for (String s:strA){sb=sb.append(s);}Log.i("aa","使用StringBuilder拼接耗时  "+(System.currentTimeMillis()-t2)+"  毫秒。");long t3=System.currentTimeMillis();StringBuffer sf=new StringBuffer();for (String s:strA){sf=sf.append(s);}Log.i("aa","使用StringBuffer拼接耗时  "+(System.currentTimeMillis()-t3)+"  毫秒。");}

看现象憋说话!还敢乱用字符串吗?

String、StringBuffer、StringBuilder操作字符串耗时对比相关推荐

  1. 浅谈 Java 字符串(String, StringBuffer, StringBuilder)

    我们先要记住三者的特征: String 字符串常量 StringBuffer 字符串变量(线程安全) StringBuilder 字符串变量(非线程安全) 一.定义 查看 API 会发现,String ...

  2. 重温java中的String,StringBuffer,StringBuilder类

    不论什么一个系统在开发的过程中, 相信都不会缺少对字符串的处理. 在 java 语言中, 用来处理字符串的的类经常使用的有 3 个: String.StringBuffer.StringBuilder ...

  3. `java`学习笔记(十二)`Java`--`String``StringBuffer``StringBuilder`

    Java–String&&StringBuffer&&StringBuilder 文章目录 `Java`--`String`&&`StringBuffe ...

  4. String StringBuffer StringBuilder区别与联系

    String     StringBuffer     StringBuilder String的值是不可变的,这就导致每次对String的操作都会生成新的String对象,不仅效率低下,而且浪费大量 ...

  5. String StringBuffer StringBuilder的区别

    简单的事情做到极致也是一种能力. 首先,说一下目前我还没进行整理的情况下,我的理解: String 不可修改 修改后相当于又新创建创建一个字符串 比如: String a = "abc&qu ...

  6. String, StringBuffer, StringBuilder之间的区别

    String与StringBuffer/StringBuilder之间的主要区别 1.String对象不可变, 如果修改会重新创建一个对象, 然后把值保存进去. StringBuffer/String ...

  7. StringBuffer类,StringBuffer类和String的区别、String,StringBuffer,StringBuilder之间的区别

    1.概述 StringBuffer是一个线程安全的可变序列. 2.StringBuffer与String区别 (1)StringBuffer的长度和内容都可以发生改变,String却不行 (2)Str ...

  8. 116day(String,StringBuffer,StringBuilder,模拟器和虚拟机的区别,复合命题的种类)

    <2018年2月4日>[连续116天] 标题:String,StringBuffer,StringBuilder,模拟器和虚拟机的区别,复合命题的种类: 内容: A.详见http://bl ...

  9. Java中的String,StringBuffer,StringBuilder有什么区别?

    相信有很多同学都是经常使用String的,或者也或多或少的听说过StringBuffer,StringBuilder,那么在经常遇见的面试题中(标题),到底这三个的区别是什么呢?让我们来一探究竟! S ...

最新文章

  1. MFC按钮添加提示文字
  2. 《Cisco/H3C交换机配置与管理完全手册(第2版)》终稿封面和目录
  3. 企业移动办公及手机办公方案
  4. linux shell编程语句if、case.
  5. 从零开始学Pytorch(七)之卷积神经网络
  6. input file multiple 配合springmvc实现多文件上传
  7. Docker cpu memory quota使用说明
  8. linux之创建大文件
  9. 深入理解并行编程pdf
  10. linq group by 多个字段取值以及取出重复的数据
  11. php如何替换ico图标,wordpress网站怎么设置更换站点favicon ico图标
  12. 颠覆性创始人Tony Delgado在波多黎各启动编码训练营
  13. java国际化之时区问题处理
  14. 快排算法的针对重复键值的优化
  15. 2017百度之星资格赛1003 度度熊与邪恶大魔王(完全背包)
  16. 如何减轻tomcat压力_6种简单的技巧可帮助您减轻工作压力
  17. 【C Primer Plus】温度转换器
  18. Linux系统中彻底隐藏你的进程(隐藏后如何恢复显示?)
  19. 工作是最好的投资——图书摘录
  20. Android启动摄像机拍照存储展示

热门文章

  1. 智能安防场景:19类物品x光机图像数据集
  2. C语言hist()函数第2篇
  3. java 答题卡_试题八(共15分)阅读以下说明和Java程序代码,将应填入(n) 处的字句写在答题纸的对应栏内。[说明]在 - 赏学吧...
  4. LeetCode——哈希表经典例题
  5. 浅谈Api 签名算法
  6. PCtoLCD取模软件的使用步骤
  7. 航空1553接口测试工装研究
  8. jsp同游网驴友网ssh旅游论坛
  9. 计算机正版化检查,软件正版化检查整改工作报告
  10. python石头剪刀布