【问题标题】:Dismiss Snackbar On left swipe关闭 Snackbar 向左滑动
【发布时间】:2016-05-23 05:19:23
【问题描述】:

下面用于显示 Snackbar 的简单代码。

public void onClick(View view) {
       Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_INDEFINITE)
               .setAction("Action", null).show();
}

onClick 事件发生时,此代码正确显示 Snackbar。

此外,此小吃栏可以通过滑动手势关闭。

但默认情况下,只有 右滑 会关闭 Snackbar。而且我无法通过向左滑动将其关闭。

如何在向左滑动时关闭快餐栏?

【问题讨论】:

  • 你找到解决办法了吗?
  • @JakubHolovsky 没有。如您所见,此帖子下方没有发布答案。它已经快 6 个月大了......所以我认为这是目前的平台限制。
  • Snackbar 需要一个 CoordinatorLayout 作为其根布局或在其顶部的某个位置,以执行其各种操作,例如 滑动关闭。你可以找到类似的问题here
  • @AADTechnical 嗨,您想在向左滑动或向右滑动等相同动画时关闭它?
  • @Charuka 好的,我会试试你的代码

标签: android onclick android-snackbar


【解决方案1】:

希望这会有所帮助:

OnSwipeTouchListener.java:

import android.view.GestureDetector;
import android.view.GestureDetector.SimpleOnGestureListener;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnTouchListener;

public class OnSwipeTouchListener implements OnTouchListener {

    private final GestureDetector gestureDetector;

    public OnSwipeTouchListener (Context ctx){
        gestureDetector = new GestureDetector(ctx, new GestureListener());
    }

    @Override
    public boolean onTouch(View v, MotionEvent event) {
        return gestureDetector.onTouchEvent(event);
    }

    private final class GestureListener extends SimpleOnGestureListener {

        private static final int SWIPE_THRESHOLD = 100;
        private static final int SWIPE_VELOCITY_THRESHOLD = 100;

        @Override
        public boolean onDown(MotionEvent e) {
            return true;
        }

        @Override
        public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
            boolean result = false;
            try {
                float diffY = e2.getY() - e1.getY();
                float diffX = e2.getX() - e1.getX();
                if (Math.abs(diffX) > Math.abs(diffY)) {
                    if (Math.abs(diffX) > SWIPE_THRESHOLD && Math.abs(velocityX) > SWIPE_VELOCITY_THRESHOLD) {
                        if (diffX > 0) {
                            onSwipeRight();
                        } else {
                            onSwipeLeft();
                        }
                    }
                    result = true;
                } 
                else if (Math.abs(diffY) > SWIPE_THRESHOLD && Math.abs(velocityY) > SWIPE_VELOCITY_THRESHOLD) {
                        if (diffY > 0) {
                            onSwipeBottom();
                        } else {
                            onSwipeTop();
                        }
                    }
                    result = true;

            } catch (Exception exception) {
                exception.printStackTrace();
            }
            return result;
        }
    }

    public void onSwipeRight() {
    }

    public void onSwipeLeft() {
    }

    public void onSwipeTop() {
    }

    public void onSwipeBottom() {
    }
}

如何使用:在 MainActivity

 public class MainActivity extends AppCompatActivity {
    CoordinatorLayout coordinatorLayout;

    private Snackbar snackbar;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        coordinatorLayout = (CoordinatorLayout)findViewById(R.id.coordinatorLayout); 

        snackbar = Snackbar
                .make(coordinatorLayout, "Replace with your own action", Snackbar.LENGTH_INDEFINITE)
                .setAction("RETRY", null);

        snackbar.setActionTextColor(Color.RED);

        View sbView = snackbar.getView();
        TextView textView = (TextView) sbView.findViewById(android.support.design.R.id.snackbar_text);
        textView.setTextColor(Color.YELLOW);
        snackbar.show();

        textView.setOnTouchListener(new OnSwipeTouchListener(MainActivity.this)
        {
            public void onSwipeTop() {

            }
            public void onSwipeRight() {

            }
            public void onSwipeLeft() {
                snackbar.dismiss();
            }
            public void onSwipeBottom() {

            }
        });

    }
}

【讨论】:

  • 什么是 SWIPE_VELOCITY_THRESHOLD 和 SWIPE_THRESHOLD?
  • @SubanDhyako 其为手势阈值,这样蛇条如果仅触摸就不会直接关闭
【解决方案2】:

这将在向左滑动时关闭 snackBar(但在向左滑动时没有该动画)

  • 使用getView() 并采用snackBar 布局
  • 使用setOnTouchListener
  • 检测移动并执行您的操作

完成了!

public class HomeActivity extends AppCompatActivity {

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

