Android墨迹3.0特性介绍效果实现——做一个垂直滚动的Layout
16lz
2021-01-26
墨迹天气新版的开机介绍很漂亮,上下滚动翻页,翻页结束后元素会有动画效果,分析一下动画元素都是基本的Animation,没有用到最新的属性动画;上下翻页滚动的控件android没有提供,只有横向的Viewpager,这里有一种实现->点击打开链接,用到了开源的控件ViewPager-Android,我们这里试着手动实现一个上下滚动的翻页控件。
前期准备
首先我们用apktool把墨迹天气的安装包解压出来,取出其中的图片资源和布局文件,一共4个布局
翻页控件实现
要实现自定义布局,需要继承ViewGroup,然后实现onMeasure、onLayout方法
[java] view plain copy print ?
- @Override
- protectedvoidonLayout(booleanchanged,intl,intt,intr,intb){
- intcount=getChildCount();
- intheight=getMeasuredHeight();
- inttop=0;
- for(inti=0;i<count;++i){
- ViewchildView=getChildAt(i);
- if(childView.getVisibility()!=View.GONE){
- childView.layout(l,top,r,top+height);
- top+=height;
- }
- }
- mTotalHeight=height*(count-1);
- mTolerance=height/2;
- }
- @Override
- protectedvoidonMeasure(intwidthMeasureSpec,intheightMeasureSpec){
- super.onMeasure(widthMeasureSpec,heightMeasureSpec);
- intcount=getChildCount();
- for(inti=0;i<count;++i){
- ViewchildView=getChildAt(i);
- measureChild(childView,widthMeasureSpec,heightMeasureSpec);
- }
- }
这里在onLayout方法中将页面排下来,每页内容都充满控件,垂直排列。
这时候在如果在activity中将View inflate出来再通过addview添加到控件中就会看到第一页的内容,但此时还不能滑动。下面我们就来实现上下滑动翻页。
要响应控件上的手势操作需要实现onTouchEvent方法:
[java] view plain copy print ?
- @Override
- publicbooleanonTouchEvent(MotionEventevent){
- if(mVelocityTracker==null){
- mVelocityTracker=VelocityTracker.obtain();
- }
- mVelocityTracker.addMovement(event);
- switch(event.getAction()){
- caseMotionEvent.ACTION_DOWN:
- if(!mScroller.isFinished()){
- mScroller.abortAnimation();
- }
- mLastY=(int)event.getY();
- mStartYPosition=getScrollY();
- break;
- caseMotionEvent.ACTION_MOVE:
- inty=(int)event.getY();
- intdistance=mLastY-y;
- intscrollY=getScrollY();
- //边界检查
- if(distance<0&&scrollY+distance<0){
- distance=0-scrollY;
- }elseif(distance>0&&scrollY+distance>mTotalHeight){
- distance=mTotalHeight-scrollY;
- }
- scrollBy(0,distance);
- mLastY=y;
- break;
- caseMotionEvent.ACTION_UP:
- mEndYPosition=getScrollY();
- intposDiff=mEndYPosition-mStartYPosition;
- mVelocityTracker.computeCurrentVelocity(1000);
- intvelocityY=(int)mVelocityTracker.getYVelocity();
- mVelocityTracker.recycle();
- mVelocityTracker=null;
- if(Math.abs(velocityY)>=600||Math.abs(posDiff)>mTolerance){
- intdis=0;
- if(posDiff>0){
- dis=getMeasuredHeight()-posDiff;
- }elseif(posDiff<0){
- dis=-(getMeasuredHeight()+posDiff);
- }
- mScroller.startScroll(0,0,0,dis);
- }else{
- mScroller.startScroll(0,0,0,-posDiff);
- }
- postInvalidate();
- break;
- default:
- break;
- }
- returntrue;
- }
上面的这些操作包括了滚动、边界检查(避免滑出边界)和完成翻页的功能,最开始其实是这样的
[java] view plain copy print ?
- @Override
- publicbooleanonTouchEvent(MotionEventevent){
- switch(event.getAction()){
- caseMotionEvent.ACTION_DOWN:
- mLastY=(int)event.getY();
- break;
- caseMotionEvent.ACTION_MOVE:
- inty=(int)event.getY();
- intdistance=mLastY-y;
- scrollBy(0,distance);
- mLastY=y;
- break;
- caseMotionEvent.ACTION_UP:
- break;
- default:
- break;
- }
- returntrue;
- }
页面可以随着手指上下滚动,但是会超出边界,再添加上边界检查,就是修改一下ACTION_MOVE,
[java] view plain copy print ?
- caseMotionEvent.ACTION_MOVE:
- inty=(int)event.getY();
- intdistance=mLastY-y;
- intscrollY=getScrollY();
- //边界检查
- if(distance<0&&scrollY+distance<0){
- distance=0-scrollY;
- }elseif(distance>0&&scrollY+distance>mTotalHeight){
- distance=mTotalHeight-scrollY;
- }
- scrollBy(0,distance);
- mLastY=y;
- break;
这时候再滚动的时候就会发现到达边界的时候就无法再滑动了,下面再添加滑动半屏后自动完成翻页的功能,就是最上面的那个完整的代码,里面用到了scroller,在抬起手指的时候计算滚动剩余距离,然后开始滚动,scroller只负责完成滚动过程位置的计算,真正控制页面的是在computeScroll()方法里:
[java] view plain copy print ?
- @Override
- publicvoidcomputeScroll(){
- if(mScroller.computeScrollOffset()){
- intscroll=mScroller.getCurrY();
- if(scroll>0&&mEndYPosition+scroll>mTotalHeight){
- scroll=mTotalHeight-mEndYPosition;
- }elseif(scroll<0&&mEndYPosition+scroll<0){
- scroll=-mEndYPosition;
- }
- scrollTo(0,mEndYPosition+scroll);
- mIsScrolling=true;
- postInvalidate();
- }elseif(mIsScrolling){
- if(mPageScrollListener!=null){
- intposition=getScrollY()/getMeasuredHeight();
- if(position!=mCurrentPage){
- mCurrentPage=position;
- mPageScrollListener.onPageChanged(mCurrentPage);
- }
- }
- mIsScrolling=false;
- }
- }
每次页面重绘都会调用computeScroll方法,然后通过scroller得到此时的滚动值,再次重绘,直到滚动结束,这里也做了下边界检测,防止滚过头了。
滚动结束后要通知控件的使用者翻页已完成,所以定义一个翻页完成的接口
[java] view plain copy print ?
- publicvoidsetOnPageScrollListener(OnPageScrollListenerlistener){
- mPageScrollListener=listener;
- }
- publicinterfaceOnPageScrollListener{
- publicvoidonPageChanged(intposition);
- }
在computeScroll()中发现翻页完成了就调用这个接口。
剩下的就是在activity中加载动画了,每当翻页结束就播放相应页面的动画并清除上一页的动画效果
[java] view plain copy print ?
- classMyPageScrollListenerimplementsOnPageScrollListener{
- @Override
- publicvoidonPageChanged(intposition){
- switch(position){
- case0:
- layout1AnimStart();
- break;
- case1:
- layout2AnimStart();
- break;
- case2:
- layout3AnimStart();
- break;
- case3:
- layout4AnimStart();
- break;
- }
- }
- }
演示效果
代码在这里->http://download.csdn.net/detail/xu_fu/7185403
更多相关文章
- android Activity布局初步(三)- 相对布局
- mono for android 第三课--页面布局
- Android(安卓)Viewpage禁止滑动屏幕
- 使用动画和fragment改善Android表单
- android页面布局时定义控件ID时@id/XX和@+id/xx 有什么区别?
- Android(安卓)引导页动态添加圆点指示器
- Android(安卓)自定义View(三):重写View实现全新控件
- Android(安卓)API Guides---Accessibility Developer Checklist
- Android通用标题栏组合控件