墨迹天气新版的开机介绍很漂亮,上下滚动翻页,翻页结束后元素会有动画效果,分析一下动画元素都是基本的Animation,没有用到最新的属性动画;上下翻页滚动的控件android没有提供,只有横向的Viewpager,这里有一种实现->点击打开链接,用到了开源的控件ViewPager-Android,我们这里试着手动实现一个上下滚动的翻页控件。

前期准备

首先我们用apktool把墨迹天气的安装包解压出来,取出其中的图片资源和布局文件,一共4个布局


翻页控件实现

要实现自定义布局,需要继承ViewGroup,然后实现onMeasure、onLayout方法

[java] view plain copy print ?
  1. @Override
  2. protectedvoidonLayout(booleanchanged,intl,intt,intr,intb){
  3. intcount=getChildCount();
  4. intheight=getMeasuredHeight();
  5. inttop=0;
  6. for(inti=0;i<count;++i){
  7. ViewchildView=getChildAt(i);
  8. if(childView.getVisibility()!=View.GONE){
  9. childView.layout(l,top,r,top+height);
  10. top+=height;
  11. }
  12. }
  13. mTotalHeight=height*(count-1);
  14. mTolerance=height/2;
  15. }
  16. @Override
  17. protectedvoidonMeasure(intwidthMeasureSpec,intheightMeasureSpec){
  18. super.onMeasure(widthMeasureSpec,heightMeasureSpec);
  19. intcount=getChildCount();
  20. for(inti=0;i<count;++i){
  21. ViewchildView=getChildAt(i);
  22. measureChild(childView,widthMeasureSpec,heightMeasureSpec);
  23. }
  24. }

这里在onLayout方法中将页面排下来,每页内容都充满控件,垂直排列。

这时候在如果在activity中将View inflate出来再通过addview添加到控件中就会看到第一页的内容,但此时还不能滑动。下面我们就来实现上下滑动翻页。

要响应控件上的手势操作需要实现onTouchEvent方法:

[java] view plain copy print ?
  1. @Override
  2. publicbooleanonTouchEvent(MotionEventevent){
  3. if(mVelocityTracker==null){
  4. mVelocityTracker=VelocityTracker.obtain();
  5. }
  6. mVelocityTracker.addMovement(event);
  7. switch(event.getAction()){
  8. caseMotionEvent.ACTION_DOWN:
  9. if(!mScroller.isFinished()){
  10. mScroller.abortAnimation();
  11. }
  12. mLastY=(int)event.getY();
  13. mStartYPosition=getScrollY();
  14. break;
  15. caseMotionEvent.ACTION_MOVE:
  16. inty=(int)event.getY();
  17. intdistance=mLastY-y;
  18. intscrollY=getScrollY();
  19. //边界检查
  20. if(distance<0&&scrollY+distance<0){
  21. distance=0-scrollY;
  22. }elseif(distance>0&&scrollY+distance>mTotalHeight){
  23. distance=mTotalHeight-scrollY;
  24. }
  25. scrollBy(0,distance);
  26. mLastY=y;
  27. break;
  28. caseMotionEvent.ACTION_UP:
  29. mEndYPosition=getScrollY();
  30. intposDiff=mEndYPosition-mStartYPosition;
  31. mVelocityTracker.computeCurrentVelocity(1000);
  32. intvelocityY=(int)mVelocityTracker.getYVelocity();
  33. mVelocityTracker.recycle();
  34. mVelocityTracker=null;
  35. if(Math.abs(velocityY)>=600||Math.abs(posDiff)>mTolerance){
  36. intdis=0;
  37. if(posDiff>0){
  38. dis=getMeasuredHeight()-posDiff;
  39. }elseif(posDiff<0){
  40. dis=-(getMeasuredHeight()+posDiff);
  41. }
  42. mScroller.startScroll(0,0,0,dis);
  43. }else{
  44. mScroller.startScroll(0,0,0,-posDiff);
  45. }
  46. postInvalidate();
  47. break;
  48. default:
  49. break;
  50. }
  51. returntrue;
  52. }

上面的这些操作包括了滚动、边界检查(避免滑出边界)和完成翻页的功能,最开始其实是这样的

[java] view plain copy print ?
  1. @Override
  2. publicbooleanonTouchEvent(MotionEventevent){
  3. switch(event.getAction()){
  4. caseMotionEvent.ACTION_DOWN:
  5. mLastY=(int)event.getY();
  6. break;
  7. caseMotionEvent.ACTION_MOVE:
  8. inty=(int)event.getY();
  9. intdistance=mLastY-y;
  10. scrollBy(0,distance);
  11. mLastY=y;
  12. break;
  13. caseMotionEvent.ACTION_UP:
  14. break;
  15. default:
  16. break;
  17. }
  18. returntrue;
  19. }

