[Android]通过ViewDragHelper实现滑动关闭Activity

Android-DragDismissActivity:平滑,易于实现的拖动以关闭Android Activity Android Drag Dismiss活动 拖动到关闭Activity模式的另一种实现。 这一灵感来自尼克·布彻(Nick Butcher)的。 该项目具有简单的API,并且是该模式的非常强大且美观的实现。 我的某些应用程序( 和 )中都使用了该库。 它是从Jacob Klinker和我的库中抽象出来的,这是一个很棒的可读性风格的应用内网络浏览器。 该库提供一个弹性的布局,可以关闭一个Activity与RecyclerView或常规Activity 。 每当用户从内容的底部或顶部向上或向下滑动时, DragDismissActivity都会完成。 将其包含在您的项目中 该项目旨在在您现 立即下载

首先来看ViewDragHelper的构造方法:

create(ViewGroup forParent, float sensitivity, ViewDragHelper.Callback cb)

需要三个参数:

  • 第一个 ViewGroup 是承载可以被拖动的控件的
  • 第二个是灵敏度
  • 第三个是拖动回调。我们需要实现拖动效果,主要就是依靠重写回调方法实现

ViewDragHelper.Callback 中 boolean tryCaptureView(View child, int pointerId) 需要实现,表明 child 是否可以被拖动,可以返回 true

对于需要实现滑动返回效果来说,还有余下方法需要实现:

int clampViewPositionHorizontal(View child, int left, int dx)
表明 child 横向上可以拖动的范围,与之对应的是 clampViewPositionVertical(View child, int top, int dy)。第二个参数表示 child view 尝试的移动到位置,返回值为实际应该在的位置。

void onViewReleased(View releasedChild, float xvel, float yvel)
在用户拖拽完成、放手的时候会被调用,需要在这个方法中判断是否拖动大于屏幕距离的一半,大于就执行 返回逻辑 ,否则反之。

void onEdgeDragStarted(int edgeFlags, int pointerId)
在用户从边缘发起拖动时会触发,因为我的目的是只有从边界处拖动才能触发效果,所以需要实现。

之后就是设置 ViewDragHelper 监视边缘拖拽,并且将事件拦截和事件处理交由 ViewDragHelper 即可。这里要注意Layout中只能包含一个直接子控件,其他子控件包裹在该子控件布局中。
当然还可以添加一些美化效果。

实现了ViewDragHelper的自定义布局View代码如下:

public class SwipeBackLayout extends FrameLayout {

    private ViewDragHelper mViewDragHelper;
    private View mContentView;
    private int mContentWidth;
    private int mMoveLeft;
    private boolean isClose = false;
    private boolean isEdgeDrag = false;
    private CallBack mCallBack;//自定义内部的回调函数,下面写
    private Drawable mShadowLeft;
    private static final int FULL_ALPHA = 255;
    private static final int DEFAULT_SCRIM_COLOR = 0x99000000;
    private int mScrimColor = DEFAULT_SCRIM_COLOR;
    private float mScrimOpacity;//滑动剩余边界的百分比,设置透明帷幕Alpha百分比用
    private float mScrollPercent;//滑动宽度的百分比
    private Rect mTmpRect = new Rect();

    //自定义控件 必备俩个构造函数
    public SwipeBackLayout(Context context) {
        this(context, null);//引用俩个参数的构造方法,目的是将三个构造方法连接起来.
    }

    public SwipeBackLayout(Context context, AttributeSet attrs) {
        this(context, attrs, 0); //引用三个参数的构造方法
    }

    public SwipeBackLayout(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init();//写个初始化方法,等下在里面实现 viewDragHelper,已经一些初始化操作
    }

