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

这个版本的博客写起来颇费口舌,有些代码自己语言组织能力有限,感觉描述起来很费劲,前前后后改了五六遍稿子还是不尽人意 ,不过我还是坚持写出来自己当初的思路,如果看得不明白的地方我在文章最后仍然会上传源代码,可以直接运行看效果,看过运行的效果后对文中有些别扭的语言估计会能直观的了解。在版本3.0的虽然实现了随着手指的左右移动listView中的item也随着滚动,但是会出现如下的情况:

当左边已经是第一个的时候,会出现如下的情况(仍然可以向右移动):

当右边是adapter最后一个item的时候,会出现如下的情况(仍然可以向左移动):

正常来说,当左边第一个和右边最后一个应该不能滚动才是,本4.0版本将解决这个问题。在解决这个问题之前先说说相关的知识点:

知识点1):手指在屏幕上移动的时候,会发生 其他相关方法...>onScroll-->onScroll-->onScroll ..-->其他相关方法.这样的调用

知识点2):3.0版本在处理手指滚动的时候用到了onScroll(MotionEvent e1, MotionEvent e2,float distanceX, float distanceY)这个方法,这个方法中有个distanceX参数,这个参数我们知道,当手指想做移动的时候distanceX>0;而手指向右移动的时候distanceX<0;这是因为distanceX的值是由第二个参数决定的:distanceX = 上次掉用onScroll方法的e2.getX()-当前onScroll方法的e2.getX()或者简写成
lastEvent2.getX() - currentEvent2.getX() = distanceX;

在版本3.0的时候我们直接用distanceX这个变量(确切的说这个变量值的相反数来模拟左右移动滚动的距离),但是这次为了解决上面的问题我们将不再直接用distanceX,而是新定义了两个变量:

变量:preTotalDistanceX :相对于当前onScroll方法调用之前,之前所有onScroll调用所产生的距离之和;比如当前是第n次调用了onScroll,那么preTotalDistanceX=前n-1次调用onScroll中distanceX的累加和;

变量:totalDistanceX:当前调用onScroll方法方法调用中所有distanceX的累加和;比如当前是第n次调用了onScroll方法,那么totalDistanceX就是n个onScrll方法调用中参数里distanceX的累加和;

那么滚动的距离distanceX = totalDistanceX - preTotalDistanceX

用代码表示总距离如下:

            public boolean onScroll(MotionEvent e1, MotionEvent e2,float distanceX, float distanceY) {
			totalDistanceX += distanceX;
			requestLayout();
			return true;

		};

该版本onLayout的方法就修改如下:

		int distanceX = totalDistanceX - preTotalDistanceX;
		removeAnvisiableViews(-distanceX);
		addRightChildViews(-distanceX);
		addLeftChildViews(-distanceX);
		layoutChildViews(-distanceX);
                preTotalDistanceX = totalDistanceX;

要解决文章开头提出的问题,关键是让distanceX = 0;即pretotalDistanceX=totalDistanceX;所以解决问题的关键就是如何让这两个变量相等;从知识点2可以知道,假设用户的手指先右后左:此时最左边的item是adapter的第一个item,所以手指向右移动的时候不能让listView向右滚动,但是实际上随着手指的向右移动totalDistanceX变量是<0,并沿着平面直角坐标系远离0点而负递增,所以在这里可以初步判断:当totalDistanceX<=0的时候,让totalDistanceX
= 0;这样preoTotalDistanceX=totalDistanceX=0,这样就会让distanceX=0,从而不会让我们的ListView不会向右移动;假设用户的手指先左后右的移动方式:当手指向左移动的时候totalDistanceX>0且不断增大,是递增的;而当手指右移动的时候totalDistanceX是在原来的基础上不断减少的过程,当较少到0的时候继续向右移动的话totalDistanceX变为负数,继续向右移动的话就类似与手指先右后左的现象了;这个是关键的地方,整个左右移动的过程发生诡异的变化类似于物理中的位移,当totalDistanceX=0的时候我们可以断定不能在向右滚动。

