在android应用程序的开发过程中,相信我们很多人都想把应用的交互做的比较绚丽,比如让界面切换平滑的滚动,还有热度灰常高的伪3D等界面效果,通常情况下,系统提供的应用在特效这方面只能为我们提供简单的动画接口,所以要想实现比较酷炫的效果还是要自己去开发布局控件(即所谓的自定义View、ViewGroup)。
下面就自定义控件开发做一些简单的介绍,其实那个地方原本可以用ScrollView解决很大一部分问题的,但有一些效果确实需要对控件进行重新定义,在继承ScrollView开发中仍然会遇到一些ScrollView自身的限制,所以就仿照ScrollView自己做了一个控件。在其中遇到了一些问题自然就是像ScrollView中拖动的效果(比如快速拖动在手指离开屏幕时控件依旧会由于惯性继续滑动一段距离后才会停止运动),所以就对这个东东做了一下仔细的研究,虽然以前也做过类似的开发,这次由于时间比较充裕,所以将开发中遇到的一些问题都一一记录了下来。下面开始正题:
自定义布局控件自然是要继承某个View或ViewGroup
由于是根据项目的开发来写的这篇博客,所以我就以自定义布局控件(ViewGroup)来做介绍了。
开发一个自定义的ViewGroup自然是要继承ViewGroup类了,在继承这个类之后必须要重写的方法就是
onLayout(boolean changed, int l, int t, int r, int b)
另外至少要有一个构造方法,我个人习惯重写那个有两个参数的构造方法(XXX(Context context, AttributeSet attrs)),因为有了这个构造方法就可以在xml布局文件里使用这个类了,如果想要对这个布局控件以及其子控件的尺寸进行精确的控制那就要重写下面这个方法了
onMeasure(int widthMeasureSpec, int heightMeasureSpec)
这个方法从字面理解就是估算控件的尺寸大小了.
下面开始介绍关于如何让自定义的控件进行平滑的移动,并能够根据手势的情况产生惯性滑动的效果
先介绍一下开发这种滑动效果需要用到的各种工具类:
android.view.VelocityTracker
android.view.Scroller
android.view.ViewConfiguration
VelocityTracker从字面意思理解那就是速度追踪器了,在滑动效果的开发中通常都是要使用该类计算出当前手势的初始速度(不知道我这么理解是否正确,对应的方法是velocityTracker.computeCurrentVelocity(1000, mMaximumVelocity))并通过getXVelocity或getYVelocity方法得到对应的速度值initialVelocity,并将获得的速度值传递给Scroller类的fling(int startX, int startY, int velocityX, int velocityY, int minX, int maxX, int minY, int maxY) 方法进行控件滚动时各种位置坐标数值的计算,API中对fling 方法的解释是基于一个fling手势开始滑动动作,滑动的距离将由所获得的初始速度initialVelocity来决定。
关于ViewConfiguration 的使用主要使用了该类的下面三个方法:
configuration.getScaledTouchSlop() //获得能够进行手势滑动的距离
configuration.getScaledMinimumFlingVelocity()//获得允许执行一个fling手势动作的最小速度值
configuration.getScaledMaximumFlingVelocity()//获得允许执行一个fling手势动作的最大速度值
需要重写的方法至少要包含下面几个方法:
onTouchEvent(MotionEvent event)//有手势操作必然少不了这个方法了
computeScroll()//必要时由父控件调用请求或通知其一个子节点需要更新它的mScrollX和mScrollY的值。典型的例子就是在一个子节点正在使用Scroller进行滑动动画时将会被执行。所以,从该方法的注释来看,继承这个方法的话一般都会有Scroller对象出现。
在往下就是介绍比较具体的开发思路
首先我们要初始化一些变量,其中的多数代码已经在上面做出介绍了
void init(Context context) { mScroller = new Scroller(getContext()); setFocusable(true); setDescendantFocusability(FOCUS_AFTER_DESCENDANTS); setWillNotDraw(false); final ViewConfiguration configuration = ViewConfiguration.get(context); mTouchSlop = configuration.getScaledTouchSlop(); mMinimumVelocity = configuration.getScaledMinimumFlingVelocity(); mMaximumVelocity = configuration.getScaledMaximumFlingVelocity(); }
public void fling(int velocityY) { if (getChildCount() > 0) { mScroller.fling(getScrollX(), getScrollY(), 0, velocityY, 0, 0, 0, maxScrollEdge); final boolean movingDown = velocityY > 0; awakenScrollBars(mScroller.getDuration()); invalidate(); } }
private void obtainVelocityTracker(MotionEvent event) { if (mVelocityTracker == null) { mVelocityTracker = VelocityTracker.obtain(); } mVelocityTracker.addMovement(event); } private void releaseVelocityTracker() { if (mVelocityTracker != null) { mVelocityTracker.recycle(); mVelocityTracker = null; } }
public boolean onTouchEvent(MotionEvent event) { if (event.getAction() == MotionEvent.ACTION_DOWN && event.getEdgeFlags() != 0) { return false; } obtainVelocityTracker(event); final int action = event.getAction(); final float x = event.getX(); final float y = event.getY(); switch (action) { case MotionEvent.ACTION_DOWN: LogUtil.log(TAG, "ACTION_DOWN#currentScrollY:" + getScrollY() + ", mLastMotionY:" + mLastMotionY, LogUtil.LOG_E); if (!mScroller.isFinished()) { mScroller.abortAnimation(); } mLastMotionY = y; break; case MotionEvent.ACTION_MOVE: final int deltaY = (int) (mLastMotionY - y); mLastMotionY = y; if (deltaY < 0) { if (getScrollY() > 0) { scrollBy(0, deltaY); } } else if (deltaY > 0) { mIsInEdge = getScrollY() <= childTotalHeight - height; if (mIsInEdge) { scrollBy(0, deltaY); } } break; case MotionEvent.ACTION_UP: final VelocityTracker velocityTracker = mVelocityTracker; velocityTracker.computeCurrentVelocity(1000, mMaximumVelocity); int initialVelocity = (int) velocityTracker.getYVelocity(); if ((Math.abs(initialVelocity) > mMinimumVelocity) && getChildCount() > 0) { fling(-initialVelocity); } releaseVelocityTracker(); break; } return true; }
public void computeScroll() { if (mScroller.computeScrollOffset()) { int scrollX = getScrollX(); int scrollY = getScrollY(); int oldX = scrollX; int oldY = scrollY; int x = mScroller.getCurrX(); int y = mScroller.getCurrY(); scrollX = x; scrollY = y; scrollY = scrollY + 10; scrollTo(scrollX, scrollY); postInvalidate(); } }
public void scrollTo(int x, int y) { if (mScrollX != x || mScrollY != y) { int oldX = mScrollX; int oldY = mScrollY; mScrollX = x; mScrollY = y; onScrollChanged(mScrollX, mScrollY, oldX, oldY); if (!awakenScrollBars()) { invalidate(); } } }
相关推荐
高德地图自定义平滑移动,效果比高德好
高德地图Marker平滑移动,这是一个让marker在地图上平滑移动的demo
android-smooth-move, android marker点沿线平滑移动效果
基于高德地图3D API做的点平滑移动效果,Android车辆轨迹平滑移动【旧版本】
Android 自定义View制作随时间增长的平滑进度条 博客地址:http://blog.csdn.net/nickey_1314/article/details/51006146
6.4.2 读取来自style和theme中的属性 181 6.5 案例1:圆形ImageView组件 186 6.6 案例2:验证码组件CodeView 190 6.7 练习作业 202 第七章 自定义容器 204 7.1 概述 204 7.2 ViewGroup类 205 7.2.1 ViewGroup常用...
Android 自定义View制作随时间增长的平滑进度条.rar,太多无法一一验证是否可用,程序如果跑不起来需要自调,部分代码功能进行参考学习。
对高德地图轨迹平滑移动的官方demo做了一点改进,易于大家理解。
高德地图平滑移动高德地图平滑移动高德地图平滑移动高德地图平滑移动
雨松MOMO Unity3D 游戏开发系列博文之Unity3D 游戏引擎之iOS自定义游戏摇杆与飞机平滑的移动,欢迎大家下载阅读,哇咔咔~~
MFC中使用gdi+实现图形平滑移动,使用线程控制,简单的图形界面
易语言鼠标平滑移动源码,鼠标平滑移动
android 主角移动与地图平滑滚动~~~~~~~~~~~~~~
安卓Android源码——主角移动与地图平滑滚动.zip
这是原文http://blog.csdn.net/android_upl/article/details/78647147
利用百度地图API实现在地图车辆的平滑移动,轨迹回放,多台车辆同时平滑移动
当前打车软件很火,而且在地图上可以看到车辆在实时的移动,本文主要介绍如何实现车辆在地图上平滑动态的移动;
scrollView跟列表手势拖拽平滑交互效果,可用伸缩布局,布局可定制,使用简单,demo使用比较清晰。
SmartTabLayout 是一个自定义的 Tab title strip, 基于 Google Samples 中的 android-SlidingTabBasic 项目, 滑动时 Indicator 可平滑过渡。效果图: