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:halfmanhuang@gmail.com
转载于:https://www.cnblogs.com/halfmanhuang/p/3834952.html
Android UI效果实现——Activity滑动退出效果相关推荐
- Android仿今日头条图片滑动退出效果
资源下载(2C币) 逛CSDN的时候,看到几篇写仿今日头条图片滑动退出效果的文章,闲着无聊便想着也给自己项目加上,实现的思路有很多种,本着就近原则选了一篇与自己思路相近的文章结合自己的实践总结一下. ...
- android 自定义 theme,Android使用Theme自定义Activity进入退出动画的方法
本文实例讲述了Android使用Theme自定义Activity进入退出动画的方法.分享给大家供大家参考,具体如下: 有没有觉得Activity的默认动画太快了或者太难看了.. 我原来使用Activi ...
- Android 动画之View动画效果和Activity切换动画效果
View动画效果: 1.>>Tween动画 通过对View的内容进行一系列的图形变换(平移.缩放.旋转.透明度变换)实现动画效果,补间动画需要使用<set>节点作为根节点,子节 ...
- android微信列表滑动删除,Android仿微信对话列表滑动删除效果
微信对话列表滑动删除效果很不错的,借鉴了github上SwipeListView(项目地址:https://github.com/likebamboo/SwipeListView),在其上进行了一些重 ...
- Axure制作手机UI原型之界面滑动滚动效果
用Axure制作手机界面原型的时候,往往会遇到像Android中listview那种页面,手指在界面上滑动,页面也就跟随滚动,拖拽到底部或者顶部的时候还有个回弹效果,如何在Axure之中模拟这种滚动呢 ...
- android qq弹出菜单,Android开发实现qqminihd 左右滑动菜单效果
类型:编程工具大小:13.8M语言:英文 评分:5.5 标签: 立即下载 观察qqminihd界面,发现其界面能够左右滑动来实现两侧菜单效果. 自定义Layout:ScrollLayout.java ...
- Android UI控件之Gallery(拖动效果) --拖动式图片浏览
我们知道现在智能手机上都有这样一种功能,就是你在浏览图片的时候.不是硬性的点击按钮 而是可以实现手指的拖动,划开效果.使用户具有更好的交互体验,不过这种效果是如何实现的呢? 在Android中是通过G ...
- Android UI 实现广告 Banner 轮播效果
编写acitivity_main.xml <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android ...
- android仿微信的activity平滑水平切换动画,Android实现简单底部导航栏 Android仿微信滑动切换效果...
Android实现简单底部导航栏 Android仿微信滑动切换效果 发布时间:2020-10-09 19:48:00 来源:脚本之家 阅读:96 作者:丶白泽 Android仿微信滑动切换最终实现效果 ...
最新文章
- Vue从Hello World到打包(后端适读)
- 模拟一个简单计算器_阅读模拟器的简单介绍
- 深入浅出 RecyclerView
- 《数据结构》知识点Day_03
- 我们来谈谈面向指针编程的那些事
- 我的 2021 年终总结
- 基于Prometheus和Grafana打造业务监控看板
- Ajax实现原理详解
- js中innerHTML和innerText jQuery中html()和text()的区别
- 目标检测第2步:如何在Windows 10下安装Anaconda?
- github 怎么搜索_实用!8个玩转GitHub的小插件,快来试试吧!
- android ui自动化 mock,移动端自动化多机并行测试-数据 mock 篇
- so运行出错:只包含了头文件,未同时编译cpp
- dubbo的线程模型、派发策略、线程池策略
- Face3D学习笔记(4)3DMM示例源码解析【中上】3DMM模型
- C语言中逻辑非和取反的不同
- 还原html默认打开方式,怎么还原打开方式,详细教您Win10系统下如何还原程序默认打开方式...
- python携程怎么做数据同步_python协程中同步如何使用?
- c++ vector 一部分_要去|原创TheShy要去SKT、小C会给阿水打辅助!各大战队面临重新洗牌...
- 软件编程c语言5级,全国青少年软件编程等级考试标准(c语言1级-10级)-20190927.pdf...
热门文章
- elasticsearch ik分词插件配置自定义分词词典
- Python Django 多表设计OneToOneField/ManyToManyField/ForeignKey
- MySQL基本架构图
- elasticsearch集群配置文件详述
- java 中IO流的概念
- 泛函分析3——线性空间和赋范线性空间总结
- vue+axios天气查询——天知道效果展示及源码分析
- pc端js获取当前经纬度_Swiper 免费开源、功能强大的触摸滑动 js 特效插件
- 2.4操作系统之死锁详解(预防、避免、检测、解除)+思维导图
- Linux / offsetof 和 container_of