Пролистайте направление в ViewPager
У меня есть приложение для Android, которое использует ViewPager и FragmentStatePagerAdapter. Однако мне нужно добавить новую функцию, в которой я должен знать направление пролистывания, чтобы перейти от одного фрагмента к другому, левому или правому. (то есть, когда я проведу пальцем влево, я сделаю одну вещь, а когда я проведу пальцем вправо, я сделаю что-нибудь еще)
Пожалуйста, обратите внимание, что мне не нужно, чтобы события происходили ПОСЛЕ того, как проведено сканирование. Я должен сделать те события, когда происходит свайп. Я думал об использовании setOnPageChangeListener()
но это не говорит мне направление удара. Можете ли вы посоветовать мне, пожалуйста, как определить направление движения?
Благодарю.
10 ответов
Я столкнулся с этой проблемой, и мне нужно знать направление удара, как это происходило, чтобы предотвратить движение в определенном направлении. Вот как я решил свою проблему, надеюсь, она кому-нибудь пригодится. Я нашел все предыдущие примеры неэффективными для того, что мне нужно.
Если вы подкласс своего ViewPager, вы можете ответить на onInterceptTouchEvent(MotionEvent event)
а также onTouchEvent(MotionEvent event)
методы ViewPager
@Override
public boolean onInterceptTouchEvent(MotionEvent event) {
boolean wasSwipeToRight = this.wasSwipeToRightEvent(event));
// Do what you want here with left/right swipe
return super.onInterceptTouchEvent(event);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
boolean wasSwipeToRight = this.wasSwipeToRightEvent(event));
// Do what you want here with left/right swipe
return super.onTouchEvent(event);
}
Вот метод, который вызывается для определения направления события.
// Stores the starting X position of the ACTION_DOWN event
float downX;
/**
* Checks the X position value of the event and compares it to
* previous MotionEvents. Returns a true/false value based on if the
* event was an swipe to the right or a swipe to the left.
*
* @param event - Motion Event triggered by the ViewPager
* @return - True if the swipe was from left to right. False otherwise
*/
private boolean wasSwipeToRightEvent(MotionEvent event){
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
downX = event.getX();
return false;
case MotionEvent.ACTION_MOVE:
case MotionEvent.ACTION_UP:
return downX - event.getX() > 0;
default:
return false;
}
}
Это достаточно просто с введением переменной экземпляра, чтобы отслеживать текущую страницу.
public class MyActivity extends Activity implements ViewPager.OnPageChangeListener {
private ViewPager viewPager;
private int currentPosition;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Do trivial stuff
.
.
.
viewPager.setOnClickListener(this); // doesnt have to be in onCreate
}
@Override
public void onPageSelected(int position) {
if(currentPosition < position) {
// handle swipe LEFT
} else if(currentPosition > position){
// handle swipe RIGHT
}
currentPosition = position; // Update current position
}
}
Посмотрите на onPageSelected(int position)
метод ViewPager.OnPageChangeListener. position
дает индекс вновь выбранной страницы. Если вы отслеживаете текущий индекс страницы, то вы можете сравнить его с position
Индекс, чтобы получить левое / правое направление прокрутки.
Теперь, когда вы упомянули, что OnPageChangeListener не помогает, рассмотрим onInterceptTouchEvent (MotionEvent ev)
метод ViewPager
, Примите во внимание ACTION_DOWN, ACTION_MOVE и ACTION_UP MotionEvent. Надеюсь это поможет.
Я использую эту маленькую реализацию, чтобы определить, выполняет ли пользователь прокрутку вправо или влево во время самой прокрутки. У меня могут быть некоторые ошибки в определенных условиях, о которых я не знаю, но это то, что я могу придумать для того, что мне нужно, без необходимости добавления сенсорного прослушивателя:
viewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
int SCROLLING_RIGHT = 0;
int SCROLLING_LEFT = 1;
int SCROLLING_UNDETERMINED = 2;
int currentScrollDirection = 2;
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
if (isScrollDirectionUndetermined()){
setScrollingDirection(positionOffset);
}
if (isScrollingLeft()){
Log.i("TabLayout","Scrolling LEFT");
}
if (isScrollingRight()){
Log.i("TabLayout","Scrolling RIGHT");
}
}
private void setScrollingDirection(float positionOffset){
if ((1-positionOffset)>= 0.5){
this.currentScrollDirection = SCROLLING_RIGHT;
}
else if ((1-positionOffset)<= 0.5){
this.currentScrollDirection = SCROLLING_LEFT;
}
}
private boolean isScrollDirectionUndetermined(){
return currentScrollDirection == SCROLLING_UNDETERMINED;
}
private boolean isScrollingRight(){
return currentScrollDirection == SCROLLING_RIGHT;
}
private boolean isScrollingLeft(){
return currentScrollDirection == SCROLLING_LEFT;
}
@Override
public void onPageSelected(int position) {
}
@Override
public void onPageScrollStateChanged(int state) {
if (state == ViewPager.SCROLL_STATE_IDLE){
this.currentScrollDirection = SCROLLING_UNDETERMINED;
}
}
});
Мы можем определить направление прокрутки, потому что когда пользователь прокручивает слева направо, positionOffset
идет от 0 -> 1, а при прокрутке справа налево - от 1 -> 0. Затем мы можем проверить это значение один раз в самом начале прокрутки и сбросить флаг только в конце прокрутки.
Мы устанавливаем currentScrollDirection
неопределенным в положении холостого хода вместо onPageSelected
так как onPageSelected
может быть вызван, если пользователь отпускает в середине прокрутки, а затем вы получите ложное чтение.
Может быть, вы можете создать слушателя так:
buttonIcons.setOnTouchListener(new OnTouchListener() {
@Override
public boolean onTouch(final View v, final MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
downX = event.getX();
return true;
case MotionEvent.ACTION_UP:
upX = event.getX();
final float deltaX = downX - upX;
if (deltaX > 0 && deltaX > SWIPE_MIN_DISTANCE) {
final Animation loadInAnimation = AnimationUtils
.loadAnimation(
activity.this,
R.anim.slide_in_right);
final Animation loadOutAnimation = AnimationUtils
.loadAnimation(
activity.this,
R.anim.slide_out_left);
viewFlipper.setInAnimation(loadInAnimation);
viewFlipper.setOutAnimation(loadOutAnimation);
viewFlipper.showPrevious();
startSaveButtonAnimation();
}
if (deltaX < 0 && -deltaX > SWIPE_MIN_DISTANCE) {
final Animation loadInAnimation = AnimationUtils
.loadAnimation(
activity.this,
R.anim.slide_in_left);
final Animation loadOutAnimation = AnimationUtils
.loadAnimation(
activity.this,
R.anim.slide_out_right);
viewFlipper.setInAnimation(loadInAnimation);
viewFlipper.setOutAnimation(loadOutAnimation);
viewFlipper.showNext();
startSaveButtonAnimation();
}
return true;
}
return false;
}
});
Используя Kotlin и ViewPager2, это мое решение, в котором вы можете зарегистрировать прослушиватель OnPageChangeCallback как фрагмент ниже (смахните только вправо)
val pager = rootView.findViewById<ViewPager2>(R.id.viewPager).apply {
registerOnPageChangeCallback(object : OnPageChangeCallback(){
var oldPosition = 0
override fun onPageScrolled(position: Int, positionOffset: Float, positionOffsetPixels: Int
) {
super.onPageScrolled(position, positionOffset, positionOffsetPixels)
if (position < oldPosition) {
setCurrentItem(oldPosition, false)
} else {
oldPosition = position
}
}
})
}
Вы можете добавить OnPageChangeListner к ViewPager и сделать что-то вроде этого:
mViewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
float tempPositionOffset = 0;
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
if (position == 0) {
if (tempPositionOffset < positionOffset) {
Log.d("eric", "scrolling left ...");
} else {
Log.d("eric", "scrolling right ...");
}
tempPositionOffset = positionOffset;
Log.d("eric", "position " + position + "; " + " positionOffset " + positionOffset + "; " + " positionOffsetPixels " + positionOffsetPixels + ";");
}
}
@Override
public void onPageSelected(int position) {
}
@Override
public void onPageScrollStateChanged(int state) {
}
});
Вы можете найти направление, используя параметры onPageScrolled
,
Следующий слушатель настроен на показ лог-сообщения один раз в каждом направлении изменения фрагмента сети (слева, если обнаружены фрагменты слева, в центре, если фрагменты не обнаружены, справа, если фрагмент справа обнаружен).
Переменные класса, нужно отслеживать
// -1 - left, 0 - center, 1 - right
private int scroll = 0;
// set only on `onPageSelected` use it in `onPageScrolled`
// if currentPage < page - we swipe from left to right
// if currentPage == page - we swipe from right to left or centered
private int currentPage = 0;
// if currentPage < page offset goes from `screen width` to `0`
// as you reveal right fragment.
// if currentPage == page , offset goes from `0` to `screen width`
// as you reveal right fragment
// You can use it to see
//if user continue to reveal next fragment or moves it back
private int currentOffset = 0;
// behaves similar to offset in range `[0..1)`
private float currentScale = 0;
Слушатель
pager.addOnPageChangeListener(
new OnPageChangeListener(){
@Override
public void onPageScrolled(int page, float scale, int offset){
if(scale != 0f && offset > 10){
if(currentOffset > offset && currentScale > scale && (page + 1) == currentPage){
if(scroll != -1){
newImageSet = true;
scroll = -1;
Log.e("scroll", "left");
}
} else if(currentOffset < offset && currentScale < scale && page == currentPage){
if(scroll != 1){
newImageSet = true;
scroll = 1;
Log.e("scroll", "right");
}
}
currentOffset = offset;
currentScale = scale;
}
@Override
public void onPageSelected(int i){
Log.e("scroll","centre");
// we are centerd, reset class variables
currentPage = i;
currentScale = 0;
currentOffset = 0;
scroll = 0;
}
@Override
public void onPageScrollStateChanged(int i){
}
}
);
Ты можешь использовать setOnPageChangeListener()
и правильно реализовать onPageScrolled(int position, float positionOffset, int positionOffsetPixels)
,
Вы можете определить направление по позиционированию и переменной положения:
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels)
{
if(position == mCurrentPosition && positionOffset > 0)
{
//swipe right
}
else if (positionOffset > 0)
{
//swipe left
}
}
Я сделал этот класс для ViewPager2. Просто создайте экземпляр и передайте егоviewpager2.registerOnPageChangeCallback
и не забудь позвонитьviewpager2.unregisterOnPageChangeCallback
!
public abstract class ViewPager2SwipeListener extends ViewPager2.OnPageChangeCallback {
private int prevPosition = -1;
private int state;
@Override
public void onPageScrolled(int newPosition, float positionOffset, int positionOffsetPixels) {
final boolean positionChanged = prevPosition != -1 && newPosition != prevPosition;
if (positionChanged && state != ViewPager2.SCROLL_STATE_IDLE) {
if (prevPosition < newPosition) {
onPageSwipeLeft(prevPosition, newPosition);
}
else {
onPageSwipeRight(prevPosition, newPosition);
}
}
prevPosition = newPosition;
}
@Override
public void onPageScrollStateChanged(int state) {
this.state = state;
}
public abstract void onPageSwipeRight(int prevPosition, int newPosition);
public abstract void onPageSwipeLeft(int prevPosition, int newPosition);
}