安卓-Android实现右侧划出划入activity

2023-10-19 09:38

本文主要是介绍安卓-Android实现右侧划出划入activity,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

原帖: link

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:可滑动Activity18  * 19  * 注意事项: 本Activity中与滑动方向相同的滑动操作会被拦截20  * 21  * @author HalfmanG222  * @version 1.0.023  * @since JDK7 SDK1924  */25 public class HorizontalActivity extends FragmentActivity {26 27     /** 框架视图 */28     protected SlideFrame frameView;29     /** 内容视图 */30     protected View contentView;31 32     @Override33     public void setContentView(int layoutResID) {34         // 初始化frame35         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视图并插入frameView45         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     @Override53     public void setContentView(View view) {54         // 初始化frame55         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视图并插入frameView65         contentView = view;66         frameView.addView(contentView, params);67         // 设置frameview为根视图68         super.setContentView(frameView);69     }70 71     @Override72     public void setContentView(View view, LayoutParams params) {73         // 初始化frame74         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视图并插入frameView84         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:halfmanhuang@gmail.com

分类: Android, Framework
标签: activity滑动效果, 滑动, 触屏事件, android, 交互效果, 滑动退出, activity复写, 自定义动画
<div id="blog_post_info">
好文要顶 关注我 收藏该文
HalfmanG2
关注 - 6
粉丝 - 4
+加关注
0
0
<div class="clear"></div>
<div id="post_next_prev"><br>
<a href="https://www.cnblogs.com/halfmanhuang/p/3837261.html" class="p_n_p_prefix">» </a> 下一篇:    <a href="https://www.cnblogs.com/halfmanhuang/p/3837261.html" title="发布于 2014-07-11 11:00">Android UI效果实现——滑动模糊渐变效果实现</a>
posted on 2014-07-10 05:55  HalfmanG2  阅读( 3589)  评论( 2)  编辑  收藏

这篇关于安卓-Android实现右侧划出划入activity的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/238959

相关文章

hdu1043(八数码问题,广搜 + hash(实现状态压缩) )

利用康拓展开将一个排列映射成一个自然数,然后就变成了普通的广搜题。 #include<iostream>#include<algorithm>#include<string>#include<stack>#include<queue>#include<map>#include<stdio.h>#include<stdlib.h>#include<ctype.h>#inclu

【C++】_list常用方法解析及模拟实现

相信自己的力量,只要对自己始终保持信心,尽自己最大努力去完成任何事,就算事情最终结果是失败了,努力了也不留遗憾。💓💓💓 目录   ✨说在前面 🍋知识点一:什么是list? •🌰1.list的定义 •🌰2.list的基本特性 •🌰3.常用接口介绍 🍋知识点二:list常用接口 •🌰1.默认成员函数 🔥构造函数(⭐) 🔥析构函数 •🌰2.list对象

【Prometheus】PromQL向量匹配实现不同标签的向量数据进行运算

✨✨ 欢迎大家来到景天科技苑✨✨ 🎈🎈 养成好习惯,先赞后看哦~🎈🎈 🏆 作者简介:景天科技苑 🏆《头衔》:大厂架构师,华为云开发者社区专家博主,阿里云开发者社区专家博主,CSDN全栈领域优质创作者,掘金优秀博主,51CTO博客专家等。 🏆《博客》:Python全栈,前后端开发,小程序开发,人工智能,js逆向,App逆向,网络系统安全,数据分析,Django,fastapi

让树莓派智能语音助手实现定时提醒功能

最初的时候是想直接在rasa 的chatbot上实现,因为rasa本身是带有remindschedule模块的。不过经过一番折腾后,忽然发现,chatbot上实现的定时,语音助手不一定会有响应。因为,我目前语音助手的代码设置了长时间无应答会结束对话,这样一来,chatbot定时提醒的触发就不会被语音助手获悉。那怎么让语音助手也具有定时提醒功能呢? 我最后选择的方法是用threading.Time

Android实现任意版本设置默认的锁屏壁纸和桌面壁纸(两张壁纸可不一致)

客户有些需求需要设置默认壁纸和锁屏壁纸  在默认情况下 这两个壁纸是相同的  如果需要默认的锁屏壁纸和桌面壁纸不一样 需要额外修改 Android13实现 替换默认桌面壁纸: 将图片文件替换frameworks/base/core/res/res/drawable-nodpi/default_wallpaper.*  (注意不能是bmp格式) 替换默认锁屏壁纸: 将图片资源放入vendo

安卓链接正常显示,ios#符被转义%23导致链接访问404

原因分析: url中含有特殊字符 中文未编码 都有可能导致URL转换失败,所以需要对url编码处理  如下: guard let allowUrl = webUrl.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed) else {return} 后面发现当url中有#号时,会被误伤转义为%23,导致链接无法访问

C#实战|大乐透选号器[6]:实现实时显示已选择的红蓝球数量

哈喽,你好啊,我是雷工。 关于大乐透选号器在前面已经记录了5篇笔记,这是第6篇; 接下来实现实时显示当前选中红球数量,蓝球数量; 以下为练习笔记。 01 效果演示 当选择和取消选择红球或蓝球时,在对应的位置显示实时已选择的红球、蓝球的数量; 02 标签名称 分别设置Label标签名称为:lblRedCount、lblBlueCount

Android平台播放RTSP流的几种方案探究(VLC VS ExoPlayer VS SmartPlayer)

技术背景 好多开发者需要遴选Android平台RTSP直播播放器的时候,不知道如何选的好,本文针对常用的方案,做个大概的说明: 1. 使用VLC for Android VLC Media Player(VLC多媒体播放器),最初命名为VideoLAN客户端,是VideoLAN品牌产品,是VideoLAN计划的多媒体播放器。它支持众多音频与视频解码器及文件格式,并支持DVD影音光盘,VCD影

Kubernetes PodSecurityPolicy:PSP能实现的5种主要安全策略

Kubernetes PodSecurityPolicy:PSP能实现的5种主要安全策略 1. 特权模式限制2. 宿主机资源隔离3. 用户和组管理4. 权限提升控制5. SELinux配置 💖The Begin💖点点关注,收藏不迷路💖 Kubernetes的PodSecurityPolicy(PSP)是一个关键的安全特性,它在Pod创建之前实施安全策略,确保P

工厂ERP管理系统实现源码(JAVA)

工厂进销存管理系统是一个集采购管理、仓库管理、生产管理和销售管理于一体的综合解决方案。该系统旨在帮助企业优化流程、提高效率、降低成本,并实时掌握各环节的运营状况。 在采购管理方面,系统能够处理采购订单、供应商管理和采购入库等流程,确保采购过程的透明和高效。仓库管理方面,实现库存的精准管理,包括入库、出库、盘点等操作,确保库存数据的准确性和实时性。 生产管理模块则涵盖了生产计划制定、物料需求计划、