【问题标题】:End up activity on swipe right?向右滑动即可结束活动?
【发布时间】:2023-03-23 15:49:01
【问题描述】:

当用户在屏幕的任意位置右滑时,我必须完成Activity。我已经尝试过GestureDetector,如果Activity 中既不存在ScrollView 也不存在RescyclerView 并且另外具有onClickListener 的视图也不允许检测到它们上方的滑动,那它工作得很好。所以我尝试了一种不同的方法,通过编程将视图覆盖到所有视图顶部的布局中,然后尝试检测其上方的滑动事件。

private void swipeOverToExit(ViewGroup rootView) {

        OverlayLayout child = new OverlayLayout(this);

        ViewGroup.LayoutParams layoutParams =
                new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);

        child.setLayoutParams(layoutParams);

        rootView.addView(child);

}

叠加布局

public class OverlayLayout extends RelativeLayout {

    private float x1, x2;
    private final int MIN_DISTANCE = 150;

    public OverlayLayout(Context context) {
        super(context);
    }

    public OverlayLayout(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public OverlayLayout(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
    public OverlayLayout(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
    }


    @Override
    public boolean onInterceptTouchEvent(MotionEvent event) {
        /*
         * This method JUST determines whether we want to intercept the motion.
         * If we return true, onTouchEvent will be called and we do the actual
         * logic there.
         */

        final int action = MotionEventCompat.getActionMasked(event);

        Logger.logD("Intercept===", action + "");


        // Always handle the case of the touch gesture being complete.
        if (action == MotionEvent.ACTION_DOWN) {
            return true; // Intercept touch event, let the parent handle swipe
        }

        Logger.logD("===", "Out side" + action + "");


        // In general, we don't want to intercept touch events. They should be
        // handled by the child view.
        return false;
    }


    @Override
    public boolean onTouchEvent(MotionEvent event) {
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                x1 = event.getX();
                break;
            case MotionEvent.ACTION_UP:

                x2 = event.getX();
                float deltaX = x2 - x1;

                if (Math.abs(deltaX) > MIN_DISTANCE) {

                    Logger.logD("Swipe Right===", MIN_DISTANCE + "");
                    return true;

                } else {

                    Logger.logD("Tap===", "Tap===");
                    return super.onTouchEvent(event);
                }
        }

        return true;

    }
}

如果滑动操作在OverlayLayout 上执行,逻辑是拦截触摸事件到其他视图,然后进一步结束Activity。但是,现在我可以在OverlayLayout 上检测到滑动事件,但是即使我在onTouchEvent 的其他条件下返回return super.onTouchEvent(event);,其他视图也无法响应,因为您可以在我的代码中找到。任何人请帮我完成它。我被固定在这里并且非常兴奋地学习这个技巧:)

【问题讨论】:

  • 尝试添加@Override public boolean dispatchTouchEvent(MotionEvent ev){ super.dispatchTouchEvent(ev);返回 productGestureDetector.onTouchEvent(ev); } 到您的活动
  • @Stella 你在活动中尝试过 dispatchTouchEvent 吗?
  • 尝试搜索touchIntercept在任何布局中控制手势的方法。
  • 我在活动中尝试过dispatchTouchEvent,但似乎对我没有帮助。我尝试了所有搜索,但我无法做到,这就是为什么我终于在这里@Atif。如果您知道发生了什么,请提供帮助。谢谢
  • @Stella 可能 help

标签: android android-activity swipe ontouchlistener


【解决方案1】:

您尝试做的基本上是 Android Wear 中的默认行为,它被视为Android Watches 中退出应用程序的标准做法。 在 Android 中,DismissOverlayView 为您完成所有繁重的工作。

智能手机有返回按钮,而 Wear 依靠长按或滑动关​​闭模式来退出屏幕。您应该在后按时关闭 Activity,在 Android 智能手机中混合佩戴模式会使用户感到困惑。至少显示一个警告对话框以避免意外退出。

解决方案

我看到这个问题被标记为 Android Activity,我建议你制作一个 Base Activity,它会处理滑动手势和finish() 本身从左到右滑动。

