《Android中使用Scroller实现非全屏宽度抽屉动画》中使用Scroller实现了一个侧滑动画效果。文中很多细节没说清楚同时有很多需求上的不足。
本例是一种使用Layout的属性对象实现的侧滑动画,仅实现根据手指滑动侧滑。
Activity的布局:
Aty代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
/** * 布局属性动画测试 <br/> * 本aty的布局最外层时RelativeLayout <br/> * bottom是个LinearLayout,和动画的实现没多大关系<br/> * top层是自定义的LinearLayout布局,重写onTouchEvent事件用于实现动画 <br/> * top层默认遮挡bottom * * @author vigiles */ public class HomeActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // bottom层的按钮 findViewById(R.id.btn).setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { Toast.makeText(HomeActivity.this, "底层控件响应:威格灵博客", 0).show(); } }); // top层的按钮 findViewById(R.id.btn2).setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { Toast.makeText(HomeActivity.this, "top布局控件响应:cuiweiyou.com", 0).show(); } }); } } |
自定义侧滑类
用到了速度判断,手指滑动速度够快,侧滑即即刻执行。用到VelocityTracker速度追踪器。这个功能可以删除。
onLayout()
首先重写此方法,主要目的是得到本布局的属性对象。
//**
* 随手指滑动时,系统持续调用此方法重绘此视图/界面/布局
* 应用运行第一次加载此布局时即调用一次。初始化属性实例,非常重要!!!
* @param changed 此布局滑动/移动 即true
* @param l 此布局左边相对于父容器 左 边的位置,位于父左边的左边为负数
* @param r 此布局右边相对于父容器 左 边的位置
* @param t 此布局顶边相对于父容器 顶 边的位置
* @param b 此布局底边相对于父容器 顶 边的位置
*//
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
@Override protected void onLayout(boolean changed, int l, int t, int r, int b) { super.onLayout(changed, l, t, r, b); // 如果位置移动了 if (changed) { // 获取布局对象 contentParams = (RelativeLayout.LayoutParams) this.getLayoutParams(); contentParams.width = contentWidth; setLayoutParams(contentParams); } } |
onTouchEvent
然后是必须的重写touch事件。在其中根据手指的按下位置、滑动过程、拿起位置、滑动速度进行判断分析处理。
说起来比较绕,具体还是代码:
手指按下
1 2 3 4 5 6 7 8 9 |
switch (event.getAction()) { case MotionEvent.ACTION_DOWN: xDown = event.getRawX(); // 无论是否已经侧滑,这个得到的都是手指和本布局左边线的距离 paramsLeftMargin = (int) (xDown - contentParams.leftMargin); paramsRightMargin = (int) (contentParams.leftMargin + xDown); break; |
手指滑动
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 |
case MotionEvent.ACTION_MOVE: xMove = event.getRawX(); int distanceX = (int) (xMove - xDown); // 负数:向左滑,正数:向右滑 // 如果向左滑的 if (distanceX <= 0) { // 如果已经滑开 if (isOpen) { // 手指滑动过程中的位置减去和边线的距离就是边线的目标位置。滑动中保持手指和边线距离不变 contentParams.leftMargin = (int) (xMove - paramsLeftMargin); contentParams.rightMargin = (int) (xMove - paramsRightMargin); // 如果向左滑的太多 if (contentParams.leftMargin < 0) { contentParams.leftMargin = 0; contentParams.rightMargin = 0; } } else { contentParams.leftMargin = 0; contentParams.rightMargin = 0; } setLayoutParams(contentParams); } // 如果向右滑动 else if (distanceX > 0) { // 如果尚未滑开 if (!isOpen) { contentParams.leftMargin = distanceX; // 负数,绝对值即向右移动的距离 contentParams.rightMargin = -distanceX; // 如果移动太多 if (contentParams.leftMargin > contentWidth - 300) { contentParams.leftMargin = contentWidth - 300; contentParams.rightMargin = 2 * contentWidth - 300; } } else { contentParams.leftMargin = contentWidth - 300; contentParams.rightMargin = 2 * contentWidth - 300; } setLayoutParams(contentParams); } break; |
手指拿起
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 |
case MotionEvent.ACTION_UP: xUp = event.getRawX(); int upDistanceX = (int) (xUp - xDown); // 手指拿起后相对于按下时的距离。正数:向右,负数:向左 if (Math.abs(upDistanceX) >= touchSlop) { // 如果手指是向右滑动的,布局还没滑开 if (upDistanceX > 0 && !isOpen) { mVelocityTracker.computeCurrentVelocity(1000); // 计算1秒内速率 int velocity = Math.abs((int) mVelocityTracker.getXVelocity()); // x轴速度 // 如果滑动距离有效,或速度够快 if ( upDistanceX > 500 || velocity > SNAP_VELOCITY) { // 向右移动,速度30像素 //new ScrollTask().execute(30); // TODO scrollTo // 向右移动 contentParams.leftMargin = contentWidth - 300; contentParams.rightMargin = 2 * contentWidth - 300; setLayoutParams(contentParams); isOpen = true; } // 如果 else { // // 向左移动,速度30像素 // new ScrollTask().execute(-30); contentParams.leftMargin = 0; contentParams.rightMargin = 0; setLayoutParams(contentParams); } } else if (upDistanceX < 0 && isOpen) { mVelocityTracker.computeCurrentVelocity(1000); int velocity = Math.abs((int) mVelocityTracker.getXVelocity()); if (Math.abs(upDistanceX) > 500 || velocity > SNAP_VELOCITY) { // 向左移动,速度30像素 //new ScrollTask().execute(-30); contentParams.leftMargin = 0; contentParams.rightMargin = 0; setLayoutParams(contentParams); isOpen = false; } else { // // 向右移动,速度30像素 // new ScrollTask().execute(30); contentParams.leftMargin = contentWidth - 300; contentParams.rightMargin = 2 * contentWidth - 300; setLayoutParams(contentParams); } } } else if (Math.abs(upDistanceX) < touchSlop) { // 当手指按下向左滑又向右滑回来,不足以触发事件时 if(isOpen){ contentParams.leftMargin = contentWidth - 300; contentParams.rightMargin = 2 * contentWidth - 300; setLayoutParams(contentParams); } else { contentParams.leftMargin = 0; contentParams.rightMargin = 0; setLayoutParams(contentParams); } } // 重置速度追踪器 mVelocityTracker.recycle(); mVelocityTracker = null; break; |
提供项目包:注意为了上传方便android-support-v4.jar删除了,导入后记得替换。同时重写build project。
[download id="1672"]
本文由崔维友 威格灵 cuiweiyou vigiles cuiweiyou 原创,转载请注明出处:http://www.gaohaiyan.com/1667.html
承接App定制、企业web站点、办公系统软件 设计开发,外包项目,毕设