自定义博客皮肤VIP专享

*博客头图:

格式为PNG、JPG,宽度*高度大于1920*100像素,不超过2MB,主视觉建议放在右侧,请参照线上博客头图

请上传大于1920*100像素的图片!

博客底图:

图片格式为PNG、JPG,不超过1MB,可上下左右平铺至整个背景

栏目图:

图片格式为PNG、JPG,图片宽度*高度为300*38像素,不超过0.5MB

主标题颜色:

RGB颜色,例如:#AFAFAF

Hover:

RGB颜色,例如:#AFAFAF

副标题颜色:

RGB颜色,例如:#AFAFAF

自定义博客皮肤

-+
  • 博客(7)
  • 资源 (39)
  • 收藏
  • 关注

原创 Tetris Bomb

Tetris Bomb

2022-10-31 00:27:44 85 1

原创 NOTE 隐私保护(Privacy Protection Agreement)

NOTE 帮助用户记录平时重要信息,重要笔记,日常消费等信息;

2022-10-23 11:03:27 94

原创 如何成为一名优秀程序猿具备哪些?程序猿一生

程序猿一生

2022-10-15 13:00:30 223

转载 mysql windows 配置

mysql windows 配置。

2022-10-08 17:52:38 708

原创 Good choice 隐私保护

good choice 帮助你选择一个工具。

2022-10-02 21:04:18 175

原创 SSL 申请 到制作,Java 代码关联

ssl 申请,配置,关联java 代码

2022-09-23 00:07:51 703

原创 Ysight App Tech Support

Ysight是一款通过wifi可以查看微距摄像图像的软件应用工具 ,通过它去连接设备的wifi,实现本地话,无流量的一个好的应用,实现智能互联网+的设备。使用方法:第1步:开启手机wifi。第2步:打开设备wifi, 通过手机的wifi 去连接。第3步:提示连接成功,打开Ysight,点开始按钮,会进入视频预览画面第4步:如果1,2,3 成功会预览到设备的视频画面。如果失败看不到任何画面。第5步:如果第2步失败,不会进入第3步。承诺项:Ysight 尊重并保护所有使用服务用户

2022-02-07 18:43:49 3433

onvif 资料

onvif 1手资料,都是自己整理的。从不懂到懂的过程。。如果你是新手对onvif ,刚接触,,值得你去下载,去看。如果你是熟手。里面有很多例子,也值得你去 看看。还有很多网址。。。

2012-11-13

视频 显示 gdi

视频 显示 gdi++ DirectDraw VC++ 加载视频 显示。主,离面切换。多通道。

2012-11-12

onvif 协议

onvif 协议

2012-11-12

ffmpeg 源码

ffmpeg 源码 流媒体 ,自己看。。

2012-11-12

SearchIPCam.exe

SearchIPCam.exe ip 查看工具 局域网

2012-11-12

h264 解码器 源码

h264 解码器 源码 H264流媒体源代码和相关资料.rar 不下别后悔。

2012-11-12

soap 协议工具