页面可以随着手指上下滚动,但是会超出边界,再添加上边界检查,就是修改一下ACTION_MOVE,

[java] view plain copy print ?
  1. caseMotionEvent.ACTION_MOVE:
  2. inty=(int)event.getY();
  3. intdistance=mLastY-y;
  4. intscrollY=getScrollY();
  5. //边界检查
  6. if(distance<0&&scrollY+distance<0){
  7. distance=0-scrollY;
  8. }elseif(distance>0&&scrollY+distance>mTotalHeight){
  9. distance=mTotalHeight-scrollY;
  10. }
  11. scrollBy(0,distance);
  12. mLastY=y;
  13. break;

这时候再滚动的时候就会发现到达边界的时候就无法再滑动了,下面再添加滑动半屏后自动完成翻页的功能,就是最上面的那个完整的代码,里面用到了scroller,在抬起手指的时候计算滚动剩余距离,然后开始滚动,scroller只负责完成滚动过程位置的计算,真正控制页面的是在computeScroll()方法里:

[java] view plain copy print ?
  1. @Override
  2. publicvoidcomputeScroll(){
  3. if(mScroller.computeScrollOffset()){
  4. intscroll=mScroller.getCurrY();
  5. if(scroll>0&&mEndYPosition+scroll>mTotalHeight){
  6. scroll=mTotalHeight-mEndYPosition;
  7. }elseif(scroll<0&&mEndYPosition+scroll<0){
  8. scroll=-mEndYPosition;
  9. }
  10. scrollTo(0,mEndYPosition+scroll);
  11. mIsScrolling=true;
  12. postInvalidate();
  13. }elseif(mIsScrolling){
  14. if(mPageScrollListener!=null){
  15. intposition=getScrollY()/getMeasuredHeight();
  16. if(position!=mCurrentPage){
  17. mCurrentPage=position;
  18. mPageScrollListener.onPageChanged(mCurrentPage);
  19. }
  20. }
  21. mIsScrolling=false;
  22. }
  23. }

每次页面重绘都会调用computeScroll方法,然后通过scroller得到此时的滚动值,再次重绘,直到滚动结束,这里也做了下边界检测,防止滚过头了。

滚动结束后要通知控件的使用者翻页已完成,所以定义一个翻页完成的接口

[java] view plain copy print ?
  1. publicvoidsetOnPageScrollListener(OnPageScrollListenerlistener){
  2. mPageScrollListener=listener;
  3. }
  4. publicinterfaceOnPageScrollListener{
  5. publicvoidonPageChanged(intposition);
  6. }

在computeScroll()中发现翻页完成了就调用这个接口。

剩下的就是在activity中加载动画了,每当翻页结束就播放相应页面的动画并清除上一页的动画效果

[java] view plain copy print ?
  1. classMyPageScrollListenerimplementsOnPageScrollListener{
  2. @Override
  3. publicvoidonPageChanged(intposition){
  4. switch(position){
  5. case0:
  6. layout1AnimStart();
  7. break;
  8. case1:
  9. layout2AnimStart();
  10. break;
  11. case2:
  12. layout3AnimStart();
  13. break;
  14. case3:
  15. layout4AnimStart();
  16. break;
  17. }
  18. }
  19. }

演示效果


代码在这里->http://download.csdn.net/detail/xu_fu/7185403

更多相关文章

  1. android Activity布局初步(三)- 相对布局
  2. mono for android 第三课--页面布局
  3. Android(安卓)Viewpage禁止滑动屏幕
  4. 使用动画和fragment改善Android表单
  5. android页面布局时定义控件ID时@id/XX和@+id/xx 有什么区别?
  6. Android(安卓)引导页动态添加圆点指示器
  7. Android(安卓)自定义View(三):重写View实现全新控件
  8. Android(安卓)API Guides---Accessibility Developer Checklist
  9. Android通用标题栏组合控件

随机推荐

  1. Android本地语音识别引擎PocketSphinx-语
  2. 使用Android(安卓)OpenGL ES 2.0绘图之五
  3. 配置Android开发环境
  4. Android事件分发机制完全解析,带你从源码
  5. Android中图像变换Matrix的原理、代码验
  6. Eclipse 中打不开android sdk managerf
  7. android的数据存储和访问 附源码
  8. 【Android Api 翻译2】Android Testing(1
  9. Android编译系统二
  10. 【Android您问我讲】超炫的左右滑动效果