    //初始化方法
    private void init() {

        //ViewDragHelper
        mViewDragHelper = ViewDragHelper.create(this, 1.0f, new ViewDragHelper.Callback() {
            //记录值的变化
            @Override
            public void onViewPositionChanged(View changedView, int left, int top, int dx, int dy) {
                //记录左边的值的变化,因为我们实现的是往右滑动,所以只记录左边的值就可以了
                mScrollPercent = Math.abs((float) left / (mContentView.getWidth() + mShadowLeft.getIntrinsicWidth()));
                mMoveLeft = left;
                if (left == mContentWidth) {
                    //如果当前状态是关闭状态且左边的值等于滑动的View的宽度,
                    //也就是说当前的界面已经滑出屏幕,就回调finish方法,通知activity可以finish了
                    mCallBack.onFinish();
                }
            }

            @Override
            public boolean tryCaptureView(View child, int pointerId) {
                // 默认不扑获 View
                return false;
            }

            @Override
            public int clampViewPositionHorizontal(View child, int left, int dx) {
                // 拖动限制(大于左边界)
                return Math.max(0, left);
            }

            @Override
            public void onViewReleased(View releasedChild, float xvel, float yvel) {
                // 拖动距离大于屏幕的一半右移,拖动距离小于屏幕的一半左移
                int left = releasedChild.getLeft();
                if (left > getWidth() / 2) {
                    mViewDragHelper.settleCapturedViewAt(mContentWidth, 0);
                } else {
                    mViewDragHelper.settleCapturedViewAt(0, 0);
                }
                invalidate();
            }

            @Override
            public void onEdgeDragStarted(int edgeFlags, int pointerId) {
                // 移动子 View
                mViewDragHelper.captureChildView(mContentView, pointerId);
            }
        });
        mViewDragHelper.setEdgeTrackingEnabled(ViewDragHelper.EDGE_LEFT);
        setShadow();//设置侧滑的边框,这个方法的代码下面写哈

    }

    @Override
    public void computeScroll() {
        super.computeScroll();
        mScrimOpacity = 1 - mScrollPercent;
        //一定要做这个操作,否则onViewReleased不起作用
        if (mViewDragHelper != null && mViewDragHelper.continueSettling(true)) {
            invalidate();
        }
    }

    public void setShadow() {
        mShadowLeft = getResources().getDrawable(R.mipmap.shadow_left);
        invalidate();
    }

    @Override
    protected void onFinishInflate() {
        super.onFinishInflate();
        //SwipeBackFrameLayout的子View有且只有一个,否则抛异常
        if (getChildCount() != 1) {
            throw new IllegalStateException("SwipeBackFrameLayout must host one child.");
        }
        //取得当前布局的第一个子View,也是唯一一个子View
        //也就是activity的主要布局
        mContentView = getChildAt(0);
    }

    @Override
    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
        super.onLayout(changed, left, top, right, bottom);    //获取当前界面宽度
        mContentWidth = mContentView.getWidth();
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        //把事件传递给ViewDragHelper
        return mViewDragHelper.shouldInterceptTouchEvent(ev);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        //把事件传递给ViewDragHelper
        mViewDragHelper.processTouchEvent(event);
        invalidate();
        return true;
    }

    //画一个子项 ,到时候把acitivity的主题设置下就可以看到下面的activity了
    @Override
    protected boolean drawChild(Canvas canvas, View child, long drawingTime) {
        final boolean drawContent = child == mContentView;
        boolean ret = super.drawChild(canvas, child, drawingTime);
        if (drawContent && mViewDragHelper.getViewDragState() != ViewDragHelper.STATE_IDLE) {
            drawShadow(canvas, child);
            drawScrim(canvas, child);
        }
        return ret;
    }

    //这个是那个阴影线
    private void drawShadow(Canvas canvas, View child) {
        final Rect childRect = mTmpRect;
        child.getHitRect(childRect);
        mShadowLeft.setBounds(childRect.left - mShadowLeft.getIntrinsicWidth(), childRect.top,childRect.left, childRect.bottom);
        mShadowLeft.draw(canvas);
    }

    //这个就是画那个透明渐变出来的帷幕
    private void drawScrim(Canvas canvas, View child) {
        final int baseAlpha = (mScrimColor & 0xff000000) >>> 24;    
        final int alpha = (int) (baseAlpha * mScrimOpacity);
        final int color = alpha << 24 | (mScrimColor & 0xffffff);
        canvas.clipRect(0, 0, child.getLeft(), getHeight());
        canvas.drawColor(color);
    }

    //界面移出屏幕时接口回调
    public interface CallBack {
        void onFinish();//这个就可以直接用了咯,然后在acitiviy中实例化接口
    }

    //设置回调接口,提供给activity实现接口
    public void setCallBack(CallBack callBack) {
        mCallBack = callBack;
    }
}

