Android 滑动布局来关闭

2023-11-27

我正在尝试制作一个可滑动的布局,这样你就可以像现在在谷歌中一样滑动它来关闭。 我设法使用以下代码让它在诸如按钮之类的视图上工作:

SwipeDismissTouchListener:

public class SwipeDismissTouchListener implements View.OnTouchListener {
// Cached ViewConfiguration and system-wide constant values
private int mSlop;
private int mMinFlingVelocity;
private int mMaxFlingVelocity;
private long mAnimationTime;

// Fixed properties
private View mView;
private DismissCallbacks mCallbacks;
private int mViewWidth = 1; // 1 and not 0 to prevent dividing by zero

// Transient properties
private float mDownX;
private float mDownY;
private boolean mSwiping;
private int mSwipingSlop;
private Object mToken;
private VelocityTracker mVelocityTracker;
private float mTranslationX;

/**
 * The callback interface used by {@link SwipeDismissTouchListener} to inform its client
 * about a successful dismissal of the view for which it was created.
 */
public interface DismissCallbacks {
    /**
     * Called to determine whether the view can be dismissed.
     */
    boolean canDismiss(Object token);

    /**
     * Called when the user has indicated they she would like to dismiss the view.
     *
     * @param view  The originating {@link android.view.View} to be dismissed.
     * @param token The optional token passed to this object's constructor.
     */
    void onDismiss(View view, Object token);
}

/**
 * Constructs a new swipe-to-dismiss touch listener for the given view.
 *
 * @param view     The view to make dismissable.
 * @param token    An optional token/cookie object to be passed through to the callback.
 * @param callbacks The callback to trigger when the user has indicated that she would like to
 *                 dismiss this view.
 */
public SwipeDismissTouchListener(View view, Object token, DismissCallbacks callbacks) {
    ViewConfiguration vc = ViewConfiguration.get(view.getContext());
    mSlop = vc.getScaledTouchSlop();
    mMinFlingVelocity = vc.getScaledMinimumFlingVelocity() * 16;
    mMaxFlingVelocity = vc.getScaledMaximumFlingVelocity();
    mAnimationTime = view.getContext().getResources().getInteger(
            android.R.integer.config_shortAnimTime);
    mView = view;
    mToken = token;
    mCallbacks = callbacks;
}
@Override
public boolean onTouch(View view, MotionEvent motionEvent) {
    // offset because the view is translated during swipe
    motionEvent.offsetLocation(mTranslationX, 0);

    if (mViewWidth < 2) {
        mViewWidth = mView.getWidth();
    }

    switch (motionEvent.getActionMasked()) {
        case MotionEvent.ACTION_DOWN: {
            // TODO: ensure this is a finger, and set a flag
            mDownX = motionEvent.getRawX();
            mDownY = motionEvent.getRawY();
            if (mCallbacks.canDismiss(mToken)) {
                mVelocityTracker = VelocityTracker.obtain();
                mVelocityTracker.addMovement(motionEvent);
            }
            return false;
        }

        case MotionEvent.ACTION_UP: {
            if (mVelocityTracker == null) {
                break;
            }

            float deltaX = motionEvent.getRawX() - mDownX;
            mVelocityTracker.addMovement(motionEvent);
            mVelocityTracker.computeCurrentVelocity(1000);
            float velocityX = mVelocityTracker.getXVelocity();
            float absVelocityX = Math.abs(velocityX);
            float absVelocityY = Math.abs(mVelocityTracker.getYVelocity());
            boolean dismiss = false;
            boolean dismissRight = false;
            if (Math.abs(deltaX) > mViewWidth / 2 && mSwiping) {
                dismiss = true;
                dismissRight = deltaX > 0;
            } else if (mMinFlingVelocity <= absVelocityX && absVelocityX <= mMaxFlingVelocity
                    && absVelocityY < absVelocityX
                    && absVelocityY < absVelocityX && mSwiping) {
                // dismiss only if flinging in the same direction as dragging
                dismiss = (velocityX < 0) == (deltaX < 0);
                dismissRight = mVelocityTracker.getXVelocity() > 0;
            }
            if (dismiss) {
                // dismiss
                mView.animate()
                        .translationX(dismissRight ? mViewWidth : -mViewWidth)
                        .alpha(0)
                        .setDuration(mAnimationTime)
                        .setListener(new AnimatorListenerAdapter() {
                            @Override
                            public void onAnimationEnd(Animator animation) {
                                performDismiss();
                            }
                        });
            } else if (mSwiping) {
                // cancel
                mView.animate()
                        .translationX(0)
                        .alpha(1)
                        .setDuration(mAnimationTime)
                        .setListener(null);
            }
            mVelocityTracker.recycle();
            mVelocityTracker = null;
            mTranslationX = 0;
            mDownX = 0;
            mDownY = 0;
            mSwiping = false;
            break;
        }

        case MotionEvent.ACTION_CANCEL: {
            if (mVelocityTracker == null) {
                break;
            }

            mView.animate()
                    .translationX(0)
                    .alpha(1)
                    .setDuration(mAnimationTime)
                    .setListener(null);
            mVelocityTracker.recycle();
            mVelocityTracker = null;
            mTranslationX = 0;
            mDownX = 0;
            mDownY = 0;
            mSwiping = false;
            break;
        }

        case MotionEvent.ACTION_MOVE: {
            if (mVelocityTracker == null) {
                break;
            }

            mVelocityTracker.addMovement(motionEvent);
            float deltaX = motionEvent.getRawX() - mDownX;
            float deltaY = motionEvent.getRawY() - mDownY;
            if (Math.abs(deltaX) > mSlop && Math.abs(deltaY) < Math.abs(deltaX) / 2) {
                mSwiping = true;
                mSwipingSlop = (deltaX > 0 ? mSlop : -mSlop);
                mView.getParent().requestDisallowInterceptTouchEvent(true);

                // Cancel listview's touch
                MotionEvent cancelEvent = MotionEvent.obtain(motionEvent);
                cancelEvent.setAction(MotionEvent.ACTION_CANCEL |
                        (motionEvent.getActionIndex() <<
                                MotionEvent.ACTION_POINTER_INDEX_SHIFT));
                mView.onTouchEvent(cancelEvent);
                cancelEvent.recycle();
            }

            if (mSwiping) {
                mTranslationX = deltaX;
                mView.setTranslationX(deltaX - mSwipingSlop);
                // TODO: use an ease-out interpolator or such
                mView.setAlpha(Math.max(0f, Math.min(1f,
                        1f - 2f * Math.abs(deltaX) / mViewWidth)));
                return true;
            }
            break;
        }
    }
    return false;
}

private void performDismiss() {
    // Animate the dismissed view to zero-height and then fire the dismiss callback.
    // This triggers layout on each animation frame; in the future we may want to do something
    // smarter and more performant.

    final ViewGroup.LayoutParams lp = mView.getLayoutParams();
    final int originalHeight = mView.getHeight();

    ValueAnimator animator = ValueAnimator.ofInt(originalHeight, 1).setDuration(mAnimationTime);

    animator.addListener(new AnimatorListenerAdapter() {
        @Override
        public void onAnimationEnd(Animator animation) {
            mCallbacks.onDismiss(mView, mToken);
            // Reset view presentation
            mView.setAlpha(1f);
            mView.setTranslationX(0);
            lp.height = originalHeight;
            mView.setLayoutParams(lp);
        }
    });

    animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
        @Override
        public void onAnimationUpdate(ValueAnimator valueAnimator) {
            lp.height = (Integer) valueAnimator.getAnimatedValue();
            mView.setLayoutParams(lp);
        }
    });

    animator.start();
}
}