gSOAP编译工具提供了一个SOAP/XML 关于C/C++ 语言的实现,从而让C/C++语言开发web服务或客户端程序的工作变得轻松了很多。绝大多数的C++web服务工具包提供一组API函数类库来处理特定的SOAP数据结构,这样就使得用户必须改变程序结构来适应相关的类库。与之相反,gSOAP利用编译器技术提供了一组透明化的SOAP API,并将与开发无关的SOAP实现细节相关的内容对用户隐藏起来。 ONVIF规范中设备管理和控制部分所定义的接口均以Web Services的形式提供。ONVIF规范涵盖了完全的XML及WSDL的定义。每一个支持ONVIF规范的终端设备均须提供与功能相应的Web Service。服务端与客户端的数据交互采用SOAP协议。 ONVIF中的其他部分比如音视频流则通过RTP/RTSP进行 。 那么WebServices、SOAP、WSDL、gSOAP又都是什么? 假如我们需要开发一个linux上的app,这个app需要与远端的Web服务有一个交互,比如获取一个运算结果、或者是天气等,那么我们就需要使用WebServices。 Web Services可以概述为: Web Services 可以将应用程序转换为网络应用程序。 通过使用 Web Services,应用程序可以向全世界发布信息,或提供某项功能。 Web Services 可以被其他应用程序使用。 通过 Web Services,会计部门的 Win 服务器可以与 IT 供应商的 UNIX 服务器相连接。 基本的 Web Services 平台是 XML+HTTP。 Web services 使用 XML 来编解码数据,并使用 SOAP 来传输数据。 SOAP又是什么? SOAP 是基于 XML 的简易协议,可使应用程序在 HTTP 之上进行信息交换。或者更简单地说:SOAP 是用于访问网络服务的协议。 对于应用程序开发来说,使程序之间进行因特网通信是很重要的。目前的应用程序通过使用远程过程调用(RPC)在诸如 DCOM 与 CORBA 等对象之间进行通信,但是 HTTP 不是为此设计的。RPC 会产生兼容性以及安全问题;防火墙和代理服务器通常会阻止此类流量。通过 HTTP 在应用程序间通信是更好的方法,因为 HTTP 得到了所有的因特网浏览器及服务器的支持。SOAP 就是被创造出来完成这个任务的。SOAP 提供了一种标准的方法,使得运行在不同的操作系统并使用不同的技术和编程语言的应用程序可以互相进行通信。 如何实现SOAP? 我们要知道SOAP协议是基于XML的,那么如何能够将他们嵌入到C/C++的应用程序里使用? gSOAP编译工具就提供了一个SOAP/XML 关于C/C++ 语言的实现,从而让C/C++语言开发web服务或客户端程序的工作变得轻松了很多。将与开发无关的SOAP协议的实现细节相关的内容对开发人员隐藏起来。因为SOAP提供的是一种标准化的方法,gSOAP的编译器能够自动的将用户定义的本地化的C或C++数据类型转变为符合XML语法的数据结构,这样,只用一组简单的API就将用户从SOAP细节实现工作中解脱了出来,可以专注与应用程序逻辑的实现工作了。并且可以跨越多个操作系统、语言环境以及在防火墙后的不同组织。 更直白的说,使用gSOAP可以产生用于开发Web Services的SOAP通信协议方面的代码框架,开发人员只需要实现server的被调用的函数,然后在client端就可以像调用本地函数一样调用在远端的函数。gSOAP包含两个工具wsdl2h和soapcpp2,用来产生代码框架。 开发Web服务程序,需使用gSOAP生成服务器端和客户端代码框架(通常情况下之需要实现server端或者实现client,因为另一端通常是别人做好的,比如ipnc中的onvif,实现的server端)。我们有两种做法: 编写WSDL,使用wsdl2h生成头文件,再soapcpp2生成框架代码; 编写头文件,使用soapcpp2生成框架代码; 这两种方式,结果是一样的,最终都有产生头文件,并生成代码。不同在于,在项目的开发中需要维护的文件不同,前者是需要维护WSDL文件,后者维护头文件。 SOAP调用示例 下面就使用第二种方法来实现一个简单的通信实例:在远端实现两数相加,然后返回运算结果。 1、下载gSOAP 我使用的版本时2.8.8,http://www.kuaipan.cn/file/id_48923272389088693.htm gSOAP-2.8软件包不需要安装,直接解压,在gsoap-2.8\gsoap\bin目录下是上面提到的两个命令行工具,包含win32、linux、maxOS等三种版本,在使用soapcpp2生产代码框架时一般需要gsoap-2.8\gsoap\import目录下和gsoap-2.8\gsoap\custom的 文件。在命令行中使用-I<PATH>包含进来即可。 2、编写头文件:add.h 在这里我们不需要wsdl的文件,可以直接从.h文件来生成代码。我们定义一个函数声明文件,用来定义接口函数,名称为add.h [cpp] view plaincopyprint?//gsoapopt cw //gsoap ns2 schema namespace: urn:add //gsoap ns2 schema form: unqualified //gsoap ns2 service name: add //gsoap ns2 service type: addPortType //gsoap ns2 service port:http://websrv.cs.fsu.edu/~engelen/addserver.cgi //gsoap ns2 service namespace: urn:add //gsoap ns2 service transport: http://schemas.xmlsoap.org/soap/http //gsoap ns2 service method-style: add rpc //gsoap ns2 service method-encoding: add http://schemas.xmlsoap.org/soap/encoding/ //gsoap ns2 service method-action: add "" int ns2__add( int num1, int num2, int* sum ); //gsoapopt cw //gsoap ns2 schema namespace: urn:add //gsoap ns2 schema form: unqualified //gsoap ns2 service name: add //gsoap ns2 service type: addPortType //gsoap ns2 service port:http://websrv.cs.fsu.edu/~engelen/addserver.cgi //gsoap ns2 service namespace: urn:add //gsoap ns2 service transport: http://schemas.xmlsoap.org/soap/http //gsoap ns2 service method-style: add rpc //gsoap ns2 service method-encoding: add http://schemas.xmlsoap.org/soap/encoding/ //gsoap ns2 service method-action: add "" int ns2__add( int num1, int num2, int* sum );3、产生代码框架 我们执行一下命令,自动生成一些远程调用需要的文件。(先将他们加如到系统环境变量中) soapcpp2 -c add.h -c是产生纯C代码,如果提示找不到typemap.dat,将gsoap-2.8\gsoap下的typemap.dat复制到当前目录就可以了。通过上列命令我们会得到如下文件: 先大概记住他们的名字,将来会提到他们。 4、添加服务端代码,创建文件:addserver.c [cpp] view plaincopyprint?#include "soapH.h" #include "add.nsmap" int main(int argc, char **argv) { int m, s; struct soap add_soap; soap_init(&add;_soap); soap_set_namespaces(&add;_soap, namespaces); if (argc < 2) { printf("usage: %s <server_port> \n", argv[0]); exit(1); } else { m = soap_bind(&add;_soap, NULL, atoi(argv[1]), 100); if (m < 0) { soap_print_fault(&add;_soap, stderr); exit(-1); } fprintf(stderr, "Socket connection successful: master socket = %d\n", m); for (;;) { s = soap_accept(&add;_soap); if (s < 0) { soap_print_fault(&add;_soap, stderr); exit(-1); } fprintf(stderr, "Socket connection successful: slave socket = %d\n", s); soap_serve(&add;_soap); soap_end(&add;_soap); } } return 0; } #if 1 int ns2__add(struct soap *add_soap, int num1, int num2, int *sum) { *sum = num1 + num2; return 0; } #endif #include "soapH.h" #include "add.nsmap" int main(int argc, char **argv) { int m, s; struct soap add_soap; soap_init(&add;_soap); soap_set_namespaces(&add;_soap, namespaces); if (argc < 2) { printf("usage: %s <server_port> \n", argv[0]); exit(1); } else { m = soap_bind(&add;_soap, NULL, atoi(argv[1]), 100); if (m < 0) { soap_print_fault(&add;_soap, stderr); exit(-1); } fprintf(stderr, "Socket connection successful: master socket = %d\n", m); for (;;) { s = soap_accept(&add;_soap); if (s < 0) { soap_print_fault(&add;_soap, stderr); exit(-1); } fprintf(stderr, "Socket connection successful: slave socket = %d\n", s); soap_serve(&add;_soap); soap_end(&add;_soap); } } return 0; } #if 1 int ns2__add(struct soap *add_soap, int num1, int num2, int *sum) { *sum = num1 + num2; return 0; } #endif 5、添加客户端代码,创建文件:addclient.c [cpp] view plaincopyprint?#include "soapStub.h" #include "add.nsmap" int add(const char *server, int num1, int num2, int *sum) { struct soap add_soap; int result = 0; soap_init(&add;_soap); soap_set_namespaces(&add;_soap, namespaces); soap_call_ns2__add(&add;_soap, server, NULL, num1, num2, sum); printf("server is %s, num1 is %d, num2 is %d/n", server, num1, num2); if (add_soap.error) { printf("soap error: %d, %s, %s\n", add_soap.error, *soap_faultcode(&add;_soap), *soap_faultstring(&add;_soap)); result = add_soap.error; } soap_end(&add;_soap); soap_done(&add;_soap); return result; } #include "soapStub.h" #include "add.nsmap" int add(const char *server, int num1, int num2, int *sum) { struct soap add_soap; int result = 0; soap_init(&add;_soap); soap_set_namespaces(&add;_soap, namespaces); soap_call_ns2__add(&add;_soap, server, NULL, num1, num2, sum); printf("server is %s, num1 is %d, num2 is %d/n", server, num1, num2); if (add_soap.error) { printf("soap error: %d, %s, %s\n", add_soap.error, *soap_faultcode(&add;_soap), *soap_faultstring(&add;_soap)); result = add_soap.error; } soap_end(&add;_soap); soap_done(&add;_soap); return result; }6、写客户端测试代码,创建文件:addtest.c [cpp] view plaincopyprint?#include <stdio.h> #include <stdlib.h> #include <string.h> int add(const char *server, int num1, int num2, int *sum); int main(int argc, char **argv) { int result = -1; char server[128] = {0}; int num1; int num2; int sum; if (argc < 4) { printf("usage: %s <ip:port> num1 num2 \n", argv[0]); exit(1); } strcpy(server,argv[1]); num1 = atoi(argv[2]); num2 = atoi(argv[3]); result = add(server, num1, num2,&sum;); if (result != 0) { printf("soap error, errcode=%d\n", result); } else { printf("%d + %d = %d\n", num1, num2, sum); } return 0; } #include <stdio.h> #include <stdlib.h> #include <string.h> int add(const char *server, int num1, int num2, int *sum); int main(int argc, char **argv) { int result = -1; char server[128] = {0}; int num1; int num2; int sum; if (argc < 4) { printf("usage: %s <ip:port> num1 num2 \n", argv[0]); exit(1); } strcpy(server,argv[1]); num1 = atoi(argv[2]); num2 = atoi(argv[3]); result = add(server, num1, num2,&sum;); if (result != 0) { printf("soap error, errcode=%d\n", result); } else { printf("%d + %d = %d\n", num1, num2, sum); } return 0; }7、编写Makefile,编译前,先将gsoap-2.8\gsoap目录下的stdsoap2.c和stdsoap2.h复制到当前目录下,它提供了对SOAP协议的简单调用。 [cpp] view plaincopyprint?GSOAP_ROOT = /root/onvif/gsoap-2.8/gsoap CC = gcc -g -DWITH_NONAMESPACES INCLUDE = -I$(GSOAP_ROOT) SERVER_OBJS = soapC.o stdsoap2.o soapServer.o addserver.o CLIENT_OBJS = soapC.o stdsoap2.o soapClient.o addclient.o addtest.o all: server server: $(SERVER_OBJS) $(CC) $(INCLUDE) -o addserver $(SERVER_OBJS) client: $(CLIENT_OBJS) $(CC) $(INCLUDE) -o addtest $(CLIENT_OBJS) clean: rm -f *.o addtest GSOAP_ROOT = /root/onvif/gsoap-2.8/gsoap CC = gcc -g -DWITH_NONAMESPACES INCLUDE = -I$(GSOAP_ROOT) SERVER_OBJS = soapC.o stdsoap2.o soapServer.o addserver.o CLIENT_OBJS = soapC.o stdsoap2.o soapClient.o addclient.o addtest.o all: server server: $(SERVER_OBJS) $(CC) $(INCLUDE) -o addserver $(SERVER_OBJS) client: $(CLIENT_OBJS) $(CC) $(INCLUDE) -o addtest $(CLIENT_OBJS) clean: rm -f *.o addtest 8、编译服务端make server,编译客户端make client 得到addserver和addtest 9、测试 一个最简单的soap调用的例子完成了。 实例分析 服务端代码 下面我们来分析上面的例子,刚才我们只是创建一个add.h头文件,在add.h头文件中声明了一个函数: [cpp] view plaincopyprint?int ns2__add( int num1, int num2, int* sum ); int ns2__add( int num1, int num2, int* sum );其他所有的的代码都是一句他来生成的。那么这个的实体在哪?对,就是在需要我们自己添加的addserver.c中: 但是它好像多了一个struct soap类型的参数,这是soap全局运行环境,所有的函数都第一个包含这个参数。注意上面的Makefile,不管是编译server还是编译client都是没有用到刚才的add.h文件的。ns2__add真正的声明在自动产生的soapStub.h中 然后在自动产生的soapServer.c中被soap_serve_ns2__add()函数调用。这样,就将真正的加法运算的ns2__add函数和soap代码框架联系了起来。那么,在客户端的代码中又是怎样来调用这个远程函数的呢? 客户端代码 在刚才添加的addtest.c中main函数中调用一个简单的add函数 这个函数的实现也是我们自己添加的,在addclient.c中: 这个函数有些复杂,因为它把客户端的调用和soap联系了起来,还记得吗,我们编译server和client的时候复制了两个文件stdsoap2.h和stdsoap2.c,这里面的soap_init() soap_end()等函数来自他们。stdsoap2提供了soap协议的简单操作,之需要简单的函数调用就能完成远程的函数调用。注意soap_call_ns2__add(),它同样在soapStub.h中声明,只不过是Client-Side Call Stubs,不明白stub意思的可以搜索rpc 这个函数的实现在自动产生的soapClient.c源文件中。同样不需要我们实现。 这样就可以通过调用gSOAP提供的stdsoap2的soap_init和自动产生的soap_call_ns2__add就实现了远程主机上的ns2__add函数的调用

2012-11-12

clarity 采集器 源码提供

clarity 采集器 和其他 源码提供 clarity 采集器和其他 源码提供 clarity 采集器 和其他 源码提供

2011-10-30

C++ VC++ 设计模式 抽象模式

设计模式里面 抽象模式,有例子 C++ VC++

2011-01-23

设计模式 工厂模式 VC++

设计模式 工厂模式 VC++ C++ 源程序

2011-01-23