基本活动类应如下所示:-

   public abstract class SwipeDismissBaseActivity extends AppCompatActivity {
    private static final int SWIPE_MIN_DISTANCE = 120;
    private static final int SWIPE_MAX_OFF_PATH = 250;
    private static final int SWIPE_THRESHOLD_VELOCITY = 200;
    private GestureDetector gestureDetector;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        gestureDetector = new GestureDetector(new SwipeDetector());
    }

    private class SwipeDetector extends GestureDetector.SimpleOnGestureListener {
        @Override
        public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {

            // Check movement along the Y-axis. If it exceeds SWIPE_MAX_OFF_PATH,
            // then dismiss the swipe.
            if (Math.abs(e1.getY() - e2.getY()) > SWIPE_MAX_OFF_PATH)
                return false;

            // Swipe from left to right.
            // The swipe needs to exceed a certain distance (SWIPE_MIN_DISTANCE)
            // and a certain velocity (SWIPE_THRESHOLD_VELOCITY).
            if (e2.getX() - e1.getX() > SWIPE_MIN_DISTANCE && Math.abs(velocityX) > SWIPE_THRESHOLD_VELOCITY) {
                finish();
                return true;
            }

            return false;
        }
    }

    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        // TouchEvent dispatcher.
        if (gestureDetector != null) {
            if (gestureDetector.onTouchEvent(ev))
                // If the gestureDetector handles the event, a swipe has been
                // executed and no more needs to be done.
                return true;
        }
        return super.dispatchTouchEvent(ev);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        return gestureDetector.onTouchEvent(event);
    }
}

现在你可以让其他活动扩展这个基础活动,他们 Inheritance 会自动让他们采用滑动关闭 行为。

public class SomeActivity extends SwipeDismissBaseActivity {

这种方式的优点

  • 纯 OOPS 方法
  • 简洁的代码 - 无需在项目中使用的每种布局类型(相对、线性等)中编写滑动监听器
  • 在 ScrollView 中完美运行

【讨论】:

  • 与 fling 完美结合。知道如何用手指拖动活动并关闭吗?
  • @hitesh-sahu 你能回答一下 Seshu 提出的问题吗,我也需要这个。
  • @FarooqKhan 你是怎么做到的?
【解决方案2】:

试试这个我正在使用这样的滑动功能

查看以滑动...

 yourview.setOnTouchListener(new SimpleGestureFilter(this)); // yourview is layout or container to swipe

SimpleGestureFilter 类

  public class SimpleGestureFilter implements View.OnTouchListener {

        static final String logTag = "ActivitySwipeDetector";
        private Context activity;
        static final int MIN_DISTANCE = 100;// TODO change this runtime based on screen resolution. for 1920x1080 is to small the 100 distance
        private float downX, downY, upX, upY;

        // private NDAAgreementActivity mMainActivity;

        public SimpleGestureFilter(Context mainActivity) {
            activity = mainActivity;
        }

        public void onRightToLeftSwipe() {


          //do your code to right to left



        }

        public void onLeftToRightSwipe() {
            //do your code to left to  right
        }

        public void onTopToBottomSwipe() {

        }

        public void onBottomToTopSwipe() {

        }

        public boolean onTouch(View v, MotionEvent event) {
            switch (event.getAction()) {
                case MotionEvent.ACTION_DOWN: {
                    downX = event.getX();
                    downY = event.getY();
                    return true;
                }
                case MotionEvent.ACTION_UP: {
                    upX = event.getX();
                    upY = event.getY();

                    float deltaX = downX - upX;
                    float deltaY = downY - upY;

                    // swipe horizontal?
                    if (Math.abs(deltaX) > MIN_DISTANCE) {
                        // left or right
                        if (deltaX < 0) {
                            this.onLeftToRightSwipe();
                            return true;
                        }
                        if (deltaX > 0) {
                            this.onRightToLeftSwipe();
                            return true;
                        }
                    } else {
                        Log.i(logTag, "Swipe was only " + Math.abs(deltaX) + " long horizontally, need at least " + MIN_DISTANCE);
                        // return false; // We don't consume the event
                    }

                    // swipe vertical?
                    if (Math.abs(deltaY) > MIN_DISTANCE) {
                        // top or down
                        if (deltaY < 0) {
                            this.onTopToBottomSwipe();
                            return true;
                        }
                        if (deltaY > 0) {
                            this.onBottomToTopSwipe();
                            return true;
                        }
                    } else {
                        Log.i(logTag, "Swipe was only " + Math.abs(deltaX) + " long vertically, need at least " + MIN_DISTANCE);
                        // return false; // We don't consume the event
                    }

                    return false; // no swipe horizontally and no swipe vertically
                }// case MotionEvent.ACTION_UP:
            }
            return false;
        }
    }

【讨论】:

