当前位置: 代码迷 >> Android >> Android墨迹3.0特点介绍效果实现——做一个滚动的Layout
  详细解决方案

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

热度:8   发布时间:2016-04-28 06:10:19.0
Android墨迹3.0特性介绍效果实现——做一个滚动的Layout

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

前期准备

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


翻页控件实现

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

@Override	protected void onLayout(boolean changed, int l, int t, int r, int b) {		int count = getChildCount();		int height = getMeasuredHeight();		int top = 0;		for (int i = 0; i < count; ++i) {			View childView = getChildAt(i);			if (childView.getVisibility() != View.GONE) {				childView.layout(l, top, r, top + height);				top += height;			}		}		mTotalHeight = height * (count - 1);		mTolerance = height / 2;	}	@Override	protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {		super.onMeasure(widthMeasureSpec, heightMeasureSpec);		int count = getChildCount();		for (int i = 0; i < count; ++i) {			View childView = getChildAt(i);			measureChild(childView, widthMeasureSpec, heightMeasureSpec);		}	}

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

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

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

	@Override	public boolean onTouchEvent(MotionEvent event) {		if (mVelocityTracker == null) {			mVelocityTracker = VelocityTracker.obtain();		}		mVelocityTracker.addMovement(event);		switch (event.getAction()) {		case MotionEvent.ACTION_DOWN:			if (!mScroller.isFinished()) {				mScroller.abortAnimation();			}			mLastY = (int) event.getY();			mStartYPosition = getScrollY();			break;		case MotionEvent.ACTION_MOVE:			int y = (int) event.getY();			int distance = mLastY - y;			int scrollY = getScrollY();			// 边界检查			if (distance < 0 && scrollY + distance < 0) {				distance = 0 - scrollY;			} else if (distance > 0 && scrollY + distance > mTotalHeight) {				distance = mTotalHeight - scrollY;			}			scrollBy(0, distance);			mLastY = y;			break;		case MotionEvent.ACTION_UP:			mEndYPosition = getScrollY();			int posDiff = mEndYPosition - mStartYPosition;			mVelocityTracker.computeCurrentVelocity(1000);			int velocityY = (int) mVelocityTracker.getYVelocity();			mVelocityTracker.recycle();			mVelocityTracker = null;			if (Math.abs(velocityY) >= 600 || Math.abs(posDiff) > mTolerance) {				int dis = 0;				if (posDiff > 0) {					dis = getMeasuredHeight() - posDiff;				} else if (posDiff < 0) {					dis = -(getMeasuredHeight() + posDiff);				}				mScroller.startScroll(0, 0, 0, dis);			} else {				mScroller.startScroll(0, 0, 0, -posDiff);			}			postInvalidate();			break;		default:			break;		}		return true;	}

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

@Override	public boolean onTouchEvent(MotionEvent event) {		switch (event.getAction()) {		case MotionEvent.ACTION_DOWN:			mLastY = (int) event.getY();			break;		case MotionEvent.ACTION_MOVE:			int y = (int) event.getY();			int distance = mLastY - y;			scrollBy(0, distance);			mLastY = y;			break;		case MotionEvent.ACTION_UP:			break;		default:			break;		}		return true;	}

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

		case MotionEvent.ACTION_MOVE:			int y = (int) event.getY();			int distance = mLastY - y;			int scrollY = getScrollY();			// 边界检查			if (distance < 0 && scrollY + distance < 0) {				distance = 0 - scrollY;			} else if (distance > 0 && scrollY + distance > mTotalHeight) {				distance = mTotalHeight - scrollY;			}			scrollBy(0, distance);			mLastY = y;			break;

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

	@Override	public void computeScroll() {		if (mScroller.computeScrollOffset()) {			int scroll = mScroller.getCurrY();			if (scroll > 0 && mEndYPosition + scroll > mTotalHeight) {				scroll = mTotalHeight - mEndYPosition;			} else if (scroll < 0 && mEndYPosition + scroll < 0) {				scroll = -mEndYPosition;			}			scrollTo(0, mEndYPosition + scroll);			mIsScrolling = true;			postInvalidate();		} else if (mIsScrolling) {			if (mPageScrollListener != null) {				int position = getScrollY() / getMeasuredHeight();				if (position != mCurrentPage) {					mCurrentPage = position;					mPageScrollListener.onPageChanged(mCurrentPage);				}			}			mIsScrolling = false;		}	}

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

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

public void setOnPageScrollListener(OnPageScrollListener listener) {		mPageScrollListener = listener;	}	public interface OnPageScrollListener {		public void onPageChanged(int position);	}

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

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

class MyPageScrollListener implements OnPageScrollListener {		@Override		public void onPageChanged(int position) {			switch (position) {			case 0:				layout1AnimStart();				break;			case 1:				layout2AnimStart();				break;			case 2:				layout3AnimStart();				break;			case 3:				layout4AnimStart();				break;			}		}	}

演示效果


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

  相关解决方案