Я должен закончить действие, когда пользователь предлагает правильное прокручивание в любом месте экрана. Я попытался с GestureDetector
и это прекрасно работает, если в ScrollView
нет ни 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); }
OverlayLayout
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
затем OverlayLayout
действие. Однако теперь я могу обнаружить событие swipe на OverlayLayout
но другие представления не могли ответить, хотя у меня возвращался return super.onTouchEvent(event);
В противном случае условие onTouchEvent
как вы можете найти его в моем коде. Любой, пожалуйста, помогите мне это сделать. Я приколол сюда и очень взволнован, чтобы узнать трюк 🙂
То, что вы пытаетесь сделать, – это, по сути, поведение по умолчанию в Android Wear, и оно рассматривается как стандартная практика в Android Watches
для существования и приложения. В одежде Android DismissOverlayView делает все тяжелый подъем для вас.
Смартфоны имеют кнопку «Назад», а Wear полагаются на длительное нажатие или прокрутку, чтобы выйти из экрана. Вы должны уволить деятельность на заднем прессе, смешивая модель износа в Android. Смартфоны будут путать пользователя. По крайней мере, покажите предупреждение, чтобы избежать случайного выхода.
Решение
Поскольку я вижу, что этот вопрос отмечен с помощью Android 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 {
Преимущества этого способа
Попробуйте это, я использую функцию для прокрутки
Просмотр для прокрутки …
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; } }
Я столкнулся с той же проблемой в отношении Наложения активности. Это сработало для меня
1) Определите, что вы SwipeListener
Открытый класс SwipeListener реализует 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, чтобы он мог получать обратные вызовы)
sl = new SwipeListener(this); overlayView.setOnTouchListener(sl);
Я считаю, что проблема, с которой вы сталкиваетесь с RecyclerView и ScrollView, связана с тем, что дочерние элементы получают фокус перед родителями. Вы можете попытаться установить android:descendantFocusability="beforeDescendants"
для просмотров Recycler / Scroll.
SwipeBack – это андроидная библиотека, предназначенная для того, чтобы действия были такими же, как и «back-button» андроида, но по-настоящему интуитивно понятным способом с помощью жестового салфетки.
Получите его от центрального центра
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(); } }); }
Затем передайте свой идентификатор макета методу, который помещен в вашу базовую активность
@Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); initDrawerSwipe(R.layout.activity_stylists); }
Это хорошо работает во всех сценариях, которые вы указали в своем запросе.