- 浏览: 1044926 次
- 性别:
- 来自: US
文章分类
最新评论
-
ever丶唯爱:
有activiti的视频吗?
Activiti介绍及视频教程 -
A_T_Being:
好东西,在百度盘上面,可以下载来看。
Redis介绍及视频教程 -
zhuchao_ko:
这个世界上只有两种语言 一种没人用的 一种被骂 的 我一直相信 ...
程序员将面临再次洗牌,你作何选择? -
ljmomo:
微软 手机 现在 已经不挂 诺基亚logo 。还有就是 微软 ...
程序员将面临再次洗牌,你作何选择? -
benwg:
楼主,MacOS是基于BSD系统的,真怀疑你是否从事多年的软件 ...
程序员将面临再次洗牌,你作何选择?
Android实现图片滚动控件,含页签功能,让你的应用像淘宝一样炫起来
首先题外话,今天早上起床的时候,手滑一下把我的手机甩了出去,结果陪伴我两年半的摩托罗拉里程碑一代就这么安息了,于是我今天决定怒更一记,纪念我死去的爱机。
如果你是网购达人,你的手机上一定少不了淘宝客户端。关注特效的人一定都会发现,淘宝不管是网站还是手机客户端,主页上都会有一个图片滚动播放器,上面展示一些它推荐的商品。这个几乎可以用淘宝来冠名的功能,看起来还是挺炫的,我们今天就来实现一下。
实现原理其实还是之前那篇文章Android滑动菜单特效实现,仿人人客户端侧滑效果,史上最简单的侧滑实现,算是以那个原理为基础的另外一个变种。正所谓一通百通,真正掌握一种方法之后,就可以使用这个方法变换出各种不通的效果。
今天仍然还是实现一个自定义控件,然后我们在任意Activity的布局文件中引用一下,即可实现图片滚动器的效果。
在Eclipse中新建一个Android项目,项目名就叫做SlidingViewSwitcher。
新建一个类,名叫SlidingSwitcherView,这个类是继承自RelativeLayout的,并且实现了OnTouchListener接口,具体代码如下:
- publicclassSlidingSwitcherViewextendsRelativeLayoutimplementsOnTouchListener{
- /**
- *让菜单滚动,手指滑动需要达到的速度。
- */
- publicstaticfinalintSNAP_VELOCITY=200;
- /**
- *SlidingSwitcherView的宽度。
- */
- privateintswitcherViewWidth;
- /**
- *当前显示的元素的下标。
- */
- privateintcurrentItemIndex;
- /**
- *菜单中包含的元素总数。
- */
- privateintitemsCount;
- /**
- *各个元素的偏移边界值。
- */
- privateint[]borders;
- /**
- *最多可以滑动到的左边缘。值由菜单中包含的元素总数来定,marginLeft到达此值之后,不能再减少。
- *
- */
- privateintleftEdge=0;
- /**
- *最多可以滑动到的右边缘。值恒为0,marginLeft到达此值之后,不能再增加。
- */
- privateintrightEdge=0;
- /**
- *记录手指按下时的横坐标。
- */
- privatefloatxDown;
- /**
- *记录手指移动时的横坐标。
- */
- privatefloatxMove;
- /**
- *记录手机抬起时的横坐标。
- */
- privatefloatxUp;
- /**
- *菜单布局。
- */
- privateLinearLayoutitemsLayout;
- /**
- *标签布局。
- */
- privateLinearLayoutdotsLayout;
- /**
- *菜单中的第一个元素。
- */
- privateViewfirstItem;
- /**
- *菜单中第一个元素的布局,用于改变leftMargin的值,来决定当前显示的哪一个元素。
- */
- privateMarginLayoutParamsfirstItemParams;
- /**
- *用于计算手指滑动的速度。
- */
- privateVelocityTrackermVelocityTracker;
- /**
- *重写SlidingSwitcherView的构造函数,用于允许在XML中引用当前的自定义布局。
- *
- *@paramcontext
- *@paramattrs
- */
- publicSlidingSwitcherView(Contextcontext,AttributeSetattrs){
- super(context,attrs);
- }
- /**
- *滚动到下一个元素。
- */
- publicvoidscrollToNext(){
- newScrollTask().execute(-20);
- }
- /**
- *滚动到上一个元素。
- */
- publicvoidscrollToPrevious(){
- newScrollTask().execute(20);
- }
- /**
- *在onLayout中重新设定菜单元素和标签元素的参数。
- */
- @Override
- protectedvoidonLayout(booleanchanged,intl,intt,intr,intb){
- super.onLayout(changed,l,t,r,b);
- if(changed){
- initializeItems();
- initializeDots();
- }
- }
- /**
- *初始化菜单元素,为每一个子元素增加监听事件,并且改变所有子元素的宽度,让它们等于父元素的宽度。
- */
- privatevoidinitializeItems(){
- switcherViewWidth=getWidth();
- itemsLayout=(LinearLayout)getChildAt(0);
- itemsCount=itemsLayout.getChildCount();
- borders=newint[itemsCount];
- for(inti=0;i<itemsCount;i++){
- borders[i]=-i*switcherViewWidth;
- Viewitem=itemsLayout.getChildAt(i);
- MarginLayoutParamsparams=(MarginLayoutParams)item.getLayoutParams();
- params.width=switcherViewWidth;
- item.setLayoutParams(params);
- item.setOnTouchListener(this);
- }
- leftEdge=borders[itemsCount-1];
- firstItem=itemsLayout.getChildAt(0);
- firstItemParams=(MarginLayoutParams)firstItem.getLayoutParams();
- }
- /**
- *初始化标签元素。
- */
- privatevoidinitializeDots(){
- dotsLayout=(LinearLayout)getChildAt(1);
- refreshDotsLayout();
- }
- @Override
- publicbooleanonTouch(Viewv,MotionEventevent){
- createVelocityTracker(event);
- switch(event.getAction()){
- caseMotionEvent.ACTION_DOWN:
- //手指按下时,记录按下时的横坐标
- xDown=event.getRawX();
- break;
- caseMotionEvent.ACTION_MOVE:
- //手指移动时,对比按下时的横坐标,计算出移动的距离,来调整左侧布局的leftMargin值,从而显示和隐藏左侧布局
- xMove=event.getRawX();
- intdistanceX=(int)(xMove-xDown)-(currentItemIndex*switcherViewWidth);
- firstItemParams.leftMargin=distanceX;
- if(beAbleToScroll()){
- firstItem.setLayoutParams(firstItemParams);
- }
- break;
- caseMotionEvent.ACTION_UP:
- //手指抬起时,进行判断当前手势的意图,从而决定是滚动到左侧布局,还是滚动到右侧布局
- xUp=event.getRawX();
- if(beAbleToScroll()){
- if(wantScrollToPrevious()){
- if(shouldScrollToPrevious()){
- currentItemIndex--;
- scrollToPrevious();
- refreshDotsLayout();
- }else{
- scrollToNext();
- }
- }elseif(wantScrollToNext()){
- if(shouldScrollToNext()){
- currentItemIndex++;
- scrollToNext();
- refreshDotsLayout();
- }else{
- scrollToPrevious();
- }
- }
- }
- recycleVelocityTracker();
- break;
- }
- returnfalse;
- }
- /**
- *当前是否能够滚动,滚动到第一个或最后一个元素时将不能再滚动。
- *
- *@return当前leftMargin的值在leftEdge和rightEdge之间返回true,否则返回false。
- */
- privatebooleanbeAbleToScroll(){
- returnfirstItemParams.leftMargin<rightEdge&&firstItemParams.leftMargin>leftEdge;
- }
- /**
- *判断当前手势的意图是不是想滚动到上一个菜单元素。如果手指移动的距离是正数,则认为当前手势是想要滚动到上一个菜单元素。
- *
- *@return当前手势想滚动到上一个菜单元素返回true,否则返回false。
- */
- privatebooleanwantScrollToPrevious(){
- returnxUp-xDown>0;
- }
- /**
- *判断当前手势的意图是不是想滚动到下一个菜单元素。如果手指移动的距离是负数,则认为当前手势是想要滚动到下一个菜单元素。
- *
- *@return当前手势想滚动到下一个菜单元素返回true,否则返回false。
- */
- privatebooleanwantScrollToNext(){
- returnxUp-xDown<0;
- }
- /**
- *判断是否应该滚动到下一个菜单元素。如果手指移动距离大于屏幕的1/2,或者手指移动速度大于SNAP_VELOCITY,
- *就认为应该滚动到下一个菜单元素。
- *
- *@return如果应该滚动到下一个菜单元素返回true,否则返回false。
- */
- privatebooleanshouldScrollToNext(){
- returnxDown-xUp>switcherViewWidth/2||getScrollVelocity()>SNAP_VELOCITY;
- }
- /**
- *判断是否应该滚动到上一个菜单元素。如果手指移动距离大于屏幕的1/2,或者手指移动速度大于SNAP_VELOCITY,
- *就认为应该滚动到上一个菜单元素。
- *
- *@return如果应该滚动到上一个菜单元素返回true,否则返回false。
- */
- privatebooleanshouldScrollToPrevious(){
- returnxUp-xDown>switcherViewWidth/2||getScrollVelocity()>SNAP_VELOCITY;
- }
- /**
- *刷新标签元素布局,每次currentItemIndex值改变的时候都应该进行刷新。
- */
- privatevoidrefreshDotsLayout(){
- dotsLayout.removeAllViews();
- for(inti=0;i<itemsCount;i++){
- LinearLayout.LayoutParamslinearParams=newLinearLayout.LayoutParams(0,
- LayoutParams.FILL_PARENT);
- linearParams.weight=1;
- RelativeLayoutrelativeLayout=newRelativeLayout(getContext());
- ImageViewimage=newImageView(getContext());
- if(i==currentItemIndex){
- image.setBackgroundResource(R.drawable.dot_selected);
- }else{
- image.setBackgroundResource(R.drawable.dot_unselected);
- }
- RelativeLayout.LayoutParamsrelativeParams=newRelativeLayout.LayoutParams(
- LayoutParams.WRAP_CONTENT,LayoutParams.WRAP_CONTENT);
- relativeParams.addRule(RelativeLayout.CENTER_IN_PARENT);
- relativeLayout.addView(image,relativeParams);
- dotsLayout.addView(relativeLayout,linearParams);
- }
- }
- /**
- *创建VelocityTracker对象,并将触摸事件加入到VelocityTracker当中。
- *
- *@paramevent
- *右侧布局监听控件的滑动事件
- */
- privatevoidcreateVelocityTracker(MotionEventevent){
- if(mVelocityTracker==null){
- mVelocityTracker=VelocityTracker.obtain();
- }
- mVelocityTracker.addMovement(event);
- }
- /**
- *获取手指在右侧布局的监听View上的滑动速度。
- *
- *@return滑动速度,以每秒钟移动了多少像素值为单位。
- */
- privateintgetScrollVelocity(){
- mVelocityTracker.computeCurrentVelocity(1000);
- intvelocity=(int)mVelocityTracker.getXVelocity();
- returnMath.abs(velocity);
- }
- /**
- *回收VelocityTracker对象。
- */
- privatevoidrecycleVelocityTracker(){
- mVelocityTracker.recycle();
- mVelocityTracker=null;
- }
- /**
- *检测菜单滚动时,是否有穿越border,border的值都存储在{@link#borders}中。
- *
- *@paramleftMargin
- *第一个元素的左偏移值
- *@paramspeed
- *滚动的速度,正数说明向右滚动,负数说明向左滚动。
- *@return穿越任何一个border了返回true,否则返回false。
- */
- privatebooleanisCrossBorder(intleftMargin,intspeed){
- for(intborder:borders){
- if(speed>0){
- if(leftMargin>=border&&leftMargin-speed<border){
- returntrue;
- }
- }else{
- if(leftMargin<=border&&leftMargin-speed>border){
- returntrue;
- }
- }
- }
- returnfalse;
- }
- /**
- *找到离当前的leftMargin最近的一个border值。
- *
- *@paramleftMargin
- *第一个元素的左偏移值
- *@return离当前的leftMargin最近的一个border值。
- */
- privateintfindClosestBorder(intleftMargin){
- intabsLeftMargin=Math.abs(leftMargin);
- intclosestBorder=borders[0];
- intclosestMargin=Math.abs(Math.abs(closestBorder)-absLeftMargin);
- for(intborder:borders){
- intmargin=Math.abs(Math.abs(border)-absLeftMargin);
- if(margin<closestMargin){
- closestBorder=border;
- closestMargin=margin;
- }
- }
- returnclosestBorder;
- }
- classScrollTaskextendsAsyncTask<Integer,Integer,Integer>{
- @Override
- protectedIntegerdoInBackground(Integer...speed){
- intleftMargin=firstItemParams.leftMargin;
- //根据传入的速度来滚动界面,当滚动穿越border时,跳出循环。
- while(true){
- leftMargin=leftMargin+speed[0];
- if(isCrossBorder(leftMargin,speed[0])){
- leftMargin=findClosestBorder(leftMargin);
- break;
- }
- publishProgress(leftMargin);
- //为了要有滚动效果产生,每次循环使线程睡眠10毫秒,这样肉眼才能够看到滚动动画。
- sleep(10);
- }
- returnleftMargin;
- }
- @Override
- protectedvoidonProgressUpdate(Integer...leftMargin){
- firstItemParams.leftMargin=leftMargin[0];
- firstItem.setLayoutParams(firstItemParams);
- }
- @Override
- protectedvoidonPostExecute(IntegerleftMargin){
- firstItemParams.leftMargin=leftMargin;
- firstItem.setLayoutParams(firstItemParams);
- }
- }
- /**
- *使当前线程睡眠指定的毫秒数。
- *
- *@parammillis
- *指定当前线程睡眠多久,以毫秒为单位
- */
- privatevoidsleep(longmillis){
- try{
- Thread.sleep(millis);
- }catch(InterruptedExceptione){
- e.printStackTrace();
- }
- }
- }
然后看一下布局文件中如何使用我们自定义的这个控件,创建或打开activity_main.xml,里面加入如下代码:
- <LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:tools="http://schemas.android.com/tools"
- android:layout_width="fill_parent"
- android:layout_height="fill_parent"
- android:orientation="horizontal"
- tools:context=".MainActivity">
- <com.example.viewswitcher.SlidingSwitcherView
- android:id="@+id/slidingLayout"
- android:layout_width="fill_parent"
- android:layout_height="100dip">
- <LinearLayout
- android:layout_width="fill_parent"
- android:layout_height="fill_parent"
- android:orientation="horizontal">
- <Button
- android:layout_width="fill_parent"
- android:layout_height="fill_parent"
- android:background="@drawable/image1"/>
- <Button
- android:layout_width="fill_parent"
- android:layout_height="fill_parent"
- android:background="@drawable/image2"/>
- <Button
- android:layout_width="fill_parent"
- android:layout_height="fill_parent"
- android:background="@drawable/image3"/>
- <Button
- android:layout_width="fill_parent"
- android:layout_height="fill_parent"
- android:background="@drawable/image4"/>
- </LinearLayout>
- <LinearLayout
- android:layout_width="60dip"
- android:layout_height="20dip"
- android:layout_alignParentBottom="true"
- android:layout_alignParentRight="true"
- android:layout_margin="15dip"
- android:orientation="horizontal">
- </LinearLayout>
- </com.example.viewswitcher.SlidingSwitcherView>
- </LinearLayout>
然后创建或打开MainActivity作为主界面,里面没有加入任何新增的代码:
- publicclassMainActivityextendsActivity{
- @Override
- protectedvoidonCreate(BundlesavedInstanceState){
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_main);
- }
- }
- <?xmlversion="1.0"encoding="utf-8"?>
- <manifestxmlns:android="http://schemas.android.com/apk/res/android"
- package="com.example.viewswitcher"
- android:versionCode="1"
- android:versionName="1.0">
- <uses-sdk
- android:minSdkVersion="8"
- android:targetSdkVersion="8"/>
- <application
- android:allowBackup="true"
- android:icon="@drawable/ic_launcher"
- android:label="@string/app_name"
- android:theme="@android:style/Theme.NoTitleBar">
- <activity
- android:name="com.example.viewswitcher.MainActivity"
- android:label="@string/app_name">
- <intent-filter>
- <actionandroid:name="android.intent.action.MAIN"/>
- <categoryandroid:name="android.intent.category.LAUNCHER"/>
- </intent-filter>
- </activity>
- </application>
- </manifest>
首先是程序打开的时候,界面显示如下:
然后手指在图片上滑动,我们可以看到图片滚动的效果:
不停的翻页,页签也会跟着一起改变,下图中我们可以看到高亮显示的点是变换的:
恩,对比一下淘宝客户端的效果,我觉得我们模仿的还是挺好的。咦,好像少了点什么。。。。。。原来图片并不会自动播放。。。。。
没关系,我在后面的一篇文章中补充了自动播放这个功能,而且不仅仅是自动播放功能喔,请参考Android图片滚动,加入自动播放功能,使用自定义属性实现,霸气十足!
今天的文章就到这里了,有问题的朋友请在下面留言。
首先题外话,今天早上起床的时候,手滑一下把我的手机甩了出去,结果陪伴我两年半的摩托罗拉里程碑一代就这么安息了,于是我今天决定怒更一记,纪念我死去的爱机。
如果你是网购达人,你的手机上一定少不了淘宝客户端。关注特效的人一定都会发现,淘宝不管是网站还是手机客户端,主页上都会有一个图片滚动播放器,上面展示一些它推荐的商品。这个几乎可以用淘宝来冠名的功能,看起来还是挺炫的,我们今天就来实现一下。
实现原理其实还是之前那篇文章Android滑动菜单特效实现,仿人人客户端侧滑效果,史上最简单的侧滑实现,算是以那个原理为基础的另外一个变种。正所谓一通百通,真正掌握一种方法之后,就可以使用这个方法变换出各种不通的效果。
今天仍然还是实现一个自定义控件,然后我们在任意Activity的布局文件中引用一下,即可实现图片滚动器的效果。
在Eclipse中新建一个Android项目,项目名就叫做SlidingViewSwitcher。
新建一个类,名叫SlidingSwitcherView,这个类是继承自RelativeLayout的,并且实现了OnTouchListener接口,具体代码如下:
- publicclassSlidingSwitcherViewextendsRelativeLayoutimplementsOnTouchListener{
- /**
- *让菜单滚动,手指滑动需要达到的速度。
- */
- publicstaticfinalintSNAP_VELOCITY=200;
- /**
- *SlidingSwitcherView的宽度。
- */
- privateintswitcherViewWidth;
- /**
- *当前显示的元素的下标。
- */
- privateintcurrentItemIndex;
- /**
- *菜单中包含的元素总数。
- */
- privateintitemsCount;
- /**
- *各个元素的偏移边界值。
- */
- privateint[]borders;
- /**
- *最多可以滑动到的左边缘。值由菜单中包含的元素总数来定,marginLeft到达此值之后,不能再减少。
- *
- */
- privateintleftEdge=0;
- /**
- *最多可以滑动到的右边缘。值恒为0,marginLeft到达此值之后,不能再增加。
- */
- privateintrightEdge=0;
- /**
- *记录手指按下时的横坐标。
- */
- privatefloatxDown;
- /**
- *记录手指移动时的横坐标。
- */
- privatefloatxMove;
- /**
- *记录手机抬起时的横坐标。
- */
- privatefloatxUp;
- /**
- *菜单布局。
- */
- privateLinearLayoutitemsLayout;
- /**
- *标签布局。
- */
- privateLinearLayoutdotsLayout;
- /**
- *菜单中的第一个元素。
- */
- privateViewfirstItem;
- /**
- *菜单中第一个元素的布局,用于改变leftMargin的值,来决定当前显示的哪一个元素。
- */
- privateMarginLayoutParamsfirstItemParams;
- /**
- *用于计算手指滑动的速度。
- */
- privateVelocityTrackermVelocityTracker;
- /**
- *重写SlidingSwitcherView的构造函数,用于允许在XML中引用当前的自定义布局。
- *
- *@paramcontext
- *@paramattrs
- */
- publicSlidingSwitcherView(Contextcontext,AttributeSetattrs){
- super(context,attrs);
- }
- /**
- *滚动到下一个元素。
- */
- publicvoidscrollToNext(){
- newScrollTask().execute(-20);
- }
- /**
- *滚动到上一个元素。
- */
- publicvoidscrollToPrevious(){
- newScrollTask().execute(20);
- }
- /**
- *在onLayout中重新设定菜单元素和标签元素的参数。
- */
- @Override
- protectedvoidonLayout(booleanchanged,intl,intt,intr,intb){
- super.onLayout(changed,l,t,r,b);
- if(changed){
- initializeItems();
- initializeDots();
- }
- }
- /**
- *初始化菜单元素,为每一个子元素增加监听事件,并且改变所有子元素的宽度,让它们等于父元素的宽度。
- */
- privatevoidinitializeItems(){
- switcherViewWidth=getWidth();
- itemsLayout=(LinearLayout)getChildAt(0);
- itemsCount=itemsLayout.getChildCount();
- borders=newint[itemsCount];
- for(inti=0;i<itemsCount;i++){
- borders[i]=-i*switcherViewWidth;
- Viewitem=itemsLayout.getChildAt(i);
- MarginLayoutParamsparams=(MarginLayoutParams)item.getLayoutParams();
- params.width=switcherViewWidth;
- item.setLayoutParams(params);
- item.setOnTouchListener(this);
- }
- leftEdge=borders[itemsCount-1];
- firstItem=itemsLayout.getChildAt(0);
- firstItemParams=(MarginLayoutParams)firstItem.getLayoutParams();
- }
- /**
- *初始化标签元素。
- */
- privatevoidinitializeDots(){
- dotsLayout=(LinearLayout)getChildAt(1);
- refreshDotsLayout();
- }
- @Override
- publicbooleanonTouch(Viewv,MotionEventevent){
- createVelocityTracker(event);
- switch(event.getAction()){
- caseMotionEvent.ACTION_DOWN:
- //手指按下时,记录按下时的横坐标
- xDown=event.getRawX();
- break;
- caseMotionEvent.ACTION_MOVE:
- //手指移动时,对比按下时的横坐标,计算出移动的距离,来调整左侧布局的leftMargin值,从而显示和隐藏左侧布局
- xMove=event.getRawX();
- intdistanceX=(int)(xMove-xDown)-(currentItemIndex*switcherViewWidth);
- firstItemParams.leftMargin=distanceX;
- if(beAbleToScroll()){
- firstItem.setLayoutParams(firstItemParams);
- }
- break;
- caseMotionEvent.ACTION_UP:
- //手指抬起时,进行判断当前手势的意图,从而决定是滚动到左侧布局,还是滚动到右侧布局
- xUp=event.getRawX();
- if(beAbleToScroll()){
- if(wantScrollToPrevious()){
- if(shouldScrollToPrevious()){
- currentItemIndex--;
- scrollToPrevious();
- refreshDotsLayout();
- }else{
- scrollToNext();
- }
- }elseif(wantScrollToNext()){
- if(shouldScrollToNext()){
- currentItemIndex++;
- scrollToNext();
- refreshDotsLayout();
- }else{
- scrollToPrevious();
- }
- }
- }
- recycleVelocityTracker();
- break;
- }
- returnfalse;
- }
- /**
- *当前是否能够滚动,滚动到第一个或最后一个元素时将不能再滚动。
- *
- *@return当前leftMargin的值在leftEdge和rightEdge之间返回true,否则返回false。
- */
- privatebooleanbeAbleToScroll(){
- returnfirstItemParams.leftMargin<rightEdge&&firstItemParams.leftMargin>leftEdge;
- }
- /**
- *判断当前手势的意图是不是想滚动到上一个菜单元素。如果手指移动的距离是正数,则认为当前手势是想要滚动到上一个菜单元素。
- *
- *@return当前手势想滚动到上一个菜单元素返回true,否则返回false。
- */
- privatebooleanwantScrollToPrevious(){
- returnxUp-xDown>0;
- }
- /**
- *判断当前手势的意图是不是想滚动到下一个菜单元素。如果手指移动的距离是负数,则认为当前手势是想要滚动到下一个菜单元素。
- *
- *@return当前手势想滚动到下一个菜单元素返回true,否则返回false。
- */
- privatebooleanwantScrollToNext(){
- returnxUp-xDown<0;
- }
- /**
- *判断是否应该滚动到下一个菜单元素。如果手指移动距离大于屏幕的1/2,或者手指移动速度大于SNAP_VELOCITY,
- *就认为应该滚动到下一个菜单元素。
- *
- *@return如果应该滚动到下一个菜单元素返回true,否则返回false。
- */
- privatebooleanshouldScrollToNext(){
- returnxDown-xUp>switcherViewWidth/2||getScrollVelocity()>SNAP_VELOCITY;
- }
- /**
- *判断是否应该滚动到上一个菜单元素。如果手指移动距离大于屏幕的1/2,或者手指移动速度大于SNAP_VELOCITY,
- *就认为应该滚动到上一个菜单元素。
- *
- *@return如果应该滚动到上一个菜单元素返回true,否则返回false。
- */
- privatebooleanshouldScrollToPrevious(){
- returnxUp-xDown>switcherViewWidth/2||getScrollVelocity()>SNAP_VELOCITY;
- }
- /**
- *刷新标签元素布局,每次currentItemIndex值改变的时候都应该进行刷新。
- */
- privatevoidrefreshDotsLayout(){
- dotsLayout.removeAllViews();
- for(inti=0;i<itemsCount;i++){
- LinearLayout.LayoutParamslinearParams=newLinearLayout.LayoutParams(0,
- LayoutParams.FILL_PARENT);
- linearParams.weight=1;
- RelativeLayoutrelativeLayout=newRelativeLayout(getContext());
- ImageViewimage=newImageView(getContext());
- if(i==currentItemIndex){
- image.setBackgroundResource(R.drawable.dot_selected);
- }else{
- image.setBackgroundResource(R.drawable.dot_unselected);
- }
- RelativeLayout.LayoutParamsrelativeParams=newRelativeLayout.LayoutParams(
- LayoutParams.WRAP_CONTENT,LayoutParams.WRAP_CONTENT);
- relativeParams.addRule(RelativeLayout.CENTER_IN_PARENT);
- relativeLayout.addView(image,relativeParams);
- dotsLayout.addView(relativeLayout,linearParams);
- }
- }
- /**
- *创建VelocityTracker对象,并将触摸事件加入到VelocityTracker当中。
- *
- *@paramevent
- *右侧布局监听控件的滑动事件
- */
- privatevoidcreateVelocityTracker(MotionEventevent){
- if(mVelocityTracker==null){
- mVelocityTracker=VelocityTracker.obtain();
- }
- mVelocityTracker.addMovement(event);
- }
- /**
- *获取手指在右侧布局的监听View上的滑动速度。
- *
- *@return滑动速度,以每秒钟移动了多少像素值为单位。
- */
- privateintgetScrollVelocity(){
- mVelocityTracker.computeCurrentVelocity(1000);
- intvelocity=(int)mVelocityTracker.getXVelocity();
- returnMath.abs(velocity);
- }
- /**
- *回收VelocityTracker对象。
- */
- privatevoidrecycleVelocityTracker(){
- mVelocityTracker.recycle();
- mVelocityTracker=null;
- }
- /**
- *检测菜单滚动时,是否有穿越border,border的值都存储在{@link#borders}中。
- *
- *@paramleftMargin
- *第一个元素的左偏移值
- *@paramspeed
- *滚动的速度,正数说明向右滚动,负数说明向左滚动。
- *@return穿越任何一个border了返回true,否则返回false。
- */
- privatebooleanisCrossBorder(intleftMargin,intspeed){
- for(intborder:borders){
- if(speed>0){
- if(leftMargin>=border&&leftMargin-speed<border){
- returntrue;
- }
- }else{
- if(leftMargin<=border&&leftMargin-speed>border){
- returntrue;
- }
- }
- }
- returnfalse;
- }
- /**
- *找到离当前的leftMargin最近的一个border值。
- *
- *@paramleftMargin
- *第一个元素的左偏移值
- *@return离当前的leftMargin最近的一个border值。
- */
- privateintfindClosestBorder(intleftMargin){
- intabsLeftMargin=Math.abs(leftMargin);
- intclosestBorder=borders[0];
- intclosestMargin=Math.abs(Math.abs(closestBorder)-absLeftMargin);
- for(intborder:borders){
- intmargin=Math.abs(Math.abs(border)-absLeftMargin);
- if(margin<closestMargin){
- closestBorder=border;
- closestMargin=margin;
- }
- }
- returnclosestBorder;
- }
- classScrollTaskextendsAsyncTask<Integer,Integer,Integer>{
- @Override
- protectedIntegerdoInBackground(Integer...speed){
- intleftMargin=firstItemParams.leftMargin;
- //根据传入的速度来滚动界面,当滚动穿越border时,跳出循环。
- while(true){
- leftMargin=leftMargin+speed[0];
- if(isCrossBorder(leftMargin,speed[0])){
- leftMargin=findClosestBorder(leftMargin);
- break;
- }
- publishProgress(leftMargin);
- //为了要有滚动效果产生,每次循环使线程睡眠10毫秒,这样肉眼才能够看到滚动动画。
- sleep(10);
- }
- returnleftMargin;
- }
- @Override
- protectedvoidonProgressUpdate(Integer...leftMargin){
- firstItemParams.leftMargin=leftMargin[0];
- firstItem.setLayoutParams(firstItemParams);
- }
- @Override
- protectedvoidonPostExecute(IntegerleftMargin){
- firstItemParams.leftMargin=leftMargin;
- firstItem.setLayoutParams(firstItemParams);
- }
- }
- /**
- *使当前线程睡眠指定的毫秒数。
- *
- *@parammillis
- *指定当前线程睡眠多久,以毫秒为单位
- */
- privatevoidsleep(longmillis){
- try{
- Thread.sleep(millis);
- }catch(InterruptedExceptione){
- e.printStackTrace();
- }
- }
- }
然后看一下布局文件中如何使用我们自定义的这个控件,创建或打开activity_main.xml,里面加入如下代码:
- <LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:tools="http://schemas.android.com/tools"
- android:layout_width="fill_parent"
- android:layout_height="fill_parent"
- android:orientation="horizontal"
- tools:context=".MainActivity">
- <com.example.viewswitcher.SlidingSwitcherView
- android:id="@+id/slidingLayout"
- android:layout_width="fill_parent"
- android:layout_height="100dip">
- <LinearLayout
- android:layout_width="fill_parent"
- android:layout_height="fill_parent"
- android:orientation="horizontal">
- <Button
- android:layout_width="fill_parent"
- android:layout_height="fill_parent"
- android:background="@drawable/image1"/>
- <Button
- android:layout_width="fill_parent"
- android:layout_height="fill_parent"
- android:background="@drawable/image2"/>
- <Button
- android:layout_width="fill_parent"
- android:layout_height="fill_parent"
- android:background="@drawable/image3"/>
- <Button
- android:layout_width="fill_parent"
- android:layout_height="fill_parent"
- android:background="@drawable/image4"/>
- </LinearLayout>
- <LinearLayout
- android:layout_width="60dip"
- android:layout_height="20dip"
- android:layout_alignParentBottom="true"
- android:layout_alignParentRight="true"
- android:layout_margin="15dip"
- android:orientation="horizontal">
- </LinearLayout>
- </com.example.viewswitcher.SlidingSwitcherView>
- </LinearLayout>
然后创建或打开MainActivity作为主界面,里面没有加入任何新增的代码:
- publicclassMainActivityextendsActivity{
- @Override
- protectedvoidonCreate(BundlesavedInstanceState){
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_main);
- }
- }
- <?xmlversion="1.0"encoding="utf-8"?>
- <manifestxmlns:android="http://schemas.android.com/apk/res/android"
- package="com.example.viewswitcher"
- android:versionCode="1"
- android:versionName="1.0">
- <uses-sdk
- android:minSdkVersion="8"
- android:targetSdkVersion="8"/>
- <application
- android:allowBackup="true"
- android:icon="@drawable/ic_launcher"
- android:label="@string/app_name"
- android:theme="@android:style/Theme.NoTitleBar">
- <activity
- android:name="com.example.viewswitcher.MainActivity"
- android:label="@string/app_name">
- <intent-filter>
- <actionandroid:name="android.intent.action.MAIN"/>
- <categoryandroid:name="android.intent.category.LAUNCHER"/>
- </intent-filter>
- </activity>
- </application>
- </manifest>
首先是程序打开的时候,界面显示如下:
然后手指在图片上滑动,我们可以看到图片滚动的效果:
不停的翻页,页签也会跟着一起改变,下图中我们可以看到高亮显示的点是变换的:
恩,对比一下淘宝客户端的效果,我觉得我们模仿的还是挺好的。咦,好像少了点什么。。。。。。原来图片并不会自动播放。。。。。
没关系,我在后面的一篇文章中补充了自动播放这个功能,而且不仅仅是自动播放功能喔,请参考Android图片滚动,加入自动播放功能,使用自定义属性实现,霸气十足!
今天的文章就到这里了,有问题的朋友请在下面留言。
相关推荐
此为示例代码,详细讲解请参考 http://blog.csdn.net/sinyu890807/article/details/8769904
Android高级图片滚动控件,3D版的图片轮播器Demo
主要介绍了Android实现图片滚动控件含页签功能的实现代码,具有很好的参考价值,希望对大家有所帮助,一起跟随小编过来看看吧
Android高级图片滚动控件,3D版的图片轮播器Demo
Android 滚动选择控件
Android应用源码之Android高级图片滚动控件,3D版的图片轮播器Demo.zip
android项目中的标签控件,用于实现热门标签的功能.rar,太多无法一一验证是否可用,程序如果跑不起来需要自调,部分代码功能进行参考学习。
Android应用源码之Android高级图片滚动控件,3D版的图片轮播器Demo.zip项目安卓应用源码下载Android应用源码之Android高级图片滚动控件,3D版的图片轮播器Demo.zip项目安卓应用源码下载 1.适合学生毕业设计研究参考 ...
Android高级应用源码-Android高级图片滚动控件,3D版的图片轮播器Demo.zip
Android 标签控件 标签选择 tag 具体效果 http://blog.csdn.net/qq_21036939/article/details/50675612
基于网上的wheelview控件修改,实现图文滚动效果,可自定义大量属性
Android高级图片滚动控件,3D版的图片轮播器Demo.zip
android 时间滚动控件 底部弹出 如果有不足之处 请提出来 共同修改
该banner(自动滚动广告图)使用viewPager实现,可兼容在viewpager中显示
Android高级图片滚动控件,3D版的图片轮播器Demo.zip项目安卓应用源码下载Android高级图片滚动控件,3D版的图片轮播器Demo.zip项目安卓应用源码下载 1.适合学生毕业设计研究参考 2.适合个人学习研究参考 3.适合公司...
Android字符滚动控件Ticker的实现
android滚动日期控件anroid wheel numberpicker
实现Android时间日期滚动控件效果,效果棒棒棒