然后还需要一些配置:

  • 如上述自定义布局View中用到的Shadow:

这里写图片描述

  • 需要在拖动后看到上一个 Activity 的内容,所以需要将屏幕最顶层的 View 背景设置为透明,在 style 中的App中添加两个标签,然后给Activity设置一下theme属性:
<item name="android:windowBackground">@android:color/transparent</item>
<item name="android:windowIsTranslucent">true</item>
//设置下theme属性就好啦
<activity 
    android:name=".BActivity"  
    android:theme="@style/AppTheme.TransparentActivity"    /> 
  • 需要侧滑退出的activity的布局文件中嵌套上咱得自定义SwipeBackLayout:
<?xml version="1.0" encoding="utf-8"?>
<xxx.xxx.SwipeBackLayout    
android:id="@+id/swipe_layout_two"    
xmlns:android="http://schemas.android.com/apk/res/android"    
android:layout_width="match_parent"    
android:layout_height="match_parent"> 
  <!-- 因为咱得这个侧滑退出自定义控件下面只能有一个子布局,所以把最外层布局嵌套在他的里面了。 -->
 <LinearLayout   
   android:layout_width="match_parent"        
   android:layout_height="match_parent"        
   android:orientation="vertical"    
   android:background="#00eeaa"        />  
</xxx.xxx.SwipeBackLayout>
  • 在activity中得到侧滑退出布局,设置他的回调接口:
@Override
protected void onCreate(Bundle savedInstanceState) {    
super.onCreate(savedInstanceState);    
setContentView(R.layout.activity_b); //找到控件 
//设置回调,然后就没然后了~~~
SwipeBackLayout swipeBackLayoutTwo = (SwipeBackLayout) findViewById(R.id.swipe_layout_two);
  swipeBackLayoutTwo.setCallBack(new SwipeBackLayout.CallBack() {        
   @Override      
    public void onFinish() {         
         finish();     
    }  
});
}
最后,启动该Activity,尝试滑动关闭
Android滑动关闭Activity 呵呵,给1分咯,效果不是很好 立即下载

相关推荐

Android-Android-DragDismissActivity滑动取消Activity

Android-DragDismissActivity:滑动取消Activity

Android自定义View,上下滑动,渐变关闭当前页面

github

fenganit的博客 1145

android 滑动关闭activity.zip

android 滑动关闭activity ,支持三种效果:左滑,右滑,及底部滑动关闭 sdk 需5.0以上,不然会报错。

Android 拖拽关闭Activity

使用ViewDragHelper实现下拉拖拽Activity关闭的功能。 SlideBackLayout类代码如下: import android.app.Activity import android.content.Context import android.util.DisplayMetrics import android.view.MotionEvent import and...

yunbiao的专栏 1813

SRRC型号核准的模块豁免规则解析——如何利用完整型模块简化设备认证流程

本文详细解析了SRRC型号核准中模块豁免规则的应用,重点介绍了完整型模块的技术定义、豁免条件及实际应用场景。通过合理利用完整型模块,企业可显著简化设备认证流程,缩短上市周期并降低成本。文章还提供了模块选型指南和常见问题解决方案,帮助工程师高效应对SRRC认证挑战。

