首页 > 代码库 > Android UI效果实现——Activity滑动退出效果

Android UI效果实现——Activity滑动退出效果

更新说明:

1、在QQ网友北京-旭的提醒下,在SlideFrame的initilize方法中添加了focusable、focusableInTouch、clickable的状态设置,否则会导致部分情况下无法滑动,感谢!

 

一、使用说明

使用方法很简单,只有一个类HorizontalActivity,继承自FragmentActivity类,实现了contentView的滑动事件触发和动画效果,要在自己的代码里实现,方法两种:

1、如果对Activity没特殊要求,直接继承HorizontalActivity即可

2、如果Activity的父类必须是某一特定类型的Activity子类,则可以仿照我的写法对该类进行继承

 

二、HorizontalActivity类的代码

  1 package com.beifeng.widget;  2   3 import android.content.Context;  4 import android.support.v4.app.FragmentActivity;  5 import android.util.AttributeSet;  6 import android.view.LayoutInflater;  7 import android.view.MotionEvent;  8 import android.view.View;  9 import android.view.ViewGroup.LayoutParams; 10 import android.view.animation.Animation; 11 import android.view.animation.Animation.AnimationListener; 12 import android.view.animation.DecelerateInterpolator; 13 import android.view.animation.Transformation; 14 import android.widget.FrameLayout; 15  16 /** 17  * HorizontalActivity:可滑动Activity 18  *  19  * 注意事项: 本Activity中与滑动方向相同的滑动操作会被拦截 20  *  21  * @author HalfmanG2 22  * @version 1.0.0 23  * @since JDK7 SDK19 24  */ 25 public class HorizontalActivity extends FragmentActivity { 26  27     /** 框架视图 */ 28     protected SlideFrame frameView; 29     /** 内容视图 */ 30     protected View contentView; 31  32     @Override 33     public void setContentView(int layoutResID) { 34         // 初始化frame 35         if (frameView == null) { 36             // 未初始化则初始化 37             frameView = new SlideFrame(this); 38         } else { 39             // 已经初始化则清空 40             frameView.removeAllViews(); 41         } 42         // 创造framelayout的填充参数 43         FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(-1, -1); 44         // 获取layoutResId对应的contentView视图并插入frameView 45         LayoutInflater inflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE); 46         contentView = inflater.inflate(layoutResID, null); 47         frameView.addView(contentView, params); 48         // 设置frameview为根视图 49         super.setContentView(frameView); 50     } 51  52     @Override 53     public void setContentView(View view) { 54         // 初始化frame 55         if (frameView == null) { 56             // 未初始化则初始化 57             frameView = new SlideFrame(this); 58         } else { 59             // 已经初始化则清空 60             frameView.removeAllViews(); 61         } 62         // 创造framelayout的填充参数 63         FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(-1, -1); 64         // 获取view为contentView视图并插入frameView 65         contentView = view; 66         frameView.addView(contentView, params); 67         // 设置frameview为根视图 68         super.setContentView(frameView); 69     } 70  71     @Override 72     public void setContentView(View view, LayoutParams params) { 73         // 初始化frame 74         if (frameView == null) { 75             // 未初始化则初始化 76             frameView = new SlideFrame(this); 77         } else { 78             // 已经初始化则清空 79             frameView.removeAllViews(); 80         } 81         // 创造framelayout的填充参数 82         FrameLayout.LayoutParams fp = new FrameLayout.LayoutParams(-1, -1); 83         // 获取view为contentView视图并插入frameView 84         contentView = view; 85         frameView.addView(contentView, fp); 86         // 设置frameview为根视图 87         super.setContentView(frameView, params); 88     } 89  90     /** 91      * 推出页面 92      */ 93     protected void onSlideFinish() { 94         finish(); 95     } 96  97     /** 98      * 位移内容视图到 99      * 100      * @param position101      *            目标位置102      */103     public void slideTo(int position) {104         if (android.os.Build.VERSION.SDK_INT > 10) {105             contentView.setX(position);106         } else {107             android.widget.FrameLayout.LayoutParams params = (android.widget.FrameLayout.LayoutParams) contentView108                     .getLayoutParams();109             params.setMargins(position, 0, -position, 0);110             contentView.setLayoutParams(params);111         }112     }113 114     /**115      * 获得当前容器位移116      * 117      * @return 当前容器位移118      */119     public int getSlide() {120         if (android.os.Build.VERSION.SDK_INT > 10) {121             return (int) contentView.getX();122         } else {123             return ((android.widget.FrameLayout.LayoutParams) contentView124                     .getLayoutParams()).leftMargin;125         }126     }127 128     /**129      * 滑动框架130      * 131      * @author HalfmanG2132      * @version 1.0.0133      * @since JDK7 SDK19134      */135     public class SlideFrame extends FrameLayout {136         /** 默认滑动阀值 */137         private final static int DEFAULT_SLIDE_DUMPING = 8;138         /** 默认状态改变阀值 */139         private final static int DEFAULT_DO_DUMPING = 100;140         /** 滑动起始位置与当前位置 */141         private int startX, currentX, startY, currentY;142         /** 是否拦截事件,是否已经完成滑动检查 */143         private boolean doNotIntercept, hasChecked;144         /** 滑动阀值 */145         private int slideDumping;146         /** 操作阀值 */147         private int doDumping;148         /** 滑屏动画 */149         protected SlideAnimation slideAnimation;150 151         @Override152         public boolean onInterceptTouchEvent(MotionEvent ev) {153             super.onInterceptTouchEvent(ev);154             // 若当前处在侧滑状态中,则拦截信号155             if ((!doNotIntercept) && hasChecked) {156                 return true;157             }158             // 否则使用默认159             return false;160         }161 162         @Override163         public boolean dispatchTouchEvent(MotionEvent ev) {164             if (ev.getAction() == MotionEvent.ACTION_DOWN) {165                 // 获得起始滑动坐标166                 startX = (int) ev.getX();167                 startY = (int) ev.getY();168                 // 初始化状态169                 doNotIntercept = false;170                 hasChecked = false;171             } else if (!doNotIntercept) {172                 // 获得当前滑动坐标173                 currentX = (int) ev.getX();174                 currentY = (int) ev.getY();175                 // 根据滑动类型区分176                 switch (ev.getAction()) {177                 case MotionEvent.ACTION_MOVE: // 移动状态178                     if (hasChecked) {179                         doSlide();180                     } else {181                         doCheck();182                     }183                     break;184                 case MotionEvent.ACTION_CANCEL: // 取消状态185                 case MotionEvent.ACTION_UP: // 抬起状态186                     // 初始化状态187                     doNotIntercept = false;188                     hasChecked = false;189                     if (Math.abs(currentX - startX) > doDumping) {190                         if (currentX > startX) {191                             // 右滑192                             slideAnimation = new SlideAnimation(getSlide(),193                                     contentView.getWidth(), 0);194                             slideAnimation195                                     .setAnimationListener(new AnimationListener() {196                                         @Override197                                         public void onAnimationStart(198                                                 Animation animation) {199                                         }200 201                                         @Override202                                         public void onAnimationRepeat(203                                                 Animation animation) {204                                         }205 206                                         @Override207                                         public void onAnimationEnd(208                                                 Animation animation) {209                                             onSlideFinish();210                                         }211                                     });212                             startAnimation(slideAnimation);213                         }214                     } else {215                         // 返回0位置216                         slideAnimation = new SlideAnimation(getSlide(), 0, 0);217                         startAnimation(slideAnimation);218                     }219                     break;220                 default:221                     break;222                 }223             }224             return super.dispatchTouchEvent(ev);225         }226 227         /**228          * 检查是否超过滑动阀值开启滑动状态229          */230         private void doCheck() {231             if (Math.abs(startY - currentY) > slideDumping) {232                 hasChecked = true;233                 doNotIntercept = true;234                 slideTo(0);235             } else if (currentX - startX > slideDumping) {236                 hasChecked = true;237                 doNotIntercept = false;238             }239         }240 241         /**242          * 进行滑动243          */244         private void doSlide() {245             if (currentX > startX) {246                 slideTo(currentX - startX);247             } else {248                 slideTo(0);249             }250         }251 252         /**253          * 设置滑动阀值254          * 255          * @param dpValue256          */257         public void setSlideDumping(int dpValue) {258             slideDumping = dip2px(dpValue);259         }260 261         /**262          * 设置状态改变阀值263          * 264          * @param dpValue265          */266         public void setDoDumping(int dpValue) {267             doDumping = dip2px(dpValue);268         }269 270         /**271          * 二级构造方法272          */273         private void initilize() {274             setSlideDumping(DEFAULT_SLIDE_DUMPING);275             setDoDumping(DEFAULT_DO_DUMPING);276             doNotIntercept = false;277             hasChecked = false;278             setClickable(true);279             setFocusable(true);280             setFocusableInTouchMode(true);281         }282 283         /**284          * 构造方法285          * 286          * @param context287          * @param attrs288          * @param defStyle289          */290         public SlideFrame(Context context, AttributeSet attrs, int defStyle) {291             super(context, attrs, defStyle);292             initilize();293         }294 295         /**296          * 构造方法297          * 298          * @param context299          * @param attrs300          */301         public SlideFrame(Context context, AttributeSet attrs) {302             super(context, attrs);303             initilize();304         }305 306         /**307          * 构造方法308          * 309          * @param context310          */311         public SlideFrame(Context context) {312             super(context);313             initilize();314         }315 316         /**317          * 讲dip值转换为px值,像素密度距离转像素距离318          * 319          * @param dipValue dp值320          * @return px值321          */322         private int dip2px(float dipValue) {323             // 获得像素密度324             final float scale = getContext().getResources().getDisplayMetrics().density;325             // 四舍五入dp值乘像素密度326             return (int) (dipValue * scale + 0.5f);327         }328     }329 330     /**331      * 滑动动画类332      * 333      * @author HalfmanG2334      */335     public class SlideAnimation extends Animation {336         /** 起始位置,目标位置 */337         private float from, to;338         /**339          * 构造方法340          * @param from 起始位置341          * @param to 目标位置342          * @param startOffset 起始延迟343          */344         public SlideAnimation(int from, int to, int startOffset) {345             this.from = from;346             this.to = to;347             setFillEnabled(false);348             setDuration(200);349             setRepeatCount(0);350             setStartOffset(startOffset);351             setInterpolator(new DecelerateInterpolator());352         }353         @Override354         protected void applyTransformation(float interpolatedTime,355                 Transformation t) {356             float current = from + (to - from) * interpolatedTime;357             slideTo((int) current);358             super.applyTransformation(interpolatedTime, t);359         }360     }361 }

 

三、使用详细步骤

1、建立一个Android工程,项目最小api level必须在api level 11及以上

2、把本类考入任意代码包下

3、项目中想要实现Activity滑动退出效果的Activity继承本类

4、如果要在滑动过程中显示上一个Activity的话,将Activity的背景设置为透明,方法建议通过设置Activity的Style或者说theme来实现

5、如果滑动过程中需要加入一些特殊效果,可以复写slideTo(int)方法,记得别把super.slideTo(int)给漏了,否则滑动失效

6、如果滑动结束后不希望立即返回上一页,可以复写onSlideFinish()方法

 

四、某项目中使用的效果展示

 

PS、

很简单的实现方法,但离我觉得完美还太远,所以如果有更好的实现方法希望可以一起交流下:

联系方式QQ:811868948,备注加上Android交流,有好的想法一定要联系我,谢谢!

联系方式E-Mail:halfmanhuang@gmail.com