所以在onLayout代码中我做了如下判断:

@Override
    protected void onLayout(boolean changed, int left, int top, int right,
            int bottom) {

        if (listAdapter == null) {
            return;
        }
        /**确保党左边是第一个的时候不再滚动*/
        if(totalDistanceX<=0) {
            totalDistanceX = 0;
        }

        int distanceX = totalDistanceX - preTotalDistanceX;
        removeAnvisiableViews(-distanceX);
        addRightChildViews(-distanceX);
        addLeftChildViews(-distanceX);
        layoutChildViews(-distanceX);
        preTotalDistanceX = totalDistanceX;

    }

运行一把发现上面的设想是成立的,到此为止,博客开头的第一个问题得到了解决。

下面将解决第二个问题:当adapter里面最后一个item添加到viewGroup里面并且完全显示的时候,禁止listView继续向左滚动。

先看最有一个item没有显示完全的情况,如下图:

解决第二个问题的关键仍然是如何让distanceX= totalDistanceX-pretotalDistanceX=0;也就是如何让totalDistanceX=preototalDistanceX;根据图示我们很容易得出如下结论:要让最后一个item显示完,在之前滚动距离总和的基础上再让listView滚动X大小的距离可以了,用上面的等式表示为totalDistanceX=X+pretotalDistanceX,所以当totalDistanceX>X+pretotalDistanceX的时候我们让 totalDistanceX
= X+preototalDistanceX;在程序用我是用scrollXMax来表示X+preototalDistanceX的值(此变量名起的有点垃圾);在代码用为:

//scrollXMax = X + pretotalDistanceX
if(totalDistanceX>scrollXMax) {
    totalDistanceX = scrollXMax;
}

......
preototalDistanceX = totalDistanceX;

这样当最后一个item滚动了X距离的情况下调用layout绘制到listView之后,手指在移动的情况下if(totalDistanceX>scrollXMax仍然成立)。这样计算的distanceX=0.但是话有说回来了,X+preDistanceX这段代码添加到哪儿呢?结合之前的几篇博客,不难分析出应该在addRightChildViews方法里面添加,代码如下:

private void addRightChildViews(int distanceX) {
		// 2.让屏幕尽可能的显示Item。注意刚开始的时候是没有
		View rightChildView = getChildAt(getChildCount() - 1);

		// 获取此childView右边框距离parentView左边框的距离
		int rightEdge = rightChildView != null ? rightChildView.getRight() : 0;
		while (rightEdge + distanceX < getWidth()
				&& rightIndex < listAdapter.getCount()) {
			View child = listAdapter.getView(rightIndex, null, null);
			child = measureChild(child);
			addViewInLayout(child, -1, child.getLayoutParams(), true);
			rightEdge += child.getMeasuredWidth();

                        //判断最后一个item
			if (rightIndex == listAdapter.getCount() - 1) {
				scrollXMax = rightEdge +preTotalDistanceX- getWidth();
			}

			rightIndex++;
		}
	}

到此位置,上面的的两个问题都得到圆满解决;自己在整这个版本的时候走了不少弯路,捣鼓了半天,到最后完成还是有种小小的成就感;何为编程,说白了就是在遵循特性编程语言规则的情况下,用该编程语言描述或者表达程序员思路的过程。在4.0版本的实现中,自己在纸上又是写又是画的,思路清晰了然后就很自然而然的用编程语言把这个思路表达出来,这就是编程吧!啰嗦完毕,当然该版本还没有完善完毕,比如说不能点击就是这个,将在下一个版本解决剩余的问题,时间允许的话直接写完,此处为项目源码,欢迎批评指正

时间: 2024-10-11 16:28:29

简单的横向ListView实现(version 4.0)的相关文章

简单的横向ListView实现(version 3.0)

版本2只是简单的实现了当手指按下的时候listView的Item向左移动一定的距离,并没有随着手指的左右移动而左右滚动,在这个版本3.0中将会实现随着手指的移动而滚动的目标:当手指向左移动的时候,listView向左滚动:当手指向右移动的时候,listView向右滚动:在开始进入正题之前,先说说预备的知识和涉及到的方法. 在version2.0之前添加View的时候用的都是addView最终辗转调用了addViewInner方法,经过查询viewGroup的源码发现有一个addViewInLay