            @Override
            protected void onCreate(Bundle savedInstanceState) {
                super.onCreate(savedInstanceState);
                setContentView(R.layout.activity_home);

                RelativeLayout relativeLayout = (RelativeLayout) findViewById(R.id.rel);

                final Snackbar snackbar = Snackbar.make(relativeLayout, "Helloo", Snackbar.LENGTH_INDEFINITE);
                Snackbar.SnackbarLayout layout = (Snackbar.SnackbarLayout) snackbar.getView();
                layout.setOnTouchListener(new View.OnTouchListener() {
                    @Override
                    public boolean onTouch(View v, 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)
                                    {// Left to Right swipe action
                                        if (x2 > x1)
                                        {
                                            Toast.makeText(HomeActivity.this, "Left to Right swipe ", Toast.LENGTH_SHORT).show ();
                                        }
                                        // Right to left swipe action
                                        else
                                        {
                                            Toast.makeText(HomeActivity.this, "Right to Left swipe ", Toast.LENGTH_SHORT).show ();
                                            snackbar.dismiss();
                                        }
                                    }
                                    else
                                    {
                                        Toast.makeText(HomeActivity.this, "Tap or Else", Toast.LENGTH_SHORT).show ();
                                    }
                                    break;
                            }

                        return false;
                    }
                });
                snackbar.show();
            }
        }

【讨论】:

    【解决方案3】:

    在 cmets 中有人建议使用CoordinatorLayout.Behavior,这是正确的方法。自己处理触摸事件几乎是个好主意,但不是正确的方法,因为它会“破坏” Snackbar 及其管理器的内部实现。

    您需要在调用 show() 方法后替换默认的 SwipeToDismissBehaviorSnackbar

         Snackbar snackbar = Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_INDEFINITE)
               .setAction("Action", null).show();
        View snackBarView = snackbar.getView();
        final ViewGroup.LayoutParams lp = snackBarView.getLayoutParams();
        if (lp instanceof CoordinatorLayout.LayoutParams) {
            final CoordinatorLayout.LayoutParams layoutParams = (CoordinatorLayout.LayoutParams) lp;
            final SwipeDismissBehavior<Snackbar.SnackbarLayout> behavior = new SwipeDismissBehavior<Snackbar.SnackbarLayout>();
            behavior.setStartAlphaSwipeDistance(0.1f);
            behavior.setEndAlphaSwipeDistance(0.6f);
            behavior.setSwipeDirection(SwipeDismissBehavior.SWIPE_DIRECTION_END_TO_START);
            behavior.setListener(new SwipeDismissBehavior.OnDismissListener() {
                @Override
                public void onDismiss(View view) {
                    snackbar.dismiss();
                }
    
                @Override
                public void onDragStateChanged(int state) {
                    switch (state) {
                        case SwipeDismissBehavior.STATE_DRAGGING:
                        case SwipeDismissBehavior.STATE_SETTLING:
                            snackbar.show();
                            break;
                        case SwipeDismissBehavior.STATE_IDLE:
                            break;
                    }
                }
            });
            layoutParams.setBehavior(behavior);
        }
    

    或更短的方法:

        View snackBarView = snackbar.getView();
        final ViewGroup.LayoutParams lp = snackBarView.getLayoutParams();
        if (lp instanceof CoordinatorLayout.LayoutParams) {
            final CoordinatorLayout.LayoutParams layoutParams = (CoordinatorLayout.LayoutParams) lp;
            CoordinatorLayout.Behavior behavior = layoutParams.getBehavior();
            if(behavior instanceof SwipeDismissBehavior){
                ((SwipeDismissBehavior) behavior).setSwipeDirection(SwipeDismissBehavior.SWIPE_DIRECTION_END_TO_START); // or SwipeDismissBehavior.SWIPE_DIRECTION_ANY
            }
            layoutParams.setBehavior(behavior);
        }
    

    【讨论】:

    • 到目前为止,您的较短方法似乎是所有答案中的最佳选择。
    • 对较短方法的警告。代码的 sn-p 需要在onShown(Snackbar) 回调中运行。如果在此之前运行,getBehavior() 将返回 null。
    • 有效。最好和干净的方法与@Benjamin 的onShown 中的评论一起使用
    【解决方案4】:

    另一种简单且更简洁的方法如下:

    val behavior = BaseTransientBottomBar.Behavior().apply {
        setSwipeDirection(SwipeDismissBehavior.SWIPE_DIRECTION_ANY)
    }
    Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_INDEFINITE)
        .setBehavior(behavior)
        .show()
    

    有了这个,你不需要检查和转换布局参数,也不需要使用onShown 回调。

    【讨论】:

    • 完美的答案是最简单的
    猜你喜欢
    • 2016-12-13
    • 2013-07-05
    • 1970-01-01
    • 2012-08-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-08-25
    • 2020-05-22
    相关资源
    最近更新 更多