weixin_29306011的博客 933

登临科技Goldwasser加速卡Python SDK实战:从环境配置到YOLOv5模型性能压测

本文详细介绍了登临科技Goldwasser加速卡的Python SDK实战指南,从环境配置到YOLOv5模型性能压测的全过程。通过驱动安装、SDK环境搭建、模型转换与推理优化等步骤,帮助开发者高效利用AI加速卡提升深度学习模型性能。重点分享了批量推理压测技巧和常见问题解决方案,助力开发者充分发挥Goldwasser加速卡的算力优势。

weixin_29035147的博客 300

Android从上往下滑动或从下往上滑动结束Activity

之前有看过xiaanming写的侧滑返回,于是仿照他的Demo,写了这个从上往下滑动或者从下往上滑动结束Activity 先附图一张,由于这台电脑分辨率有问题以及模拟器的缘故,先凑活看吧 先贴代码: 从上往下滑动: import android.content.Context; import android.util.AttributeSet

qq_18612815的博客 8652

kaggle——销量预测的baseline(M5 Forecasting - Accuracy)

前言 在刚刚结束的kaggle比赛M5 Forecasting - Accuracy中,因为是第一次参加,笔者也是花了大量的时间和精力在上面,最终拿到一块银牌(所以我拿到了大学第一个考试挂科。。。求求电磁场老师高抬贵手给点平时分放我一马吧。。。早上看到kaggle成绩异常兴奋,中午考完直接爆炸=。=),当然运气占了很大因素,这次比赛private leadboard的shake up非常大,排名波动几千名都存在的。笔者运气不错,是向上的shake:)。这里总结一下销量预测的基本流程。 从下图可以看到这次比

weixin_43901221的博客 5432

android webview_Android仿网易新闻上拉关闭Webview

效果如下:分为两部分:1. View的创建。2. 滑动事件处理1. View的创建从页面上看,主要分为上下两部分,上部为滚动的Webview,底部为拉出来的CloseView我这里自定义了ViewGrup。初始状态Webview撑满整个屏幕,CloseView不可见,位于Webview底部。代码如下public class PullupCloseLayout extends ViewGr...

weixin_39580564的博客 245

VMware共享磁盘配置实战:从零搭建多机共享存储环境

本文详细介绍了在VMware环境中从零开始配置共享磁盘的完整实战流程。通过创建共享磁盘、挂载至多台虚拟机并修改.vmx配置文件等关键步骤,帮助用户搭建可用于数据库集群(如Oracle RAC)测试的多机共享存储环境,并提供了核心参数设置与常见问题排查指南。

weixin_29284201的博客 492

自动驾驶仿真基础:使用Veristand自定义CAN报文的Checksum和Counter

文章目录前言一、关于Checksum的组成形式二、自定义的Checksum方法一1、实现的主要流程图如下:2、方法一的主要算法参考三、自定义的Checksum方法二1、软件及插件下载;2、Custom device的使用;4、Veristand调用Custom Device;5、Veristand发送信号值;6、部署到实时机; 前言 1、现在很多的车厂对于车辆的安全机制非常重视,车厂通过对发送的CAN数据进行加密而形成一种保护机制,而Checksum和Counter是其中的一种保护介质,当CAN报文数据的

zataji的博客 1万+

Node-Redis游戏开发:5个关键技术实现游戏数据存储与同步

Node-Redis作为现代高性能Redis客户端,为游戏开发提供了强大的数据存储和实时同步能力。本文将介绍如何利用Node-Redis在游戏开发中实现高效的数据管理和实时通信。🎮 Redis作为内存数据库,具有极快的读写速度,非常适合游戏场景中的排行榜、玩家状态、实时对战等需求。通过Node-Redis,开发者可以轻松构建高性能的多人游戏应用。 ## 🔥 游戏排行榜快速实现 在游戏开发