简单的横向ListView实现(version 1.0)

最近工作不是很忙,就随便按照自己的意愿胡乱整了个小demo,简单的实现横向的ListView:   功能随着版本的增加而完善,包括左右滚动.itemClick等等listView的基本功能: 虽然说demo超级简单,但是真正的写起来倒是废了不小的功夫.废话少说,开始吧. ListView肯定需要一个Adapter对象,这个小demo的核心原理就是循环遍历Adapter里面的子View,并调用子view的layout方法使其按计算的位置横向的排列在ViewGroup上面,就构成了一个横向的一排Vi

简单的横向ListView实现(version 2.0)

版本1.0的横向listView核心只是简单的用layout来进行横向的布局,并没有实现基本的滚动操作,整个屏幕智能显示固定的数目的Item,且Adapter中剩余的View虽然添加到了viewGroup中但是并由于没法滚动无法显示出来,这个版本的横向listView将简单的实现滚动的功能.再说滚动之前的时候需要准备的知识资料如下: 如上图,外层蓝色的矩形框为parentView,黑色的矩形框为childView.其中parentView的左上角是相对于child的坐标原点(0,0);在andr

一个简单的loading动画,version 1.0

一个简单的loading动画:如图 点我查看

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

Android UI开发: 横向ListView(HorizontalListView)及一个简单相册的完整实现 (附源码下载) POSTED ON 2014年6月27日 BY 天边的星星 本文内容: 1.横向ListView的所有实现思路; 2.其中一个最通用的思路HorizontalListView,并基于横向ListView开发一个简单的相册: 3.实现的横向ListView在点击.浏览时item背景会变色,并解决了listview里setSelected造成item的选择状态混乱的问题.

Android-搭建简单服务端+ListView异步加载数据

Android-搭建简单服务端+ListView异步加载数据 2014年5月6日 本篇博文带给大家的是教大家如何在MyEclipse中搭建一个服务端,并通过手机端与其通信,异步加载数据. 笔者使用的是MyEclipse,各位也可以直接用Eclipse创建Java Web项目,谷歌提供的ADT Bundle是不能创建Web项目,读者可以下载Eclipse For JaveEE Developer这个IDE. 下面来介绍如何在MyEclipse创建一个Web项目,并部署到Tomcat当中,关于Tom

项目总结--Version 1.0(三)

可扩展性决定了项目能走多远,可复用行决定了项目走的是否轻快. 本文主要讨论1.0版本的项目在进行设计时对可复用性和可扩展性的思考,涉及了整个项目分层的所有层(想查阅分层相关部分的可以点这:项目总结--Version 1.0(一)和项目总结--Version 1.0(二)). 由于经验有限,做过多的扩展容易误导其他人,所以本文所做的一些讨论总结只限在本项目范围内进行,对这个项目在进行架构设计的时候遇到的问题和自己的一些想法在此做一些梳理和总结. 同样的,先从最底层-数据持久层开始说起.先看一下数据

PopupWindow弹出产品属性+横向ListView HorizontialList实现产品属性

先来张效果图吧~ 先说下思路吧: 这是个商品详情页,然后商品页面里面使用layoutInflater获取出要弹出框框的view,当然了,这里面参数的加载数据也就写在这个popwindow里面啦. 开始贴代码了 商品弹出框布局:(下面的购物车和购买偷懒直接设定了宽度) activity_product_attribute.xml <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:an

必须添加对程序集“EntityFramework, Version=5.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089”的引用。

我在使用mvc时候.遇到的一个问题...  必须添加对程序集"EntityFramework, Version=5.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"的引用. 下面是解决方法 关于我们在使用ASP.NET  MVC架构时候...在Model中创建了实体框架EF...如图 我们需要在DAL中使用Entity来操作数据库,执行一些查询等crud操作的时候... 我们在dal中获的entity... 然后我们再创建