Android墨迹3.0特性介绍效果实现——做一个垂直滚动的Layout

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

前期准备

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

Android墨迹3.0特性介绍效果实现——做一个垂直滚动的Layout_第1张图片

翻页控件实现

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

[java]  view plain  copy
 print ?
  1. @Override  
  2.     protected void onLayout(boolean changed, int l, int t, int r, int b) {  
  3.         int count = getChildCount();  
  4.         int height = getMeasuredHeight();  
  5.         int top = 0;  
  6.         for (int i = 0; i < count; ++i) {  
  7.             View childView = 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.   
  17.     @Override  
  18.     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {  
  19.         super.onMeasure(widthMeasureSpec, heightMeasureSpec);  
  20.         int count = getChildCount();  
  21.         for (int i = 0; i < count; ++i) {  
  22.             View childView = getChildAt(i);  
  23.             measureChild(childView, widthMeasureSpec, heightMeasureSpec);  
  24.         }  
  25.     }  

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

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

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

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

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

[java]  view plain  copy
 print ?
  1. @Override  
  2.     public boolean onTouchEvent(MotionEvent event) {  
  3.   
  4.         switch (event.getAction()) {  
  5.         case MotionEvent.ACTION_DOWN:  
  6.             mLastY = (int) event.getY();  
  7.             break;  
  8.         case MotionEvent.ACTION_MOVE:  
  9.             int y = (int) event.getY();  
  10.             int distance = mLastY - y;  
  11.             scrollBy(0, distance);  
  12.             mLastY = y;  
  13.             break;  
  14.         case MotionEvent.ACTION_UP:  
  15.             break;  
  16.         default:  
  17.             break;  
  18.         }  
  19.   
  20.         return true;  
  21.     }  

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

[java]  view plain  copy
 print ?
  1. case MotionEvent.ACTION_MOVE:  
  2.     int y = (int) event.getY();  
  3.     int distance = mLastY - y;  
  4.     int scrollY = getScrollY();  
  5.     // 边界检查  
  6.     if (distance < 0 && scrollY + distance < 0) {  
  7.         distance = 0 - scrollY;  
  8.     } else if (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. public void computeScroll() {  
  3.   
  4.     if (mScroller.computeScrollOffset()) {  
  5.         int scroll = mScroller.getCurrY();  
  6.         if (scroll > 0 && mEndYPosition + scroll > mTotalHeight) {  
  7.             scroll = mTotalHeight - mEndYPosition;  
  8.         } else if (scroll < 0 && mEndYPosition + scroll < 0) {  
  9.             scroll = -mEndYPosition;  
  10.         }  
  11.         scrollTo(0, mEndYPosition + scroll);  
  12.         mIsScrolling = true;  
  13.         postInvalidate();  
  14.     } else if (mIsScrolling) {  
  15.         if (mPageScrollListener != null) {  
  16.             int position = getScrollY() / getMeasuredHeight();  
  17.             if (position != mCurrentPage) {  
  18.                 mCurrentPage = position;  
  19.                 mPageScrollListener.onPageChanged(mCurrentPage);  
  20.             }  
  21.         }  
  22.         mIsScrolling = false;  
  23.     }  
  24. }  

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

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

[java]  view plain  copy
 print ?
  1. public void setOnPageScrollListener(OnPageScrollListener listener) {  
  2.         mPageScrollListener = listener;  
  3.     }  
  4.   
  5.     public interface OnPageScrollListener {  
  6.         public void onPageChanged(int position);  
  7.     }  

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

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

[java]  view plain  copy
 print ?
  1. class MyPageScrollListener implements OnPageScrollListener {  
  2.   
  3.         @Override  
  4.         public void onPageChanged(int position) {  
  5.             switch (position) {  
  6.             case 0:  
  7.                 layout1AnimStart();  
  8.                 break;  
  9.             case 1:  
  10.                 layout2AnimStart();  
  11.                 break;  
  12.             case 2:  
  13.                 layout3AnimStart();  
  14.                 break;  
  15.             case 3:  
  16.                 layout4AnimStart();  
  17.                 break;  
  18.             }  
  19.         }  
  20.   
  21.     }  

演示效果

Android墨迹3.0特性介绍效果实现——做一个垂直滚动的Layout_第2张图片

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

你可能感兴趣的:(android,动画,viewpager,控件,墨迹天气)