gitblog_00026的博客 466

C#串口通信革命:RJCP.DLL.SerialPortStream实战全解析

本文介绍了如何通过RJCP.DLL.SerialPortStream库实现高性能串口通信解决方案。相比.NET自带的SerialPort类,该库提供了完全的异步非阻塞IO、动态缓冲区控制和多线程事件驱动等优势,特别适合工业自动化和物联网场景。文章详细讲解了环境搭建、核心功能对比,并通过代码示例展示了端口配置、异步通信管道搭建等关键技术。最后以Modbus RTU协议为例,演示了高级协议封装方法,为开发者提供了完整的工业级串口通信实现方案。

墨夶的博客 1872

滑动关闭activity

对于微信滑动关闭activity的功能,我一直觉得挺酷,想在自己的项目上也加上这个功能。网上找了一下发现一个不错的思路。 使用ViewDragHelper。 首先要让activity在滑动的时候下面的activity能够看得到,那么就得设置activity的主题,让activity的窗口变透明。 <style name="MyActivityBackground" parent="...

weixin_34384557的博客 174

Google 二次签名 导致 Facebook , Google 登录失败

google 授权登录

xq610928的博客 1957

22、预条件技术:矩阵分解与多项式预条件器

本文系统介绍了预条件技术中的不完全分裂法、多项式预条件器和近似逆预条件器。内容涵盖矩阵分解的基本原理、不完全LU和Cholesky分解的实现方法、基于填充水平和阈值策略的改进技术,以及多项式和近似逆预条件器的数学基础与应用。通过算法流程图和表格对比,展示了各类预条件器的适用场景与优缺点,同时探讨了其在迭代求解中的关键作用和未来发展方向。

theta的博客 95

仿微信、知乎实现上下左右滑动关闭Acticity

用过IOS的手机都知道,IOS是可以右滑可以返回前一个界面的。在Android机上目前使用的还不多,到现在为止,我看到的只有微信、知乎实现了这个功能。目录[TOC] - 效果展示 - 逻辑剖析 - 代码注释 - 代码库效果展示 特色: 1、支持上下左右边界或者全屏幕的滑动 2、实现了前一个Activity的界面滑动逻辑剖析实现这个效果,我们需要处理两部分

2260

TMS_WebGMaps_1.9.8.0_Full_Source

TMS_WebGMaps_1.9.8.0_Full_Source 全源码 delphi cbuilder

滑动关闭Activity

常常可以看到,很多Android应用都有这么一个功能,就是滑动关闭Activity,比如微信,优快云移动端,百度贴吧移动端等。我自己也想写个滑动关闭Activity,最近事件没有那么多,我就google了一下,查看了一下实现滑动关闭Activity的实现方法,其中,有个思路,我觉得很不错,因此,在这里,我通过别人的思路,自己实现了一下滑动关闭Activity的方法,在此记录一下。我希望这篇博客,

梅的专栏 6997

C# WinForm 基于DirectShow.dll编写的程序,可边预览边保存视频,音频和图片

基于微软的DirectShow.dll的二次开发1.自动识别连接的摄像头跟麦克风且可以对其进行选择(默认选中第一个)2.可录制wmv和avi两种格式的视频并且都带有音频,avi可以录制的分辨率和帧数进行选择,wmv默认进行了淸晰度优化如不喜欢可去除代码中有相关提示3.可在预览点开之后进行拍照,也可边录制视频边拍照4.添加了视频和音频的压缩功能(酌情使用)这次二次开发发现C#对DirectShow的相关信息太少,这次做完也不敢藏私共享出来,还望大家指正

复分析 阿尔福斯(Ahlfors) 第三版答案 英文

答案分为十章,有部分习题没有答案,全英文复分析阿尔福斯(Ahlfors) 第三版答案

SwipeBackLayout - 手势滑动关闭的优雅实现