调用它:

    dismissableButton.setOnTouchListener(new SwipeDismissTouchListener(
            dismissableButton,
            null,
            new SwipeDismissTouchListener.DismissCallbacks() {
                @Override
                public boolean canDismiss(Object token) {
                    return true;
                }
                @Override
                public void onDismiss(View view, Object token) {
                group.removeView(dismissableButton);
             }
     }));

我想让这段代码在布局上工作,这样我就可以滑动布局来关闭,例如,我可以将相对布局放置在 ViewGroup 内,并使相对布局可滑动来关闭。


我刚刚用过同样的SwipeDismissTouchListener类来实现滑动手势RelativeLayout,一开始遇到的问题是ACTION_MOVE从未通过,或除ACTION_DOWN.

发现问题在于ACTION_DOWN返回false。所以只需改变你的情况ACTION_DOWN回来true,并且它将正常工作,因为这将使其他操作也得到通过。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Android 滑动布局来关闭 的相关文章

  • 如何从 Java 中的 Native Android Activity 打开 React Native 应用程序的特定组件?

    Alert 这个问题基本上是关于一种方法 所以不会有任何可用的笔或代码可以共享 I was doing a POC where integrating an RN app into an Android App I did successf
  • 使用react-native测量音频的响度

    我正在创建一个应用程序 Android 来使用本机反应录制手机中的语音 一项要求是实时测量声音的响度并基于它制作动画 我尝试使用react native audio库 但问题是响度监控仅在IOS中支持 我检查了世博会音频库 但找不到方法 有
  • Android 全屏对话框片段(如日历应用程序)

    我正在尝试实现如下图所示的全屏对话框 我能够显示全屏对话框 但是当显示对话框时 状态栏颜色变为黑色并且不保留原色深色 这是我的对话片段 public class IconsDialogFragment extends DialogFragm
  • 在 Android Studio 中设置 Http 代理

    我已经阅读了多个类似的问题和文档 但我无法解决我的机器所在的公司防火墙的问题 我收到的错误是 无法刷新 Gradle 项目 未知主机 services gradle org 我所阅读和理解的所有内容都让我相信这是一个 http 代理问题 我
  • 动态创建形状

    我有一个在 XML 中定义的形状对象 如下所示
  • 按下按钮时清除编辑文本焦点并隐藏键盘

    我正在制作一个带有编辑文本和按钮的应用程序 当我在 edittext 中输入内容然后单击按钮时 我希望键盘和焦点在 edittext 上消失 但我似乎无法做到这一点 我在 XML 中插入了这两行代码 android focusable tr
  • 从 Bitmap 类创建 .bmp 图像文件

    我创建了一个使用套接字的应用程序 客户端在其中接收图像并将图像数据存储在 Bitmap 类中 谁能告诉我如何创建一个名为我的图像 png or 我的图像 bmp来自此 Bitmap 对象 String base64Code dataInpu
  • AlertDialog setButton 已弃用

    我在我的 Eclipse Android 项目中使用此代码 alertDialog setButton OK new DialogInterface OnClickListener Override public void onClick
  • Android SIP 客户端 SipManager.open() 未打开

    我一直在使用 Android SDK 的本机 SIP 库编写 SIP 客户端 由于某种原因 我无法让我的帐户在服务器上注册 以下是测试场地 Linux Mint 17 XFCE 运行 Kamailio 服务器 启用 MySQL 和 TLS
  • Android中的SQLite是否有内存缓存以及如何释放或清除它?

    首先 我在 Android 应用程序中创建一个名为 mydb 的数据库 DBHelper dbHelper new DBHelper context mydb null 1 DBHelper is my custom class 并将一些数
  • 当您处于飞行模式并退出飞行模式时,我只收到最后一条 FCM 推送通知?

    我只在退出飞行模式后收到最后的推送通知 FCM 但是 如果我的应用程序位于前台 一旦我离开飞行模式 我将收到所有推送通知 我已将 FCM 消息类型实现为通知消息 笔记 无法将 FCM 消息类型实现为数据消息 因为 APNS 只接受我的 iO
  • 何时取消订阅

    我有一个关于如何取消订阅可观察的问题 我有两个代码 但我不确定哪一个更好 示例 1 gt 流结束后取消订阅订阅者 Subscriber
  • Firebird 和 Android JDBC 驱动程序

    火鸟有问题 我从未与 DB 合作过 服务器 firebird 1 5 上的数据库 添加库 firebird full 2 2 4到 libs 文件夹 将其添加到 Gradle implementation fileTree libs 将其添
  • SlidingPaneLayout setCoveredFadeColor () 和 setSliderFadeColor()

    我正在使用SlidingPaneLayout并希望在滑块右窗格打开时在左窗格上设置灰色渐变颜色 在右窗格关闭且左窗格完全可见时在左窗格上设置透明渐变颜色 我知道这是默认行为SlidingPaneLayout 但使用默认实现时 我在横向模式下
  • Xamarin.Forms 用相机拍照显示方向错误并且后退按钮崩溃

    我正在使用此处的 Xamarin Forms Camera 示例 https github com XForms Xamarin Forms Labs Samples tree master XF Labs CameraSample htt
  • 在 Android 中使用 Fragment 时处理后按

    我在应用程序中使用 Android 滑动菜单和导航抽屉 并且在应用程序中使用片段而不是活动 当我打开抽屉时 单击一个项目会出现一个片段 我使用以下代码从一个片段移动到另一个片段 Fragment fragment null fragment
  • Android 中的垂直(旋转)标签

    我需要两种在 Android 中显示垂直标签的方法 水平标签逆时针旋转 90 度 字母在侧面 带有字母的水平标签 如商店招牌 我是否需要为这两种情况 一种情况 开发自定义小部件 我可以使 TextView 以这种方式呈现吗 如果我需要完全自
  • 用户的 RecyclerView 为空

    我试图使用 Firebase 实时数据库在 RecyclerView 中向用户显示主键 但每次我尝试 RecyclerView 都是空的 我尝试了很多教程 但似乎没有任何帮助 这是我的数据库的样子 这是我使用 RecyclerView 的类
  • 在模拟器中启动应用程序后,“React Native run android”立即停止

    我正在尝试测试我的 Android 应用程序 但是当我启动它时react native run android命令在设备上启动后立即停止 不会出现错误 我懂了 This build could be faster please consid
  • 安卓框架?

    是否有任何框架比构建 Android 应用程序更容易 您会对其中一个感兴趣吗 很快就会有 我正在开发 DroidFu 一个 Android 共享库 它将为您提供 活动 和服务 中直接提供大量实用功能 例如生成列表和错误对话框 检查 Inte

