В конечном итоге деятельность по салфетки вправо?
Я должен закончить 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);
}
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
, а затем в конце Activity
. Однако теперь я могу обнаружить событие swipe на OverlayLayout
, но другие представления не могли ответить, хотя у меня было возвращение return super.onTouchEvent(event);
в else condition of onTouchEvent
, так как вы можете найти его в моем коде. Кто-нибудь, пожалуйста, помогите мне это сделать. Я приколол сюда и очень взволнован, чтобы узнать трюк:)
Ответы
Ответ 1
То, что вы пытаетесь сделать, это в основном поведение по умолчанию в Android Wear, и это считается стандартной практикой в Android Watches
для выхода из приложения. В Android Wear DismissOverlayView делает всю тяжелую работу за вас.
Смартфоны имеют кнопку "назад", в то время как для "износа" требуется длительное нажатие или режим отклонения для выхода из экрана. Вы должны отклонить активность при нажатии на спину, смешивание рисунка износа в 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 {
Преимущества этого способа
- Чисто УПС подход
- Чистый код - не нужно писать прослушиватель смахивания для каждого типа макета, используемого в проекте (относительный, линейный и т.д.)
- Отлично работает в ScrollView
Ответ 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
Я столкнулся с той же проблемой в отношении наложения активности. Это сработало для меня
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, чтобы он мог получать обратные вызовы)
sl = new SwipeListener(this);
overlayView.setOnTouchListener(sl);
Ответ 4
Я считаю, что проблема, с которой вы сталкиваетесь с RecyclerView и ScrollView, связана с дочерними элементами, получающими фокус перед родителями. вы можете попробовать установить android:descendantFocusability="beforeDescendants"
для просмотра Recycler/Scroll.
Ответ 5
SwipeBack - это андроидная библиотека для Activities
, чтобы сделать то же самое, что и "back-button" андроида, но по-настоящему интуитивно понятным способом, используя жестом салфетки.
Получить его из центра 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();
}
});
}
Затем передайте свой идентификатор макета методу, который был помещен в вашу базовую активность.
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
initDrawerSwipe(R.layout.activity_stylists);
}
Это хорошо работает во всех сценариях, которые вы указали в своем запросе.
Ответ 6
Если вы заинтересованы в использовании lib, используйте это https://github.com/gongwen/SwipeBackLayout