  • 如果我为任何孩子设置了点击事件,这将无法正常工作。
  • 你应该检查你滑动中的子区域.....检查区域匹配父和匹配高度而不是检查它......
【解决方案3】:

我相信 RecyclerView 和 ScrollView 的问题与子元素在父元素之前获得焦点有关。您可以尝试为 Recycler/Scroll 视图设置 android:descendantFocusability="beforeDescendants"

【讨论】:

    【解决方案4】:

    我在 Activity Overlay 方面遇到了同样的问题。这对我有用

    1) 定义你的 SwipeListener

    public class SwipeListener implements View.OnTouchListener {
    
    private SwipeListenerInterface activity;
    private float downX, downY, upX, upY;
    
    public SwipeListener(SwipeListenerInterface activity) {
        this.activity = activity;
    }
    
    public void onRightToLeftSwipe(View v) {
        Log.i(logTag, "RightToLeftSwipe!");
        activity.onRightToLeftSwipe(v);
    }
    
    public void onLeftToRightSwipe(View v) {
        Log.i(logTag, "LeftToRightSwipe!");
        activity.onLeftToRightSwipe(v);
    }
    
    public void onTopToBottomSwipe(View v) {
        Log.i(logTag, "TopToBottomSwipe!");
        activity.onTopToBottomSwipe(v);
    }
    
    public void onBottomToTopSwipe(View v) {
        Log.i(logTag, "BottomToTopSwipe!");
        activity.onBottomToTopSwipe(v);
    }
    
    public boolean onTouch(View v, MotionEvent event) {
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN: {
                downX = event.getX();
                downY = event.getY();
                return true;
            }
            case MotionEvent.ACTION_UP: {
                upX = event.getX();
                upY = event.getY();
                float deltaX = downX - upX;
                float deltaY = downY - upY;
    
                    if (deltaX < 0 ) {
                        this.onLeftToRightSwipe(v);
                        return true;
                    }
                    if (deltaX > 0 ) {
                        this.onRightToLeftSwipe(v);
                        return true;
                    }
    
                    if (deltaY < 0) {
                        this.onTopToBottomSwipe(v);
                        return true;
                    }
                    if (deltaY > 0) {
                        this.onBottomToTopSwipe(v);
                        return true;
                    }
    
            }
        }
        return false;
    }
    
    public void setSwipeRestrictions(int swipeRestrictionX, int swipeRestrictionY) {
        this.swipeRestrictionX = swipeRestrictionX;
        this.swipeRestrictionY = swipeRestrictionY;
    }
    

    2) 具有以下引用的接口

        public interface SwipeListenerInterface {
    
        void onRightToLeftSwipe(View v);
    
        void onLeftToRightSwipe(View v);
    
        void onTopToBottomSwipe(View v);
    
        void onBottomToTopSwipe(View v);
    }
    

    3)创建对象并将其绑定到您的overlayView(确保将界面调整为overLay view,以便它可以接收回调)

        sl = new SwipeListener(this);
        overlayView.setOnTouchListener(sl);
    

    【讨论】:

      【解决方案5】:

      SwipeBack 是一个 android 库,Activities 的功能与 android 的“后退按钮”几乎相同,但使用滑动手势以非常直观的方式。

      从 Maven 中心获取它

      compile 'com.hannesdorfmann:swipeback:1.0.4'

      创建一个基础活动并记下方法

       public void initDrawerSwipe(int layoutId) {
              SwipeBack.attach(this, Position.LEFT)
                      .setContentView(layoutId)
                      .setSwipeBackView(R.layout.layout_swipe_back)
                      .setSwipeBackTransformer(new SlideSwipeBackTransformer() {
                          @Override
                          public void onSwipeBackCompleted(SwipeBack swipeBack, Activity activity) {
                              supportFinishAfterTransition();
                          }
                      });
          }
      

      然后将您的布局 id 传递给放置在您的基本活动中的方法

         @Override
          protected void onCreate(@Nullable Bundle savedInstanceState) {
              super.onCreate(savedInstanceState);
              initDrawerSwipe(R.layout.activity_stylists);
           }
      

      这适用于您在查询中指出的所有情况。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-02-17
        • 1970-01-01
        • 2015-07-10
        • 1970-01-01
        相关资源
        最近更新 更多