随机推荐

  • 使用数据映射器模式,实体(域对象)是否应该了解映射器?

    我是第一次使用 Doctrine2 但我认为这个问题足够通用 不依赖于特定的 ORM 数据映射器模式中的实体是否应该意识到 以及use 地图绘制者 我有一些具体的例子 但它们似乎都可以归结为同一个普遍问题 如果我正在处理来自外部源的数据 例
  • 使用 processBuilder 执行 shell 命令并与其交互

    我正在尝试创建一个程序 允许我通过带有参数的终端 如果您想知道 则为树莓派的 OmxPlayer 执行命令 但我希望在启动后能够与它进行交互命令 例如我想做 omxplayer win x1 y1 x2 y2 然后可以按 p 暂停视频 音频
  • 如何只制作注册邀请函?

    使用 Meteor 帐户 以及accounts ui 有没有一种简单的方法可以只邀请新用户注册 例如 通过提供邀请链接或邀请码 我在 Meteor 文档中能找到的唯一相关内容是Meteor sendEnrollmentEmail但这并不能解
  • 如何通过连接表填充 has_many 中的字段

    我有一个关于活动记录关联的问题 参考 Rails 文档的这一部分 http guides rubyonrails org association basics html the has many through association 如果
  • 关闭 stdout 和 stdin 文件描述符后重新打开它们

    我正在编写一个函数 给定一个参数 该函数会将标准输出重定向到文件或从文件读取标准输入 为此 我关闭与 stdout 或 stdin 关联的文件描述符 以便当我打开文件时 它会在我刚刚关闭的描述符下打开 这是可行的 但问题是一旦完成 我需要将
  • 计算船只到海岸或海岸线的距离

    对于船只的 200M GPS 经度 纬度 坐标数据集 我想计算到最近陆地或海岸线的近似距离 作为一个名为 distance to shore 的函数 它将返回该海岸的距离和国家 地区 我使用的国家边界和海岸线形状文件来自 http www
  • 在这种情况下SQLite线程安全吗?

    我需要通过一个拥有数据库连接的单例对象从多个线程进行数据库访问操作 我从 SQLite3 的网站上读到 它说 sqlite3 结构只能在调用 sqlite3 open 来创建它的同一线程中使用 您无法在一个线程中打开数据库 然后将句柄传递给
  • 为什么在使用 Model.copy() 后出现“GurobiError:变量不在模型中”?

    我需要优化具有不同约束集的模型 但这些约束的子集对于每个模型都是相同的 我的想法是构建一个包含每次都需要的所有变量和所有约束的基本模型 但是 它看起来并不像 Gurobi Model copy 方法按照我想象的方式复制变量 这是我希望做的事
  • 安装旧版本的 R 包

    我正在尝试使用 Rpy2 和 ggplot2 但出现错误 经过网上一些搜索错误 我发现发生错误是因为ggplot2包中存在尚未反映在Rpy2中的更改 例如 参见这个帖子 编辑 链接现已失效 所以我现在需要安装旧版本的 ggplot2 这是我
  • .NET Core 相当于 Thread.Abort

    背景 我有一个Service抽象 每个服务都有自己的WorkItem 工作项能够从一些数据开始 该服务正在限制执行时间WorkItem 假设单个工作项最多可能需要 60 秒 在此之后 Service应该杀掉它 这段代码从 NET Frame
  • Android TimePickerDialog材质设计颜色

    我在我的应用程序中使用时间选择器对话框 我还使用 appcompat 来为我的应用程序提供材料设计主题 然而 该对话框保留默认的青色强调色 我的强调色是浅蓝色 所以在我的代码中我尝试将对话框主题设置为我自己的并且它可以工作接受它使其全屏显示
  • 获取 java.util.List 的泛型类型

    I have List
  • 如何使用 Node.js“执行”HTML+Javascript 页面

    这样 我就有了 Node js 脚本 我有一些 HTML 页面 其中包含带有 JavaScript jquery 的 HTML 如何加载它并获取该页面上 JavaScript 的执行结果 你可以检查zombie js项目 http zomb
  • (React) CSSTransition 与 css 模块

    我正在尝试在我的项目中实现 CSSTransition 到模式 问题是我正在使用 css 模块 我的模态的渲染方法 render return
  • 检测 html 表单是否被编辑的通用方法

    我有一个选项卡式 html 表单 从一个选项卡导航到另一选项卡时 即使数据没有更改 当前选项卡的数据也会保留 在数据库上 我想仅在编辑表单时才进行持久性调用 该表单可以包含任何类型的控件 不一定要通过键入一些文本来弄脏表单 但在日历控件中选
  • 如果为空则创建新实例的简写?

    在 Javascript 中我可以这样做 var myVar returnNull new MyObject 在 C 中 我目前正在这样做 var myVar returnObjectOrNull if myVar null myVar n
  • 在 mongodb 中存储赞成票/反对票

    我有一个收藏Posts and Users用户可以对每个帖子投赞成票 反对票 将其存储在 mongodb 数据库中以确保用户不能多次为给定文档投票的最佳方法是什么 我想出的最简单的 nosql ish 解决方案是存储在每个内部投票的 use
  • 跨平台网络 API [关闭]

    Closed 此问题正在寻求书籍 工具 软件库等的推荐 不满足堆栈溢出指南 目前不接受答案 我想知道是否有一个 API 可以在 Windows Mac 和 Linux 上运行网络 我想做一个2人可以通过TCP连接玩的纸牌游戏 有几个选项可以
  • 使用ngrx一次获取store的当前状态

    您好 我想知道是否有人知道如何在无需订阅的情况下获取商店的当前状态 我目前正在使用 ngrx 订阅商店并访问其状态以设置组件的属性 但由于我订阅了该属性 所以它会不断刷新 因此 我正在寻找一种仅获取此属性一次的方法 以便我可以显示数据而无需
  • Android 滑动布局来关闭

    我正在尝试制作一个可滑动的布局 这样你就可以像现在在谷歌中一样滑动它来关闭 我设法使用以下代码让它在诸如按钮之类的视图上工作 SwipeDismissTouchListener public class SwipeDismissTouchL