SwipeBackLayout - 手势滑动关闭的优雅实现 SwipeBackLayout 是一个 Android 开源库,它让你可以通过手势来完成 Activity 的退出操作,为你的应用带来更加流畅的用户体验。 项目介绍 这个库提供了从四个方向(FROM_LEFT, FROM_TOP, FROM_RIGHT, FROM_BOTTOM)滑动关闭活动的功能,并且可以设置是否只能从边缘开始滑动。Sl...

gitblog_00061的博客 532

ssm框架搭建

这个是一个在idea上成功跑起来的ssm框架项目,保存在这里方便以后使用直接下载

Android右滑关闭Activity界面功能-自定义控件实现

引言Android右滑关闭Activity界面功能,网上已经有好多优秀的开源代码和项目,不过大部分都是结合ViewDragHelper来实现的,这里要讨论的是通过结合ValueAnimator来实现,目前我的控件只实现了从左往右(上往下)滑关闭界面。需求在界面上从左往右滑,View位置根据手势移动。只拦截左右滑动,上下方向的滑动无影响。子View的左右滑动事件无影响。预览图image实现思路Swi...

aakzhangliangming的专栏 853

侧滑Activity返回原理剖析

文章标题简介Slidr使用示例步骤一 重新包裹界面步骤二 使用`ViewDragHelper.class`处理滑动手势步骤三 在ViewDragHelper.Callback中处理我们的界面的拖动总结 简介 使用侧滑Activity返回很常见,例如微信就用到了。那么它是怎么实现的呢。本文带你剖析一下实现原理。我在github上找了一个star有2.6k的开源,我们分析他是怎么实现的 //star 2.6k 'com.r0adkll:slidableactivity:2.0.5' Slidr使用示例 它

Gyso的博客 451

Activity添加滑动关闭功能-[Android_YangKe]

code小生,一个专注 Android 领域的技术分享平台作者:Android_YangKe地址:https://www.jianshu.com/p/d62cda4101...

code小生 695

【android开发】手势滑动关闭Activity(随手指消失)的辅助类的实现

【优快云抽风,把我写一个多小时的东西覆盖了。真的是哔了狗了,自己又没有备份。。。重写吧。。。】这个类主要是实现向右滑动关闭Activity,效果如下: 老套路,先写思路: 1)将Activity的背景设置为透明模式。(从而可以看到下一层Activity) 2)创建一个FrameLayout,将contentView从DecorView中移除,并将contentView添加到我们的FrameL

蓝亭书序 5859

Android右滑关闭当前Activity

转载请注明出处:meijian531161724 常常可以看到,很多Android应用都有这么一个功能,就是滑动关闭Activity,比如微信,优快云移动端,百度贴吧移动端等。我自己也想写个滑动关闭Activity,最近事情没有那么多,我就google了一下,查看了一下实现滑动关闭Activity的实现方法,其中,有个思路,我觉得很不错,因此,在这里,我通过别人的思路,自己实现了一下滑

FynnJason的技术屋 4248

Anime4K 实时超分辨率实战:3 档硬件配置,让老番重获 4K 清晰度

深夜,4K 电视,你从"老番存档"文件夹里拖出一部 90 年代的赛璐珞(手绘胶片时代)动画。第一帧出来你就后悔了:人物轮廓是糊的,边缘浮着一圈光晕,大面积色块被切成一格一格的色阶,整帧还蒙着一层压缩噪声。4K 屏幕没有让画面变好,只是把这些毛病放大到了整面墙。重编码成 4K 得花几小时一集,而且一去不回头;更省事的办法叫实时超分辨率——让 GPU 在播放时逐帧重构画面。开源项目 Anime4K 干

gitblog_00033的博客 503
上一篇: [Android]Fragment进行show和hide时候刷新数据
下一篇: [Android]透明状态栏
runstoppable
博客等级 码龄10年 1粉丝 23原创
评论 2
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值