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 position
101      *            目标位置
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) contentView
108                     .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) contentView
124                     .getLayoutParams()).leftMargin;
125         }
126     }
127
128     /**
129      * 滑动框架
130      *
131      * @author HalfmanG2
132      * @version 1.0.0
133      * @since JDK7 SDK19
134      */
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         @Override
152         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         @Override
163         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                             slideAnimation
195                                     .setAnimationListener(new AnimationListener() {
196                                         @Override
197                                         public void onAnimationStart(
198                                                 Animation animation) {
199                                         }
200
201                                         @Override
202                                         public void onAnimationRepeat(
203                                                 Animation animation) {
204                                         }
205
206                                         @Override
207                                         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 dpValue
256          */
257         public void setSlideDumping(int dpValue) {
258             slideDumping = dip2px(dpValue);
259         }
260
261         /**
262          * 设置状态改变阀值
263          *
264          * @param dpValue
265          */
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 context
287          * @param attrs
288          * @param defStyle
289          */
290         public SlideFrame(Context context, AttributeSet attrs, int defStyle) {
291             super(context, attrs, defStyle);
292             initilize();
293         }
294
295         /**
296          * 构造方法
297          *
298          * @param context
299          * @param attrs
300          */
301         public SlideFrame(Context context, AttributeSet attrs) {
302             super(context, attrs);
303             initilize();
304         }
305
306         /**
307          * 构造方法
308          *
309          * @param context
310          */
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 HalfmanG2
334      */
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         @Override
354         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:[email protected]

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

时间: 2024-10-12 13:21:16

Android UI效果实现——Activity滑动退出效果的相关文章

【Android UI】案例03滑动切换效果的实现(ViewPager)

本例使用ViewPager实现滑动切换的效果.本例涉及的ViewPager,为android.support.v4.view.ViewPager.所以需要在android项目中导入android-support-v4.jar. 本例中ViewPager是实现滑动效果的核心部分.对其设置PageChangeListener监听事件,是实现滑动效果的核心思路. [转载使用,请注明出处:http://blog.csdn.net/mahoking] 首先是主界面layout.xml文件,activity

Android UI - 实现广告Banner轮播效果

Android UI - 实现广告Banner轮播效果 前言 本篇博客要分享的一个效果是实现广告Banner轮播效果,这个效果也比较常见,一些视频类应用就经常有,就拿360影视大全来举例吧: 用红框框住的那个效果就是小巫今天要分享的,先来思考一下会用到什么控件?有什么用户体验? 控件我们可能一下子就可以想到的自然是ViewPager,没错!用到的就是ViewPager,那么它会有什么用户体验呢,它可能有以下几个体验: 1. 间隔不停的切换图片,指示器也跟着变 2. 点击图片可以跳转到指定的页面

android 使用viewflipper实现左右滑动的效果

public class MainActivity extends Activity implements OnGestureListener { private static final String TAG = "MainActivity"; private ViewFlipper viewFlipper; private GestureDetector detector; //手势检测 Animation leftInAnimation; Animation leftOutAni

Android 编程下实现 Activity 的透明效果

实现方式一(使用系统透明样式) 通过配置 Activity 的样式来实现,在 AndroidManifest.xml 找到要实现透明效果的 Activity,在 Activity 的配置中添加如下的代码设置该 Activity 为透明样式,但这种实现方式只能实现纯透明的样式,无法调整透明度,所以这种实现方式有一定的局限性,但这种方式实现简单. android:theme="@android:style/Theme.Translucent" <activity android:na

进阶三之Android UI介面之(滑动效果之Gallery + GridView)

人一生下就会哭,笑是后来才学会的.所以忧伤是一种低级的本能,而快乐是一种更高级的能力. 本讲内容:滑动效果之Gallery + GridView Android系统自带一个GridView和Gallery两个控件,GridView网格显示,Gallery单个浏览,两者结合起来可以真正实现Gallery浏览图片效果. 示例效果图         下面是res/layout/activity_main.xml 布局文件: <?xml version="1.0" encoding=&q

ANDROID模拟火花粒子的滑动喷射效果

转载请注明本文出自大苞米的博客(http://blog.csdn.net/a396901990),谢谢支持! 开篇废话: 年前换了一个手机,SONY的Z3C.这个手机在解锁屏幕时有一个滑动动画,类似火花的粒子喷射,效果很炫... 于是尝试着模拟了一下,完成后效果如下图(还有很多细节没有实现):    SurfaceView: 因为surfaceview是使用的双缓冲机制,所以很适合绘制这种需要不停变换的画面. 下面我从网上copy了几条关于SurfaceView的一些特性(已经表明了出处),因为

进阶七之Android UI介面之(滑动倒影效果)

只有你学会把自己已有的成绩都归零,才能腾出空间去接纳更多的新东西,如此才能使自己不断的超越自己. 本讲内容:介面滑动倒影效果 一.倒影原理: 倒影效果是主要由原图+间距+倒影三部分组成,高度大约为原图的3/2(原图为1.倒影为1/2) 原图,就是我们看到了最开始的图片 间距,是原图与倒影之间的间隙,如:reflectionGap = 4; 倒影,是原图下半部分1/2高度,通过矩阵变换matrix.preScale(1, -1); 获取倒立图片,然后再加上线性遮罩和阴影实现 示例一效果图:    

Android 设定activity的进入和退出效果

看了android的源代码和资源文件,终于明白如何去修改设置Dialog和Activity的进入和退出效果了.设置Dialog首先通过 getWindow()方法获取它的窗口,然后通过getAttributes()方法获得window的 WindowManager.LayoutParams lp, lp有个公共属性windowAnimations, 只要把要实现的animation的id赋值给它就可以了.问题是这个animation应该怎么写呢,研究发现,窗口进入和退出的效果分别是通过 @and

Android UI效果实现——滑动模糊渐变效果实现

前言: 大家应该都看到过iOS7解锁屏幕的滑动模糊渐变效果,好了,现在可以把手纸收起来了,今天黄老师就给大家讲一下如何在Android平台上 实现类似的滑动模糊渐变效果,其实方式远比你想像的简单. 目标效果展示: 第一部分:几个前提 说到模糊效果,我们先要了解几个前提 1.原图,指需要被模糊的一张位图 2.模糊,通常是采用指将一个位图的每个像素RGB值都取周围像素的RGB值的平均值,这样就可以产生模糊效果,一般通过高斯函数来实现, 至于Java中的实现方式黄老师就不给大家细讲了,我也不是搞图形算