串口测试程序 C++

一个不错的 工具,专门用来测试 串口是否连通。可以测试看下,有帮助。专门为程序员打造。

2011-01-23

无线网络中的组播技术

无线网络中的组播技术 非常详细。对于初学者及 公司开发都比较有用

2009-05-21

vc++ 控件 大全

很不错的c++ 程序 专门描述vc++控件使用的

2009-05-20

读配置文件 vc++ 源程序

很不错的 读配置文件的源程序。用vc++ 开发的。功能很强大

2009-05-20

聊天系统服务器和客户端

牛b 牛b 牛b 牛b牛b 牛b牛b牛b牛b牛b牛b牛b牛b牛b牛b

2009-03-27

2BBox控件使用大全

2BBox控件使用大全 2BBox控件使用大全2BBox控件使用大全 2BBox控件使用大全

2009-03-27

vc内幕第四版本 好书

vc内幕第四版本 vc6 内幕vc内 幕vc内 幕vc内幕

2009-03-27

网络五子棋网络五子棋

很好的java程序!!!!!!!! 很好的java程序!!!!!!!! 很好的java程序!!!!!!!!

2009-03-17

程序员面霸手册.pdf

程序员面霸手册 程序员面霸手册 程序员面霸手册 程序员面霸手册

2009-03-15

jpeg ios .a 静态库 libjpeg-turbo

jpeg ios .a 静态库 libjpeg-turbo

2021-12-09

mp4v2-2.0.0

mp4v2 包含源码,以及android jni 编译完整工程。给苦恼寻找,编译出问题的使用。

2018-12-25

cordova js android

这份代码 覆盖了,cordova 和原生APP 交互 关键技术和代码。能从H5(JS)通过CORDOVA 到原生APP,处理完数据后结果返回给H5页面。 代码中提供cordova 源码。和android 原生关键技术代码。前提你得知道怎么引入。然后修改替换即可。

2017-03-14

滑动关闭打开

滑动关闭/打开, 解锁。打电话解锁

2016-11-11

谷歌glassess

谷歌眼镜DEMO 能运行于谷歌眼镜

2016-11-11

H265编码器

H265 编码,含个环境配置文件,里面已经生成了1个VC++2010的代码。 只要通过CMAKE工具就能生成。

2016-08-08

android studio 配置

该文档描述了 eclipse 开发工具,到 android studio 工具的应用,遇到的一些问题,和思维转变。以及遇到的一些配置,低版本兼容问题。文档以配图的方式展现出来。

2016-07-15

ViewPager 放大缩小左右移动

