安卓Activity上滑关闭效果实现

最近在做一个屏保功能,需要支持如图的上滑关闭功能。

因为屏保是可以左右滑动切换的,内部是一个viewpager

做这个效果的时候,关键就是要注意外层拦截触摸事件时,需要有条件的拦截,不能影响到内部viewpager的滑动处理。

以下是封装好的自定义view,继承自FrameLayout:

import android.animation.Animator;
import android.animation.ObjectAnimator;
import android.content.Context;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.VelocityTracker;
import android.view.View;
import android.view.ViewConfiguration;
import android.view.animation.Animation;
import android.view.animation.TranslateAnimation;
import android.widget.FrameLayout;import androidx.annotation.NonNull;public class SlideCloseFrameLayout extends FrameLayout {/*** 滑动监听器*/public interface OnSlideCloseListener {/*** 滑动开始时调用*/void onStartSlide();/*** 滑动结束&动画结束时调用,isClose为true表示滑动关闭,为false表示滑动恢复原位* @param isClose*/void onStopSlide(boolean isClose);}private OnSlideCloseListener onSlideCloseListener;private static final String TAG = "SlideCloseFrameLayout";private float downY = 0; // 记录手指按下时的Y坐标private boolean isSlideAction = false; // 标记是否为滑动关闭动作private VelocityTracker velocityTracker = null; // 速度跟踪器private float lastTranslationY = 0; // 记录上一次的TranslationY值,用于滑动时的位置更新public SlideCloseFrameLayout(Context context) {super(context);}public SlideCloseFrameLayout(Context context, AttributeSet attrs) {super(context, attrs);}public SlideCloseFrameLayout(Context context, AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);}@Overridepublic boolean onInterceptTouchEvent(MotionEvent event) {try {int action = event.getAction();switch (action) {case MotionEvent.ACTION_DOWN:downY = event.getRawY();if (downY > getHeight() - getHeight() / 5f) {initVelocityTracker();velocityTracker.addMovement(event);return false; // 拦截事件}break;case MotionEvent.ACTION_MOVE:velocityTracker.addMovement(event);velocityTracker.computeCurrentVelocity(1000);float xVelocity = velocityTracker.getXVelocity();float yVelocity = velocityTracker.getYVelocity();if (Math.abs(yVelocity) > ViewConfiguration.get(getContext()).getScaledMinimumFlingVelocity()&& Math.abs(yVelocity) > Math.abs(xVelocity)) {// 如果超过最小判定距离,并且Y轴速度大于X轴速度,才视为纵向滑动if (yVelocity < 0) {// 向下滑动if (onSlideCloseListener != null) {onSlideCloseListener.onStartSlide();}isSlideAction = true;return true;}}break;case MotionEvent.ACTION_UP:case MotionEvent.ACTION_CANCEL:isSlideAction = false;break;}} catch (Exception e) {e.printStackTrace();}return super.onInterceptTouchEvent(event);}@Overridepublic boolean onTouchEvent(MotionEvent event) {try {if (isSlideAction) {velocityTracker.addMovement(event);int action = event.getAction();switch (action) {case MotionEvent.ACTION_MOVE:float moveDistance = event.getRawY() - downY;if (moveDistance < 0) { // 仅当向上滑动时处理lastTranslationY = moveDistance;this.setTranslationY(moveDistance);}break;case MotionEvent.ACTION_UP:case MotionEvent.ACTION_CANCEL:velocityTracker.computeCurrentVelocity(1000);float velocityY = velocityTracker.getYVelocity();if (Math.abs(velocityY) > 1000 || Math.abs(lastTranslationY) > getHeight() / 5f) {slideUpAndExit();} else {slideBack();}releaseVelocityTracker();isSlideAction = false;break;}return true;}} catch (Exception e) {e.printStackTrace();}return super.onTouchEvent(event);}public boolean isSlideAction() {return isSlideAction;}public OnSlideCloseListener getOnSlideCloseListener() {return onSlideCloseListener;}public void setOnSlideCloseListener(OnSlideCloseListener onSlideCloseListener) {this.onSlideCloseListener = onSlideCloseListener;}private void initVelocityTracker() {if (velocityTracker == null) {velocityTracker = VelocityTracker.obtain();} else {velocityTracker.clear();}}private void releaseVelocityTracker() {if (velocityTracker != null) {velocityTracker.recycle();velocityTracker = null;}}private void slideUpAndExit() {// 执行上移退出动画TranslateAnimation exitAnimation = new TranslateAnimation(0, 0, getTranslationY(), -getHeight());exitAnimation.setDuration(300);exitAnimation.setFillAfter(false);exitAnimation.setAnimationListener(new Animation.AnimationListener() {@Overridepublic void onAnimationStart(Animation animation) {}@Overridepublic void onAnimationEnd(Animation animation) {// 动画结束后的操作setVisibility(View.GONE); // 隐藏或其他逻辑if (onSlideCloseListener != null) {onSlideCloseListener.onStopSlide(true);}}@Overridepublic void onAnimationRepeat(Animation animation) {}});startAnimation(exitAnimation);this.setTranslationY(0); // 重置TranslationY值}private void slideBack() {// 使用属性动画使视图回到原位ObjectAnimator animator = ObjectAnimator.ofFloat(this, "translationY", getTranslationY(), 0);animator.setDuration(300);animator.start();animator.addListener(new Animator.AnimatorListener(){@Overridepublic void onAnimationStart(@NonNull Animator animation) {}@Overridepublic void onAnimationEnd(@NonNull Animator animation) {if (onSlideCloseListener != null) {onSlideCloseListener.onStopSlide(false);}}@Overridepublic void onAnimationCancel(@NonNull Animator animation) {if (onSlideCloseListener != null) {onSlideCloseListener.onStopSlide(false);}}@Overridepublic void onAnimationRepeat(@NonNull Animator animation) {}});}
}

