《Android中使用Scroller实现非全屏宽度抽屉动画》中使用Scroller实现了一个侧滑动画效果。文中很多细节没说清楚同时有很多需求上的不足。
本例是一种使用Layout的属性对象实现的侧滑动画,仅实现根据手指滑动侧滑。
Aty的布局只有一个容器,其为一个自定义的RelativeLayout:
1 2 3 4 5 6 7 8 9 10 |
<!-- 这是个相对布局!后加入的元素默认会遮挡首先加入的元素 --> <com.cuiweiyou.scrollertest.view.ScrollerRelativeLyt xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/container" android:layout_width="match_parent" android:layout_height="match_parent" > </com.cuiweiyou.scrollertest.view.ScrollerRelativeLyt> |
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 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 |
/** * 本Aty的contentView布局中只有一个最外层RelativeLayout,并且是个自定义的RL类<br/> * 在自定义RL类中定义一个Scroller滚动器。使用滚动器对这个类的子内容进行滚动 * @author Administrator */ public class MainActivity extends Activity { /** 是否侧滑了 */ public boolean isScrolled; /** 顶层布局 */ private ScrollerRelativeLyt llcontainer; /** 屏幕宽度 */ public int screenWidth; /** Margin距离 */ public int marginDis; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); DisplayMetrics dm = new DisplayMetrics(); getWindowManager().getDefaultDisplay().getMetrics(dm); screenWidth = dm.widthPixels; marginDis = screenWidth - 300; // 注意这个是new出来的,首先使用这个设置bottom的位置 RelativeLayout.LayoutParams btmLtyParams = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT, RelativeLayout.LayoutParams.MATCH_PARENT); btmLtyParams.leftMargin = -marginDis; btmLtyParams.rightMargin = marginDis; RelativeLayout bottomView = (RelativeLayout) View.inflate(this, R.layout.view_bottom, null); bottomView.setLayoutParams(btmLtyParams); RelativeLayout topView = (RelativeLayout) View.inflate(this, R.layout.view_top, null); llcontainer = (ScrollerRelativeLyt) findViewById(R.id.container); llcontainer.addView(this, bottomView, topView); } public void doScroll(View v) { // 此boolean变量,当抽屉关闭时为false,抽屉打开时为true if (!isScrolled) { // 如果抽屉关着,那么执行抽屉动画 isScrolled = true; llcontainer.doScrollTo(-marginDis, 500); } else { // 如果抽屉开着,执行复位动画 isScrolled = false; llcontainer.doScrollTo(marginDis, 500); } } } |
2个子布局:
每个布局的按钮都设置了onClick属性,用于执行Aty里的doScroll(View v)方法进行侧滑动画。
自定义RL侧滑类
首先是全局的滚动器、手指按下位置等:
/** 滑动器 **/
private Scroller scroller;
/** 手指按下的屏幕位置 **/
private PointF downPoint;
/** 屏幕宽度 **/
private int screenWidth;
/** 容器aty **/
private MainActivity parent;
* 使用Scroller滚动器响应按钮事件
* 使用scrollTo方法响应手指滑动事件
* 注意:执行scroller.startScroll或scrollTo时,是本布局的子内容滚动,而不是本布局自身
然后是添加子内容的方法:
1 2 3 4 5 6 7 8 9 10 11 12 |
/** * 添加子布局 * @param btmV 底 * @param topV 顶 */ public void addView(Activity parentContainer, RelativeLayout btmV, RelativeLayout topV) { parent = (MainActivity)parentContainer; addView(btmV); addView(topV); } |
接着是滚动器调用方法及相关处理
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 |
/** * 自定义方法:平滑移动本布局<br/> * 用于按钮点击时执行滑动 * * @param dx x轴移动距离 * @param duration 时长 cuiweiyou.com */ public void doScrollTo(int dx, int duration) { // 开始滑动(x轴出发点,y轴出发点,x轴距离,y轴距离,时长) scroller.startScroll(getScrollX(), getScrollY(), dx, getScrollY(), duration); // 刷新布局 invalidate(); } /** * 滑动过程中持续调用此方法 cuiweiyou.com */ @Override public void computeScroll() { // 当滑动执行完毕 if (scroller.computeScrollOffset()) { int oldX = getScrollX(); // 本布局停止后的位置 int oldY = getScrollY(); int x = scroller.getCurrX(); // 获取Scroller停止后当前水平位置 int y = scroller.getCurrY(); if (oldX != x || oldY != y) { // 自身scrollTo的参数是偏移量!!! scrollTo(x, y); // 将View中内容滑动到相应的位置,参考的坐标系原点为parent View的左上角 } invalidate(); } } |
最终是Touch事件的处理
上面Scroller的使用都是为了响应按钮。这里才是手指触摸的处理。
因为scrollTo方法是本父容器对子内容的滚动,这个touch事件是被本父容器接收的,当top侧滑后,想要再随手指侧滑回来,应注意效果上看起来应该是按住top层滑回来。
手指按下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
/** * Touch滑动事件处理<br/> */ @Override public boolean onTouchEvent(MotionEvent ev) { // 当手指按下 if (ev.getAction() == MotionEvent.ACTION_DOWN) { downPoint = new PointF(ev.getRawX(), ev.getRawY()); // 如果已经侧滑了 if(parent.isScrolled){ // 手指没有按在top层上 if(downPoint.x < Math.abs(getScrollX())){ return false; } } } |
手指滑动
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 |
// 当手指滑动 else if (ev.getAction() == MotionEvent.ACTION_MOVE) { PointF movePoint = new PointF(ev.getRawX(), ev.getRawY()); float distanceX = movePoint.x - downPoint.x; // 方向向右 if(distanceX > 0){ // 尚未滑开 if(!parent.isScrolled){ scrollTo( - (int)distanceX, 0); if(getScrollX() < -parent.marginDis){ scrollTo(-parent.marginDis, 0); } } } // 如果向左 else if(distanceX < 0){ // 已经滑开 if(parent.isScrolled){ scrollTo( -parent.marginDis - (int)distanceX, 0); if(getScrollX() > 0){ scrollTo(0, 0); } } } invalidate(); } |
手指拿起
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 |
// 当手指拿起 else if (ev.getAction() == MotionEvent.ACTION_UP) { float upRawX = ev.getRawX(); float distanceX = upRawX - downPoint.x; // 方向向右 if(distanceX > 0){ // 尚未滑开 if(!parent.isScrolled){ // 手指滑动距离有效 if (distanceX >= 500 ) { scrollTo(-parent.marginDis, 0); parent.isScrolled = true; } else { scrollTo(0, 0); } } } // 如果向左 else if(distanceX < 0){ // 已经滑开 if(parent.isScrolled){ if(-distanceX >= 300 ){ // 一般左滑会比较懒 scrollTo(0, 0); parent.isScrolled = false; } else{ scrollTo(-parent.marginDis, 0); } } } invalidate(); } return true; } |
项目下载:注意为了上传方便android-support-v4.jar删除了,导入后记得替换。同时重写build project。
[download id="1679"]
本文由崔维友 威格灵 cuiweiyou vigiles cuiweiyou 原创,转载请注明出处:http://www.gaohaiyan.com/1677.html
承接App定制、企业web站点、办公系统软件 设计开发,外包项目,毕设