实现 图片的放大,缩小,左右屏幕滑动 。 直接贴代码吧。。 public class ViewPager extends ViewGroup { private static final String TAG = "ViewPager"; private static final boolean DEBUG = false; private static final boolean USE_CACHE = false; private static final int DEFAULT_OFFSCREEN_PAGES = 1; private static final int MAX_SETTLE_DURATION = 600; // ms private static final int PAGER_NEXT_MARGIN_DP = 40; static class ItemInfo { Object object; int position; boolean scrolling; } private static final Comparator<ItemInfo> COMPARATOR = new Comparator<ItemInfo>() { @Override public int compare(ItemInfo lhs, ItemInfo rhs) { return lhs.position - rhs.position; } }; private static final Interpolator sInterpolator = new Interpolator() { public float getInterpolation(float t) { // _o(t) = t * t * ((tension + 1) * t + tension) // o(t) = _o(t - 1) + 1 t -= 1.0f; return t * t * t + 1.0f; } }; private final ArrayList<ItemInfo> mItems = new ArrayList<ItemInfo>(); private PagerAdapter mAdapter; private int mCurItem; // Index of currently displayed page. private int mRestoredCurItem = -1; private Parcelable mRestoredAdapterState = null; private ClassLoader mRestoredClassLoader = null; private Scroller mScroller; private PagerAdapter.DataSetObserver mObserver; private int mPageMargin; private Drawable mMarginDrawable; private int mChildWidthMeasureSpec; private int mChildHeightMeasureSpec; private boolean mInLayout; private boolean mScrollingCacheEnabled; private boolean mPopulatePending; private boolean mScrolling; private int mOffscreenPageLimit = DEFAULT_OFFSCREEN_PAGES; private boolean mIsBeingDragged; private boolean mIsUnableToDrag; private int mTouchSlop; private float mInitialMotionX; /** * Position of the last motion event. */ private float mLastMotionX; private float mLastMotionY; /** * ID of the active pointer. This is used to retain consistency during * drags/flings if multiple pointers are used. */ private int mActivePointerId = INVALID_POINTER; /** * Sentinel value for no current active pointer. Used by * {@link #mActivePointerId}. */ private static final int INVALID_POINTER = -1; /** * Determines speed during touch scrolling */ private VelocityTracker mVelocityTracker; private int mMinimumVelocity; private int mMaximumVelocity; private float mBaseLineFlingVelocity; private float mFlingVelocityInfluence; private int mPagerNextMarginPixels; private boolean mFakeDragging; private long mFakeDragBeginTime; private EdgeEffectCompat mLeftEdge; private EdgeEffectCompat mRightEdge; private boolean mFirstLayout = true; private OnPageChangeListener mOnPageChangeListener; /** * Indicates that the pager is in an idle, settled state. The current page * is fully in view and no animation is in progress. */ public static final int SCROLL_STATE_IDLE = 0; /** * Indicates that the pager is currently being dragged by the user. */ public static final int SCROLL_STATE_DRAGGING = 1; /** * Indicates that the pager is in the process of settling to a final * position. */ public static final int SCROLL_STATE_SETTLING = 2; private int mScrollState = SCROLL_STATE_IDLE; /** * Callback interface for responding to changing state of the selected page. */ public interface OnPageChangeListener { /** * This method will be invoked when the current page is scrolled, either * as part of a programmatically initiated smooth scroll or a user * initiated touch scroll. * * @param position * Position index of the first page currently being * displayed. Page position+1 will be visible if * positionOffset is nonzero. * @param positionOffset * Value from [0, 1) indicating the offset from the page at * position. * @param positionOffsetPixels * Value in pixels indicating the offset from position. */ public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels); /** * This method will be invoked when a new page becomes selected. * Animation is not necessarily complete. * * @param position * Position index of the new selected page. */ public void onPageSelected(int position, int prePosition); /** * Called when the scroll state changes. Useful for discovering when the * user begins dragging, when the pager is automatically settling to the * current page, or when it is fully stopped/idle. * * @param state * The new scroll state. * @see ViewPager#SCROLL_STATE_IDLE * @see ViewPager#SCROLL_STATE_DRAGGING * @see ViewPager#SCROLL_STATE_SETTLING */ public void onPageScrollStateChanged(int state); } /** * Simple implementation of the {@link OnPageChangeListener} interface with * stub implementations of each method. Extend this if you do not intend to * override every method of {@link OnPageChangeListener}. */ public static class SimpleOnPageChangeListener implements OnPageChangeListener { @Override public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { // This space for rent } @Override public void onPageSelected(int position, int prePosition) { // This space for rent } @Override public void onPageScrollStateChanged(int state) { // This space for rent } } public ViewPager(Context context) { super(context); initViewPager(); } public ViewPager(Context context, AttributeSet attrs) { super(context, attrs); initViewPager(); } void initViewPager() { setWillNotDraw(false); setDescendantFocusability(FOCUS_AFTER_DESCENDANTS); setFocusable(true); final Context context = getContext(); mScroller = new Scroller(context, sInterpolator); final ViewConfiguration configuration = ViewConfiguration.get(context); mTouchSlop = ViewConfigurationCompat .getScaledPagingTouchSlop(configuration); mMinimumVelocity = configuration.getScaledMinimumFlingVelocity(); mMaximumVelocity = configuration.getScaledMaximumFlingVelocity(); mLeftEdge = new EdgeEffectCompat(context); mRightEdge = new EdgeEffectCompat(context); float density = context.getResources().getDisplayMetrics().density; mBaseLineFlingVelocity = 2500.0f * density; mFlingVelocityInfluence = 0.4f; final float scale = getResources().getDisplayMetrics().density; mPagerNextMarginPixels = (int) (PAGER_NEXT_MARGIN_DP * scale + 0.5f); } private void setScrollState(int newState) { if (mScrollState == newState) { return; } mScrollState = newState; if (mOnPageChangeListener != null) { mOnPageChangeListener.onPageScrollStateChanged(newState); } } public void setAdapter(PagerAdapter adapter) { if (mAdapter != null) { mAdapter.setDataSetObserver(null); mAdapter.startUpdate(this); for (int i = 0; i < mItems.size(); i++) { final ItemInfo ii = mItems.get(i); mAdapter.destroyItem(this, ii.position, ii.object); } mAdapter.finishUpdate(this); mItems.clear(); removeAllViews(); mCurItem = 0; scrollTo(0, 0); } mAdapter = adapter; if (mAdapter != null) { if (mObserver == null) { mObserver = new DataSetObserver(); } mAdapter.setDataSetObserver(mObserver); mPopulatePending = false; if (mRestoredCurItem >= 0) { mAdapter.restoreState(mRestoredAdapterState, mRestoredClassLoader); setCurrentItemInternal(mRestoredCurItem, false, true); mRestoredCurItem = -1; mRestoredAdapterState = null; mRestoredClassLoader = null; } else { populate(); } } } public PagerAdapter getAdapter() { return mAdapter; } /** * Set the currently selected page. If the ViewPager has already been * through its first layout there will be a smooth animated transition * between the current item and the specified item. * * @param item * Item index to select */ public void setCurrentItem(int item) { mPopulatePending = false; setCurrentItemInternal(item, !mFirstLayout, false); } /** * Set the currently selected page. * * @param item * Item index to select * @param smoothScroll * True to smoothly scroll to the new item, false to transition * immediately */ public void setCurrentItem(int item, boolean smoothScroll) { mPopulatePending = false; setCurrentItemInternal(item, smoothScroll, false); } public int getCurrentItem() { return mCurItem; } void setCurrentItemInternal(int item, boolean smoothScroll, boolean always) { setCurrentItemInternal(item, smoothScroll, always, 0); } void setCurrentItemInternal(int item, boolean smoothScroll, boolean always, int velocity) { int preItem = mCurItem; if (mAdapter == null || mAdapter.getCount() <= 0) { setScrollingCacheEnabled(false); return; } if (!always && mCurItem == item && mItems.size() != 0) { setScrollingCacheEnabled(false); return; } if (item < 0) { item = 0; } else if (item >= mAdapter.getCount()) { item = mAdapter.getCount() - 1; } final int pageLimit = mOffscreenPageLimit; if (item > (mCurItem + pageLimit) || item < (mCurItem - pageLimit)) { // We are doing a jump by more than one page. To avoid // glitches, we want to keep all current pages in the view // until the scroll ends. for (int i = 0; i < mItems.size(); i++) { mItems.get(i).scrolling = true; } } final boolean dispatchSelected = mCurItem != item; mCurItem = item; populate(); final int destX = (getWidth() + mPageMargin) * item; if (smoothScroll) { smoothScrollTo(destX, 0, velocity); if (dispatchSelected && mOnPageChangeListener != null) { mOnPageChangeListener.onPageSelected(item, preItem); } } else { if (dispatchSelected && mOnPageChangeListener != null) { mOnPageChangeListener.onPageSelected(item, preItem); } completeScroll(); scrollTo(destX, 0); } } public void setOnPageChangeListener(OnPageChangeListener listener) { mOnPageChangeListener = listener; } /** * Returns the number of pages that will be retained to either side of the * current page in the view hierarchy in an idle state. Defaults to 1. * * @return How many pages will be kept offscreen on either side * @see #setOffscreenPageLimit(int) */ public int getOffscreenPageLimit() { return mOffscreenPageLimit; } /** * Set the number of pages that should be retained to either side of the * current page in the view hierarchy in an idle state. Pages beyond this * limit will be recreated from the adapter when needed. * * <p> * This is offered as an optimization. If you know in advance the number of * pages you will need to support or have lazy-loading mechanisms in place * on your pages, tweaking this setting can have benefits in perceived * smoothness of paging animations and interaction. If you have a small * number of pages (3-4) that you can keep active all at once, less time * will be spent in layout for newly created view subtrees as the user pages * back and forth. * </p> * * <p> * You should keep this limit low, especially if your pages have complex * layouts. This setting defaults to 1. * </p> * * @param limit * How many pages will be kept offscreen in an idle state. */ public void setOffscreenPageLimit(int limit) { if (limit < DEFAULT_OFFSCREEN_PAGES) { Log.w(TAG, "Requested offscreen page limit " + limit + " too small; defaulting to " + DEFAULT_OFFSCREEN_PAGES); limit = DEFAULT_OFFSCREEN_PAGES; } if (limit != mOffscreenPageLimit) { mOffscreenPageLimit = limit; populate(); } } /** * Set the margin between pages. * * @param marginPixels * Distance between adjacent pages in pixels * @see #getPageMargin() * @see #setPageMarginDrawable(Drawable) * @see #setPageMarginDrawable(int) */ public void setPageMargin(int marginPixels) { final int oldMargin = mPageMargin; mPageMargin = marginPixels; final int width = getWidth(); recomputeScrollPosition(width, width, marginPixels, oldMargin); requestLayout(); } /** * Return the margin between pages. * * @return The size of the margin in pixels */ public int getPageMargin() { return mPageMargin; } /** * Set a drawable that will be used to fill the margin between pages. * * @param d * Drawable to display between pages */ public void setPageMarginDrawable(Drawable d) { mMarginDrawable = d; if (d != null) refreshDrawableState(); setWillNotDraw(d == null); invalidate(); } /** * Set a drawable that will be used to fill the margin between pages. * * @param resId * Resource ID of a drawable to display between pages */ public void setPageMarginDrawable(int resId) { setPageMarginDrawable(getContext().getResources().getDrawable(resId)); } @Override protected boolean verifyDrawable(Drawable who) { return super.verifyDrawable(who) || who == mMarginDrawable; } @Override protected void drawableStateChanged() { super.drawableStateChanged(); final Drawable d = mMarginDrawable; if (d != null && d.isStateful()) { d.setState(getDrawableState()); } } // We want the duration of the page snap animation to be influenced by the // distance that // the screen has to travel, however, we don't want this duration to be // effected in a // purely linear fashion. Instead, we use this method to moderate the effect // that the distance // of travel has on the overall snap duration. float distanceInfluenceForSnapDuration(float f) { f -= 0.5f; // center the values about 0. f *= 0.3f * Math.PI / 2.0f; return (float) Math.sin(f); } /** * Like {@link View#scrollBy}, but scroll smoothly instead of immediately. * * @param x * the number of pixels to scroll by on the X axis * @param y * the number of pixels to scroll by on the Y axis */ void smoothScrollTo(int x, int y) { smoothScrollTo(x, y, 0); } /** * Like {@link View#scrollBy}, but scroll smoothly instead of immediately. * * @param x * the number of pixels to scroll by on the X axis * @param y * the number of pixels to scroll by on the Y axis * @param velocity * the velocity associated with a fling, if applicable. (0 * otherwise) */ void smoothScrollTo(int x, int y, int velocity) { if (getChildCount() == 0) { // Nothing to do. setScrollingCacheEnabled(false); return; } int sx = getScrollX(); int sy = getScrollY(); int dx = x - sx; int dy = y - sy; if (dx == 0 && dy == 0) { completeScroll(); setScrollState(SCROLL_STATE_IDLE); return; } setScrollingCacheEnabled(true); mScrolling = true; setScrollState(SCROLL_STATE_SETTLING); final float pageDelta = (float) Math.abs(dx) / (getWidth() + mPageMargin); int duration = (int) (pageDelta * 100); velocity = Math.abs(velocity); if (velocity > 0) { duration += (duration / (velocity / mBaseLineFlingVelocity)) * mFlingVelocityInfluence; } else { duration += 100; } duration = Math.min(duration, MAX_SETTLE_DURATION); mScroller.startScroll(sx, sy, dx, dy, duration); invalidate(); } void addNewItem(int position, int index) { ItemInfo ii = new ItemInfo(); ii.position = position; ii.object = mAdapter.instantiateItem(this, position); if (index < 0) { mItems.add(ii); } else { mItems.add(index, ii); } } void dataSetChanged() { // This method only gets called if our observer is attached, so mAdapter // is non-null. boolean needPopulate = mItems.size() < 3 && mItems.size() < mAdapter.getCount(); int newCurrItem = -1; for (int i = 0; i < mItems.size(); i++) { final ItemInfo ii = mItems.get(i); final int newPos = mAdapter.getItemPosition(ii.object); if (newPos == PagerAdapter.POSITION_UNCHANGED) { continue; } if (newPos == PagerAdapter.POSITION_NONE) { mItems.remove(i); i--; mAdapter.destroyItem(this, ii.position, ii.object); needPopulate = true; if (mCurItem == ii.position) { // Keep the current item in the valid range newCurrItem = Math.max(0, Math.min(mCurItem, mAdapter.getCount() - 1)); } continue; } if (ii.position != newPos) { if (ii.position == mCurItem) { // Our current item changed position. Follow it. newCurrItem = newPos; } ii.position = newPos; needPopulate = true; } } Collections.sort(mItems, COMPARATOR); if (newCurrItem >= 0) { // TODO This currently causes a jump. setCurrentItemInternal(newCurrItem, false, true); needPopulate = true; } if (needPopulate) { populate(); requestLayout(); } } void populate() { if (mAdapter == null) { return; } // Bail now if we are waiting to populate. This is to hold off // on creating views from the time the user releases their finger to // fling to a new position until we have finished the scroll to // that position, avoiding glitches from happening at that point. if (mPopulatePending) { if (DEBUG) Log.i(TAG, "populate is pending, skipping for now..."); return; } // Also, don't populate until we are attached to a window. This is to // avoid trying to populate before we have restored our view hierarchy // state and conflicting with what is restored. if (getWindowToken() == null) { return; } mAdapter.startUpdate(this); final int pageLimit = mOffscreenPageLimit; final int startPos = Math.max(0, mCurItem - pageLimit); final int N = mAdapter.getCount(); final int endPos = Math.min(N - 1, mCurItem + pageLimit); if (DEBUG) Log.v(TAG, "populating: startPos=" + startPos + " endPos=" + endPos); // Add and remove pages in the existing list. int lastPos = -1; for (int i = 0; i < mItems.size(); i++) { ItemInfo ii = mItems.get(i); if ((ii.position < startPos || ii.position > endPos) && !ii.scrolling) { if (DEBUG) Log.i(TAG, "removing: " + ii.position + " @ " + i); mItems.remove(i); i--; mAdapter.destroyItem(this, ii.position, ii.object); } else if (lastPos < endPos && ii.position > startPos) { // The next item is outside of our range, but we have a gap // between it and the last item where we want to have a page // shown. Fill in the gap. lastPos++; if (lastPos < startPos) { lastPos = startPos; } while (lastPos <= endPos && lastPos < ii.position) { if (DEBUG) Log.i(TAG, "inserting: " + lastPos + " @ " + i); addNewItem(lastPos, i); lastPos++; i++; } } lastPos = ii.position; } // Add any new pages we need at the end. lastPos = mItems.size() > 0 ? mItems.get(mItems.size() - 1).position : -1; if (lastPos < endPos) { lastPos++; lastPos = lastPos > startPos ? lastPos : startPos; while (lastPos <= endPos) { if (DEBUG) Log.i(TAG, "appending: " + lastPos); addNewItem(lastPos, -1); lastPos++; } } if (DEBUG) { Log.i(TAG, "Current page list:"); for (int i = 0; i < mItems.size(); i++) { Log.i(TAG, "#" + i + ": page " + mItems.get(i).position); } } ItemInfo curItem = null; for (int i = 0; i < mItems.size(); i++) { if (mItems.get(i).position == mCurItem) { curItem = mItems.get(i); break; } } mAdapter.setPrimaryItem(this, mCurItem, curItem != null ? curItem.object : null); mAdapter.finishUpdate(this); if (hasFocus()) { View currentFocused = findFocus(); ItemInfo ii = currentFocused != null ? infoForAnyChild(currentFocused) : null; if (ii == null || ii.position != mCurItem) { for (int i = 0; i < getChildCount(); i++) { View child = getChildAt(i); ii = infoForChild(child); if (ii != null && ii.position == mCurItem) { if (child.requestFocus(FOCUS_FORWARD)) { break; } } } } } } public static class SavedState extends BaseSavedState { int position; Parcelable adapterState; ClassLoader loader; public SavedState(Parcelable superState) { super(superState); } @Override public void writeToParcel(Parcel out, int flags) { super.writeToParcel(out, flags); out.writeInt(position); out.writeParcelable(adapterState, flags); } @Override public String toString() { return "FragmentPager.SavedState{" + Integer.toHexString(System.identityHashCode(this)) + " position=" + position + "}"; } public static final Parcelable.Creator<SavedState> CREATOR = ParcelableCompat .newCreator(new ParcelableCompatCreatorCallbacks<SavedState>() { @Override public SavedState createFromParcel(Parcel in, ClassLoader loader) { return new SavedState(in, loader); } @Override public SavedState[] newArray(int size) { return new SavedState[size]; } }); SavedState(Parcel in, ClassLoader loader) { super(in); if (loader == null) { loader = getClass().getClassLoader(); } position = in.readInt(); adapterState = in.readParcelable(loader); this.loader = loader; } } @Override public Parcelable onSaveInstanceState() { Parcelable superState = super.onSaveInstanceState(); SavedState ss = new SavedState(superState); ss.position = mCurItem; if (mAdapter != null) { ss.adapterState = mAdapter.saveState(); } return ss; } @Override public void onRestoreInstanceState(Parcelable state) { if (!(state instanceof SavedState)) { super.onRestoreInstanceState(state); return; } SavedState ss = (SavedState) state; super.onRestoreInstanceState(ss.getSuperState()); if (mAdapter != null) { mAdapter.restoreState(ss.adapterState, ss.loader); setCurrentItemInternal(ss.position, false, true); } else { mRestoredCurItem = ss.position; mRestoredAdapterState = ss.adapterState; mRestoredClassLoader = ss.loader; } } @Override public void addView(View child, int index, LayoutParams params) { if (mInLayout) { addViewInLayout(child, index, params); child.measure(mChildWidthMeasureSpec, mChildHeightMeasureSpec); } else { super.addView(child, index, params); } if (USE_CACHE) { if (child.getVisibility() != GONE) { child.setDrawingCacheEnabled(mScrollingCacheEnabled); } else { child.setDrawingCacheEnabled(false); } } } ItemInfo infoForChild(View child) { for (int i = 0; i < mItems.size(); i++) { ItemInfo ii = mItems.get(i); if (mAdapter.isViewFromObject(child, ii.object)) { return ii; } } return null; } ItemInfo infoForAnyChild(View child) { ViewParent parent; while ((parent = child.getParent()) != this) { if (parent == null || !(parent instanceof View)) { return null; } child = (View) parent; } return infoForChild(child); } @Override protected void onAttachedToWindow() { super.onAttachedToWindow(); mFirstLayout = true; } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { // For simple implementation, or internal size is always 0. // We depend on the container to specify the layout size of // our view. We can't really know what it is since we will be // adding and removing different arbitrary views and do not // want the layout to change as this happens. setMeasuredDimension(getDefaultSize(0, widthMeasureSpec), getDefaultSize(0, heightMeasureSpec)); // Children are just made to fill our space. mChildWidthMeasureSpec = MeasureSpec.makeMeasureSpec(getMeasuredWidth() - getPaddingLeft() - getPaddingRight(), MeasureSpec.EXACTLY); mChildHeightMeasureSpec = MeasureSpec.makeMeasureSpec( getMeasuredHeight() - getPaddingTop() - getPaddingBottom(), MeasureSpec.EXACTLY); // Make sure we have created all fragments that we need to have shown. mInLayout = true; populate(); mInLayout = false; // Make sure all children have been properly measured. final int size = getChildCount(); for (int i = 0; i < size; ++i) { final View child = getChildAt(i); if (child.getVisibility() != GONE) { if (DEBUG) Log.v(TAG, "Measuring #" + i + " " + child + ": " + mChildWidthMeasureSpec); child.measure(mChildWidthMeasureSpec, mChildHeightMeasureSpec); } } } @Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { super.onSizeChanged(w, h, oldw, oldh); // Make sure scroll position is set correctly. if (w != oldw) { recomputeScrollPosition(w, oldw, mPageMargin, mPageMargin); } } private void recomputeScrollPosition(int width, int oldWidth, int margin, int oldMargin) { final int widthWithMargin = width + margin; if (oldWidth > 0) { final int oldScrollPos = getScrollX(); final int oldwwm = oldWidth + oldMargin; final int oldScrollItem = oldScrollPos / oldwwm; final float scrollOffset = (float) (oldScrollPos % oldwwm) / oldwwm; final int scrollPos = (int) ((oldScrollItem + scrollOffset) * widthWithMargin); scrollTo(scrollPos, getScrollY()); if (!mScroller.isFinished()) { // We now return to your regularly scheduled scroll, already in // progress. final int newDuration = mScroller.getDuration() - mScroller.timePassed(); mScroller.startScroll(scrollPos, 0, mCurItem * widthWithMargin, 0, newDuration); } } else { int scrollPos = mCurItem * widthWithMargin; if (scrollPos != getScrollX()) { completeScroll(); scrollTo(scrollPos, getScrollY()); } } } @Override protected void onLayout(boolean changed, int l, int t, int r, int b) { mInLayout = true; populate(); mInLayout = false; final int count = getChildCount(); final int width = r - l; for (int i = 0; i < count; i++) { View child = getChildAt(i); ItemInfo ii; if (child.getVisibility() != GONE && (ii = infoForChild(child)) != null) { int loff = (width + mPageMargin) * ii.position; int childLeft = getPaddingLeft() + loff; int childTop = getPaddingTop(); if (DEBUG) Log.v(TAG, "Positioning #" + i + " " + child + " f=" + ii.object + ":" + childLeft + "," + childTop + " " + child.getMeasuredWidth() + "x" + child.getMeasuredHeight()); child.layout(childLeft, childTop, childLeft + child.getMeasuredWidth(), childTop + child.getMeasuredHeight()); } } mFirstLayout = false; } @Override public void computeScroll() { if (DEBUG) Log.i(TAG, "computeScroll: finished=" + mScroller.isFinished()); if (!mScroller.isFinished()) { if (mScroller.computeScrollOffset()) { if (DEBUG) Log.i(TAG, "computeScroll: still scrolling"); int oldX = getScrollX(); int oldY = getScrollY(); int x = mScroller.getCurrX(); int y = mScroller.getCurrY(); if (oldX != x || oldY != y) { scrollTo(x, y); } if (mOnPageChangeListener != null) { final int widthWithMargin = getWidth() + mPageMargin; final int position = x / widthWithMargin; final int offsetPixels = x % widthWithMargin; final float offset = (float) offsetPixels / widthWithMargin; mOnPageChangeListener.onPageScrolled(position, offset, offsetPixels); } // Keep on drawing until the animation has finished. invalidate(); return; } } // Done with scroll, clean up state. completeScroll(); } private void completeScroll() { boolean needPopulate = mScrolling; if (needPopulate) { // Done with scroll, no longer want to cache view drawing. setScrollingCacheEnabled(false); mScroller.abortAnimation(); int oldX = getScrollX(); int oldY = getScrollY(); int x = mScroller.getCurrX(); int y = mScroller.getCurrY(); if (oldX != x || oldY != y) { scrollTo(x, y); } setScrollState(SCROLL_STATE_IDLE); } mPopulatePending = false; mScrolling = false; for (int i = 0; i < mItems.size(); i++) { ItemInfo ii = mItems.get(i); if (ii.scrolling) { needPopulate = true; ii.scrolling = false; } } if (needPopulate) { populate(); } } @Override public boolean onInterceptTouchEvent(MotionEvent ev) { /* * This method JUST determines whether we want to intercept the motion. * If we return true, onMotionEvent will be called and we do the actual * scrolling there. */ final int action = ev.getAction() & MotionEventCompat.ACTION_MASK; // Always take care of the touch gesture being complete. if (action == MotionEvent.ACTION_CANCEL || action == MotionEvent.ACTION_UP) { // Release the drag. if (DEBUG) Log.v(TAG, "Intercept done!"); mIsBeingDragged = false; mIsUnableToDrag = false; mActivePointerId = INVALID_POINTER; return false; } // Nothing more to do here if we have decided whether or not we // are dragging. if (action != MotionEvent.ACTION_DOWN) { if (mIsBeingDragged) { if (DEBUG) Log.v(TAG, "Intercept returning true!"); return true; } if (mIsUnableToDrag) { if (DEBUG) Log.v(TAG, "Intercept returning false!"); return false; } } switch (action) { case MotionEvent.ACTION_MOVE: { /* * mIsBeingDragged == false, otherwise the shortcut would have * caught it. Check whether the user has moved far enough from his * original down touch. */ /* * Locally do absolute value. mLastMotionY is set to the y value of * the down event. */ final int activePointerId = mActivePointerId; if (activePointerId == INVALID_POINTER) { // If we don't have a valid id, the touch down wasn't on // content. break; } final int pointerIndex = MotionEventCompat.findPointerIndex(ev, activePointerId); final float x = MotionEventCompat.getX(ev, pointerIndex); final float dx = x - mLastMotionX; final float xDiff = Math.abs(dx); final float y = MotionEventCompat.getY(ev, pointerIndex); final float yDiff = Math.abs(y - mLastMotionY); final int scrollX = getScrollX(); final boolean atEdge = (dx > 0 && scrollX == 0) || (dx < 0 && mAdapter != null && scrollX >= (mAdapter .getCount() - 1) * getWidth() - 1); if (DEBUG) Log.v(TAG, "Moved x to " + x + "," + y + " diff=" + xDiff + "," + yDiff); if (canScroll(this, false, (int) dx, (int) x, (int) y)) { // Nested view has scrollable area under this point. Let it be // handled there. mInitialMotionX = mLastMotionX = x; mLastMotionY = y; return false; } if (xDiff > mTouchSlop && xDiff > yDiff) { if (DEBUG) Log.v(TAG, "Starting drag!"); mIsBeingDragged = true; setScrollState(SCROLL_STATE_DRAGGING); mLastMotionX = x; setScrollingCacheEnabled(true); } else { if (yDiff > mTouchSlop) { // The finger has moved enough in the vertical // direction to be counted as a drag... abort // any attempt to drag horizontally, to work correctly // with children that have scrolling containers. if (DEBUG) Log.v(TAG, "Starting unable to drag!"); mIsUnableToDrag = true; } } break; } case MotionEvent.ACTION_DOWN: { /* * Remember location of down touch. ACTION_DOWN always refers to * pointer index 0. */ mLastMotionX = mInitialMotionX = ev.getX(); mLastMotionY = ev.getY(); mActivePointerId = MotionEventCompat.getPointerId(ev, 0); if (mScrollState == SCROLL_STATE_SETTLING) { // Let the user 'catch' the pager as it animates. mIsBeingDragged = true; mIsUnableToDrag = false; setScrollState(SCROLL_STATE_DRAGGING); } else { completeScroll(); mIsBeingDragged = false; mIsUnableToDrag = false; } if (DEBUG) Log.v(TAG, "Down at " + mLastMotionX + "," + mLastMotionY + " mIsBeingDragged=" + mIsBeingDragged + "mIsUnableToDrag=" + mIsUnableToDrag); break; } case MotionEventCompat.ACTION_POINTER_UP: onSecondaryPointerUp(ev); break; } /* * The only time we want to intercept motion events is if we are in the * drag mode. */ return mIsBeingDragged; } @Override public boolean onTouchEvent(MotionEvent ev) { if (mFakeDragging) { // A fake drag is in progress already, ignore this real one // but still eat the touch events. // (It is likely that the user is multi-touching the screen.) return true; } if (ev.getAction() == MotionEvent.ACTION_DOWN && ev.getEdgeFlags() != 0) { // Don't handle edge touches immediately -- they may actually belong // to one of our // descendants. return false; } if (mAdapter == null || mAdapter.getCount() == 0) { // Nothing to present or scroll; nothing to touch. return false; } if (mVelocityTracker == null) { mVelocityTracker = VelocityTracker.obtain(); } mVelocityTracker.addMovement(ev); final int action = ev.getAction(); boolean needsInvalidate = false; switch (action & MotionEventCompat.ACTION_MASK) { case MotionEvent.ACTION_DOWN: { /* * If being flinged and user touches, stop the fling. isFinished * will be false if being flinged. */ completeScroll(); // Remember where the motion event started mLastMotionX = mInitialMotionX = ev.getX(); mActivePointerId = MotionEventCompat.getPointerId(ev, 0); break; } case MotionEvent.ACTION_MOVE: if (!mIsBeingDragged) { final int pointerIndex = MotionEventCompat.findPointerIndex(ev, mActivePointerId); final float x = MotionEventCompat.getX(ev, pointerIndex); final float xDiff = Math.abs(x - mLastMotionX); final float y = MotionEventCompat.getY(ev, pointerIndex); final float yDiff = Math.abs(y - mLastMotionY); if (DEBUG) Log.v(TAG, "Moved x to " + x + "," + y + " diff=" + xDiff + "," + yDiff); if (xDiff > mTouchSlop && xDiff > yDiff) { if (DEBUG) Log.v(TAG, "Starting drag!"); mIsBeingDragged = true; mLastMotionX = x; setScrollState(SCROLL_STATE_DRAGGING); setScrollingCacheEnabled(true); } } if (mIsBeingDragged) { // Scroll to follow the motion event final int activePointerIndex = MotionEventCompat .findPointerIndex(ev, mActivePointerId); final float x = MotionEventCompat.getX(ev, activePointerIndex); final float deltaX = mLastMotionX - x; mLastMotionX = x; float oldScrollX = getScrollX(); float scrollX = oldScrollX + deltaX; final int width = getWidth(); final int widthWithMargin = width + mPageMargin; final int lastItemIndex = mAdapter.getCount() - 1; final float leftBound = Math.max(0, (mCurItem - 1) * widthWithMargin); final float rightBound = Math.min(mCurItem + 1, lastItemIndex) * widthWithMargin; if (scrollX < leftBound) { if (leftBound == 0) { float over = -scrollX; needsInvalidate = mLeftEdge.onPull(over / width); } scrollX = leftBound; } else if (scrollX > rightBound) { if (rightBound == lastItemIndex * widthWithMargin) { float over = scrollX - rightBound; needsInvalidate = mRightEdge.onPull(over / width); } scrollX = rightBound; } // Don't lose the rounded component mLastMotionX += scrollX - (int) scrollX; scrollTo((int) scrollX, getScrollY()); if (mOnPageChangeListener != null) { final int position = (int) scrollX / widthWithMargin; final int positionOffsetPixels = (int) scrollX % widthWithMargin; final float positionOffset = (float) positionOffsetPixels / widthWithMargin; mOnPageChangeListener.onPageScrolled(position, positionOffset, positionOffsetPixels); } } break; case MotionEvent.ACTION_UP: if (mIsBeingDragged) { final VelocityTracker velocityTracker = mVelocityTracker; velocityTracker.computeCurrentVelocity(1000, mMaximumVelocity); int initialVelocity = (int) VelocityTrackerCompat.getXVelocity( velocityTracker, mActivePointerId); mPopulatePending = true; final int widthWithMargin = getWidth() + mPageMargin; final int scrollX = getScrollX(); // 澧炲姞杈硅窛鍒ゆ柇 int currentPage = scrollX / widthWithMargin; int leftPageScorll = scrollX % widthWithMargin; int nextPage = currentPage; float chargeVelocity = initialVelocity; if (chargeVelocity > 0) { // 鍚戝彸 if (widthWithMargin - leftPageScorll > mPagerNextMarginPixels) { nextPage = currentPage; } else { nextPage = currentPage + 1; } } else { // 鍚戝乏 if (leftPageScorll > mPagerNextMarginPixels) { nextPage = currentPage + 1; } else { nextPage = currentPage; } } // nextPage = chargeVelocity > 0 ? currentPage // : currentPage + 1; // Log.d(TAG, "initialVelocity:" + initialVelocity // + ", currentPage: " + (scrollX / widthWithMargin) // + ", widthWithMargin: " + widthWithMargin // + ", scrollX: " + scrollX + ", chargeVelocity: " // + chargeVelocity + ", nextPage: " + nextPage); setCurrentItemInternal(nextPage, true, true, initialVelocity); mActivePointerId = INVALID_POINTER; endDrag(); needsInvalidate = mLeftEdge.onRelease() | mRightEdge.onRelease(); } break; case MotionEvent.ACTION_CANCEL: if (mIsBeingDragged) { setCurrentItemInternal(mCurItem, true, true); mActivePointerId = INVALID_POINTER; endDrag(); needsInvalidate = mLeftEdge.onRelease() | mRightEdge.onRelease(); } break; case MotionEventCompat.ACTION_POINTER_DOWN: { final int index = MotionEventCompat.getActionIndex(ev); final float x = MotionEventCompat.getX(ev, index); mLastMotionX = x; mActivePointerId = MotionEventCompat.getPointerId(ev, index); break; } case MotionEventCompat.ACTION_POINTER_UP: onSecondaryPointerUp(ev); mLastMotionX = MotionEventCompat.getX(ev, MotionEventCompat.findPointerIndex(ev, mActivePointerId)); break; } if (needsInvalidate) { invalidate(); } return true; } @Override public void draw(Canvas canvas) { super.draw(canvas); boolean needsInvalidate = false; final int overScrollMode = ViewCompat.getOverScrollMode(this); if (overScrollMode == ViewCompat.OVER_SCROLL_ALWAYS || (overScrollMode == ViewCompat.OVER_SCROLL_IF_CONTENT_SCROLLS && mAdapter != null && mAdapter.getCount() > 1)) { if (!mLeftEdge.isFinished()) { final int restoreCount = canvas.save(); final int height = getHeight() - getPaddingTop() - getPaddingBottom(); canvas.rotate(270); canvas.translate(-height + getPaddingTop(), 0); mLeftEdge.setSize(height, getWidth()); needsInvalidate |= mLeftEdge.draw(canvas); canvas.restoreToCount(restoreCount); } if (!mRightEdge.isFinished()) { final int restoreCount = canvas.save(); final int width = getWidth(); final int height = getHeight() - getPaddingTop() - getPaddingBottom(); final int itemCount = mAdapter != null ? mAdapter.getCount() : 1; canvas.rotate(90); canvas.translate(-getPaddingTop(), -itemCount * (width + mPageMargin) + mPageMargin); mRightEdge.setSize(height, width); needsInvalidate |= mRightEdge.draw(canvas); canvas.restoreToCount(restoreCount); } } else { mLeftEdge.finish(); mRightEdge.finish(); } if (needsInvalidate) { // Keep animating invalidate(); } } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); // Draw the margin drawable if needed. if (mPageMargin > 0 && mMarginDrawable != null) { final int scrollX = getScrollX(); final int width = getWidth(); final int offset = scrollX % (width + mPageMargin); if (offset != 0) { // Pages fit completely when settled; we only need to draw when // in between final int left = scrollX - offset + width; mMarginDrawable.setBounds(left, 0, left + mPageMargin, getHeight()); mMarginDrawable.draw(canvas); } } } /** * Start a fake drag of the pager. * * <p> * A fake drag can be useful if you want to synchronize the motion of the * ViewPager with the touch scrolling of another view, while still letting * the ViewPager control the snapping motion and fling behavior. (e.g. * parallax-scrolling tabs.) Call {@link #fakeDragBy(float)} to simulate the * actual drag motion. Call {@link #endFakeDrag()} to complete the fake drag * and fling as necessary. * * <p> * During a fake drag the ViewPager will ignore all touch events. If a real * drag is already in progress, this method will return false. * * @return true if the fake drag began successfully, false if it could not * be started. * * @see #fakeDragBy(float) * @see #endFakeDrag() */ public boolean beginFakeDrag() { if (mIsBeingDragged) { return false; } mFakeDragging = true; setScrollState(SCROLL_STATE_DRAGGING); mInitialMotionX = mLastMotionX = 0; if (mVelocityTracker == null) { mVelocityTracker = VelocityTracker.obtain(); } else { mVelocityTracker.clear(); } final long time = SystemClock.uptimeMillis(); final MotionEvent ev = MotionEvent.obtain(time, time, MotionEvent.ACTION_DOWN, 0, 0, 0); mVelocityTracker.addMovement(ev); ev.recycle(); mFakeDragBeginTime = time; return true; } /** * End a fake drag of the pager. * * @see #beginFakeDrag() * @see #fakeDragBy(float) */ public void endFakeDrag() { Log.d(TAG, "endFakeDrag"); if (!mFakeDragging) { throw new IllegalStateException( "No fake drag in progress. Call beginFakeDrag first."); } final VelocityTracker velocityTracker = mVelocityTracker; velocityTracker.computeCurrentVelocity(1000, mMaximumVelocity); int initialVelocity = (int) VelocityTrackerCompat.getYVelocity( velocityTracker, mActivePointerId); mPopulatePending = true; Log.d(TAG, "initialVelocity: " + initialVelocity + ", Math.abs(mInitialMotionX - mLastMotionX): " + Math.abs(mInitialMotionX - mLastMotionX)); if ((Math.abs(initialVelocity) > mMinimumVelocity) || Math.abs(mInitialMotionX - mLastMotionX) >= (getWidth() / 3)) { if (mLastMotionX > mInitialMotionX) { setCurrentItemInternal(mCurItem - 1, true, true); } else { setCurrentItemInternal(mCurItem + 1, true, true); } } else { setCurrentItemInternal(mCurItem, true, true); } endDrag(); mFakeDragging = false; } /** * Fake drag by an offset in pixels. You must have called * {@link #beginFakeDrag()} first. * * @param xOffset * Offset in pixels to drag by. * @see #beginFakeDrag() * @see #endFakeDrag() */ public void fakeDragBy(float xOffset) { if (!mFakeDragging) { throw new IllegalStateException( "No fake drag in progress. Call beginFakeDrag first."); } mLastMotionX += xOffset; float scrollX = getScrollX() - xOffset; final int width = getWidth(); final int widthWithMargin = width + mPageMargin; final float leftBound = Math.max(0, (mCurItem - 1) * widthWithMargin); final float rightBound = Math .min(mCurItem + 1, mAdapter.getCount() - 1) * widthWithMargin; if (scrollX < leftBound) { scrollX = leftBound; } else if (scrollX > rightBound) { scrollX = rightBound; } // Don't lose the rounded component mLastMotionX += scrollX - (int) scrollX; scrollTo((int) scrollX, getScrollY()); if (mOnPageChangeListener != null) { final int position = (int) scrollX / widthWithMargin; final int positionOffsetPixels = (int) scrollX % widthWithMargin; final float positionOffset = (float) positionOffsetPixels / widthWithMargin; mOnPageChangeListener.onPageScrolled(position, positionOffset, positionOffsetPixels); } // Synthesize an event for the VelocityTracker. final long time = SystemClock.uptimeMillis(); final MotionEvent ev = MotionEvent.obtain(mFakeDragBeginTime, time, MotionEvent.ACTION_MOVE, mLastMotionX, 0, 0); mVelocityTracker.addMovement(ev); ev.recycle(); } /** * Returns true if a fake drag is in progress. * * @return true if currently in a fake drag, false otherwise. * * @see #beginFakeDrag() * @see #fakeDragBy(float) * @see #endFakeDrag() */ public boolean isFakeDragging() { return mFakeDragging; } private void onSecondaryPointerUp(MotionEvent ev) { final int pointerIndex = MotionEventCompat.getActionIndex(ev); final int pointerId = MotionEventCompat.getPointerId(ev, pointerIndex); if (pointerId == mActivePointerId) { // This was our active pointer going up. Choose a new // active pointer and adjust accordingly. final int newPointerIndex = pointerIndex == 0 ? 1 : 0; mLastMotionX = MotionEventCompat.getX(ev, newPointerIndex); mActivePointerId = MotionEventCompat.getPointerId(ev, newPointerIndex); if (mVelocityTracker != null) { mVelocityTracker.clear(); } } } private void endDrag() { mIsBeingDragged = false; mIsUnableToDrag = false; if (mVelocityTracker != null) { mVelocityTracker.recycle(); mVelocityTracker = null; } } private void setScrollingCacheEnabled(boolean enabled) { if (mScrollingCacheEnabled != enabled) { mScrollingCacheEnabled = enabled; if (USE_CACHE) { final int size = getChildCount(); for (int i = 0; i < size; ++i) { final View child = getChildAt(i); if (child.getVisibility() != GONE) { child.setDrawingCacheEnabled(enabled); } } } } } /** * Tests scrollability within child views of v given a delta of dx. * * @param v * View to test for horizontal scrollability * @param checkV * Whether the view v passed should itself be checked for * scrollability (true), or just its children (false). * @param dx * Delta scrolled in pixels * @param x * X coordinate of the active touch point * @param y * Y coordinate of the active touch point * @return true if child views of v can be scrolled by delta of dx. */ protected boolean canScroll(View v, boolean checkV, int dx, int x, int y) { if (v instanceof ViewGroup) { final ViewGroup group = (ViewGroup) v; final int scrollX = v.getScrollX(); final int scrollY = v.getScrollY(); final int count = group.getChildCount(); // Count backwards - let topmost views consume scroll distance // first. for (int i = count - 1; i >= 0; i--) { // TODO: Add versioned support here for transformed views. // This will not work for transformed views in Honeycomb+ final View child = group.getChildAt(i); if (x + scrollX >= child.getLeft() && x + scrollX < child.getRight() && y + scrollY >= child.getTop() && y + scrollY < child.getBottom() && canScroll(child, true, dx, x + scrollX - child.getLeft(), y + scrollY - child.getTop())) { return true; } } } return checkV && ViewCompat.canScrollHorizontally(v, -dx); } @Override public boolean dispatchKeyEvent(KeyEvent event) { // Let the focused view and/or our descendants get the key first return super.dispatchKeyEvent(event) || executeKeyEvent(event); } /** * You can call this function yourself to have the scroll view perform * scrolling from a key event, just as if the event had been dispatched to * it by the view hierarchy. * * @param event * The key event to execute. * @return Return true if the event was handled, else false. */ public boolean executeKeyEvent(KeyEvent event) { boolean handled = false; if (event.getAction() == KeyEvent.ACTION_DOWN) { switch (event.getKeyCode()) { case KeyEvent.KEYCODE_DPAD_LEFT: handled = arrowScroll(FOCUS_LEFT); break; case KeyEvent.KEYCODE_DPAD_RIGHT: handled = arrowScroll(FOCUS_RIGHT); break; case KeyEvent.KEYCODE_TAB: if (KeyEventCompat.hasNoModifiers(event)) { handled = arrowScroll(FOCUS_FORWARD); } else if (KeyEventCompat.hasModifiers(event, KeyEvent.META_SHIFT_ON)) { handled = arrowScroll(FOCUS_BACKWARD); } break; } } return handled; } public boolean arrowScroll(int direction) { View currentFocused = findFocus(); if (currentFocused == this) currentFocused = null; boolean handled = false; View nextFocused = FocusFinder.getInstance().findNextFocus(this, currentFocused, direction); if (nextFocused != null && nextFocused != currentFocused) { if (direction == View.FOCUS_LEFT) { // If there is nothing to the left, or this is causing us to // jump to the right, then what we really want to do is page // left. if (currentFocused != null && nextFocused.getLeft() >= currentFocused.getLeft()) { handled = pageLeft(); } else { handled = nextFocused.requestFocus(); } } else if (direction == View.FOCUS_RIGHT) { // If there is nothing to the right, or this is causing us to // jump to the left, then what we really want to do is page // right. if (currentFocused != null && nextFocused.getLeft() <= currentFocused.getLeft()) { handled = pageRight(); } else { handled = nextFocused.requestFocus(); } } } else if (direction == FOCUS_LEFT || direction == FOCUS_BACKWARD) { // Trying to move left and nothing there; try to page. handled = pageLeft(); } else if (direction == FOCUS_RIGHT || direction == FOCUS_FORWARD) { // Trying to move right and nothing there; try to page. handled = pageRight(); } if (handled) { playSoundEffect(SoundEffectConstants .getContantForFocusDirection(direction)); } return handled; } boolean pageLeft() { if (mCurItem > 0) { setCurrentItem(mCurItem - 1, true); return true; } return false; } boolean pageRight() { if (mAdapter != null && mCurItem < (mAdapter.getCount() - 1)) { setCurrentItem(mCurItem + 1, true); return true; } return false; } /** * We only want the current page that is being shown to be focusable. */ @Override public void addFocusables(ArrayList<View> views, int direction, int focusableMode) { final int focusableCount = views.size(); final int descendantFocusability = getDescendantFocusability(); if (descendantFocusability != FOCUS_BLOCK_DESCENDANTS) { for (int i = 0; i < getChildCount(); i++) { final View child = getChildAt(i); if (child.getVisibility() == VISIBLE) { ItemInfo ii = infoForChild(child); if (ii != null && ii.position == mCurItem) { child.addFocusables(views, direction, focusableMode); } } } } // we add ourselves (if focusable) in all cases except for when we are // FOCUS_AFTER_DESCENDANTS and there are some descendants focusable. // this is // to avoid the focus search finding layouts when a more precise search // among the focusable children would be more interesting. if (descendantFocusability != FOCUS_AFTER_DESCENDANTS || // No focusable descendants (focusableCount == views.size())) { // Note that we can't call the superclass here, because it will // add all views in. So we need to do the same thing View does. if (!isFocusable()) { return; } if ((focusableMode & FOCUSABLES_TOUCH_MODE) == FOCUSABLES_TOUCH_MODE && isInTouchMode() && !isFocusableInTouchMode()) { return; } if (views != null) { views.add(this); } } } /** * We only want the current page that is being shown to be touchable. */ @Override public void addTouchables(ArrayList<View> views) { // Note that we don't call super.addTouchables(), which means that // we don't call View.addTouchables(). This is okay because a ViewPager // is itself not touchable. for (int i = 0; i < getChildCount(); i++) { final View child = getChildAt(i); if (child.getVisibility() == VISIBLE) { ItemInfo ii = infoForChild(child); if (ii != null && ii.position == mCurItem) { child.addTouchables(views); } } } } /** * We only want the current page that is being shown to be focusable. */ @Override protected boolean onRequestFocusInDescendants(int direction, Rect previouslyFocusedRect) { int index; int increment; int end; int count = getChildCount(); if ((direction & FOCUS_FORWARD) != 0) { index = 0; increment = 1; end = count; } else { index = count - 1; increment = -1; end = -1; } for (int i = index; i != end; i += increment) { View child = getChildAt(i); if (child.getVisibility() == VISIBLE) { ItemInfo ii = infoForChild(child); if (ii != null && ii.position == mCurItem) { if (child.requestFocus(direction, previouslyFocusedRect)) { return true; } } } } return false; } @Override public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) { // ViewPagers should only report accessibility info for the current // page, // otherwise things get very confusing. // TODO: Should this note something about the paging container? final int childCount = getChildCount(); for (int i = 0; i < childCount; i++) { final View child = getChildAt(i); if (child.getVisibility() == VISIBLE) { final ItemInfo ii = infoForChild(child); if (ii != null && ii.position == mCurItem && child.dispatchPopulateAccessibilityEvent(event)) { return true; } } } return false; }

2014-08-12

flv解析工具

一款功能强大的flv 解析工具,能解析出head onMetaData 数据内容

2013-10-16

Android视频监控源码

Android 视频监控 源码 适合视频会议,手机会议。网络相机监控等。不下载别后悔。工作中项目 程序。

2013-09-24

apk 签名 zipalign

android 上传到GOOGLE 市场,不能发布问题。以及签名问题。有图详细介绍。

2013-07-10

FFMPEG移植到Android

FFMPEG 移植到 Android cygdrive 安装。交叉编译环境搭建。手把手编译FFMPEG

2013-06-20

sockettool

sockettool 是一款功能强大的测试工具。测试服务器,客户端 socket 连通问题。。方便 socket 句柄 列表化。直观。可以相互发送数据。

2013-06-14

XMLEditor.exe

一个功能很强大的XML 格式 查看工具,简单易用,只要拖进去就可以了。

2012-12-14

live555 编译

live555 编译 编译。VS2008编译的。自己可以打包生成DLL 库。

2012-12-07

onvfi 晋级了

针对上1版本,这段时间对onvif,有了更深入的了解,总结了经验,赶紧去下载啊。你对他还有1头雾水。。别错过。。

2012-12-04

VisualAssistX

VisualAssistX 破解版 VC,VS2008,VS2010.

2012-11-15

onvif 所有设备源码

onvif 发现所有设备源码 discovery

2012-11-14

ONVIF Device Manager

ONVIF Device Manager 用来检测 onvif 相机的是否ok的。

2012-11-14

空空如也

TA创建的收藏夹 TA关注的收藏夹

TA关注的人

提示
确定要删除当前文章?
取消 删除