Activity使用时,只需要把根View设置为这个自定义view,然后透明主题,透明背景,同时关闭Activity的进入退出动画,便可以实现如图效果了。

嵌套使用时,不会影响到内部的Viewpager或其他可滑动view

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/573935.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

LLLM并发加速部署方案(llama.cpp、vllm、lightLLM、fastLLM)

大模型并发加速部署 解析当前应用较广的几种并发加速部署方案&#xff01; llama.cpp vllm lightLLM fastLLM

docker 的网络管理

docker应用自带了三种类型的网络&#xff0c;然后我们自己也能自定义网络 roottest-virtual-machine:~# docker network ls NETWORK ID NAME DRIVER SCOPE 4c3e28760cff bridge bridge local afd1493dc119 host host local 5f200e2eaf22 n…

【学习】软件测试行业有哪些从业方向

从事任何一个行业&#xff0c;不论想入行的新人还是已经在职的从业人员&#xff0c;一定要系统化的掌握自身的学习路线和发展方向&#xff0c;随时对自身的优劣点掌握清楚。尤其是对于软件测试这个岗位。测试职业所涉及的技能范围比较广&#xff0c;测试流程、测试计划、缺陷管…

C是用什么语言写出来的?

C是用什么语言写出来的? C语言的起源和发展是一个迭代过程&#xff1a; 1. 最初的C语言编译器的开发始于对B语言的改进。B语言是由Ken Thompson设计的&#xff0c;它是基于BCPL语言简化而来的。在开始前我有一些资料&#xff0c;是我根据网友给的问题精心整理了一份「 C语言的…

jmeter常用的函数

20211025白板 课前内容&#xff1a; 参数&#xff1a; 用户定义变量&#xff1a;它是一个全局变量&#xff0c;在启动运行时&#xff0c;获取一次值&#xff0c;在运行过程中&#xff0c;不会动态获取值。 用户定义变量&#xff0c;在启动时获取一次值&#xff0c;在运行过程中…

课堂练习——4、实验环境练习

任务描述 本关任务&#xff1a;修改 Linux 0.11 内核程序&#xff0c;将系统启动时显示的字符串由原来的Partition table ok.变为Hello, world!。 通过本关任务&#xff0c;可以熟悉 Linux 0.11 内核实验环境&#xff0c;掌握内核程序的编辑、编译和测试方法。 相关知识 为了…

SCP收容物006~010

注 &#xff1a;此文接SCP简介以及001~005的介绍,本文只供开玩笑 ,与 steve_gqq_MC 合作 --------------------------------------------------------------------------------------------------------------------------------- 目录 scp-006 scp-007 scp-008 scp-010 …

【Hive】HIVE运行卡死没反应

Hive运行卡死 再次强调 hive&#xff1a;小兄弟&#xff0c;没想到吧&#xff0c;咱可不是随便的人。&#x1f604; 那么&#xff0c;这次又遇见了hadoop问题&#xff0c;问题描述是这样的。 hive> insert into test values(1, nucty, 男); Query ID atguigu_202403241754…

StringRedisTemplate与RedisTemplate详解【序列化的方式不同】

spring 封装了 RedisTemplate 对象来进行对redis的各种操作&#xff0c;它支持所有的 redis 原生的 api。在RedisTemplate中提供了几个常用的接口方法的使用&#xff0c;分别是: private ValueOperations<K, V> valueOps; private HashOperations<K, V> hashOps; …

设计模式之原型模式讲解

原型模式本身就是一种很简单的模式&#xff0c;在Java当中&#xff0c;由于内置了Cloneable 接口&#xff0c;就使得原型模式在Java中的实现变得非常简单。UML图如下&#xff1a; 我们来举一个生成新员工的例子来帮助大家理解。 import java.util.Date; public class Employee…

【科研基础】VAE: Auto-encoding Variational Bayes

[1]Kingma, Diederik P., and Max Welling. “Auto-encoding variational bayes.” arXiv preprint arXiv:1312.6114 (2013). [2] [论文简析]VAE: Auto-encoding Variational Bayes[1312.6114] [3] The Reparameterization Trick [4] 变分法的基本原理是什么? 文章目录 1-…

SMMU学习这一篇就够了

快速链接: 【精选】ARMv8/ARMv9架构入门到精通-[目录] &#x1f448;&#x1f448;&#x1f448; 引流关键词: SMMU&#xff0c;mmu500,mmu600,mmu700,system mmu,Non-cacheable,Cacheable, non-shareable,inner-shareable,outer-shareable, optee、ATF、TF-A、Trustzone、opte…