【问题标题】:Touch Listener interferes with RecyclerView ScrollingTouch Listener 干扰 RecyclerView 滚动
【发布时间】:2020-05-23 11:32:43
【问题描述】:

我的应用如下所示:

基本上是一个框架布局,用于托管片段和底部导航视图。现在我想在家庭内实施右滑动手势(选择了主页选项卡时)。但是该片段托管了一个 RecyclerView。要添加向右滑动,我正在使用:

public class OnSwipeTouchListener implements View.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 GestureDetector.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() {
    }
}

当我将此触摸侦听器添加到 RecyclerView 时,滚动不会顺利进行。我不知道这背后的原因。如果有请说明。

现在请建议我应该怎么做才能克服这个问题。有没有其他方法可以设置触摸侦听器和手势侦听器,以便滚动不会受到阻碍以及我可以检测到向右滑动手势。

作为一种解决方法,我尝试在 recyclerview 上方设置一个完全透明的视图,它检测到手势但 recyclerview 不滚动。

【问题讨论】:

  • 我不明白,你想在 recyclerview 或框架布局上添加监听器?
  • @Avinash 基本上我想在 HomeFragment 上添加这个。所以无论是在 RV 还是 FrameLayout 上。我只希望当用户在该特定片段中向右滑动时,我会收到一个事件。
  • 每个片段上显示的回收器视图?
  • @Avinash 不,只有一个片段。
  • 您是将触摸监听器放置在 RecyclerView 本身还是每个视图持有者(或其他地方)上?

标签: android android-recyclerview


【解决方案1】:

您可以使用 ViewPager 更改您的 FrameLayout,并为滑动操作添加监听器

将 FrameLayout 更改为 ViewPager

 <android.support.v4.view.ViewPager
    android:id="@+id/pager"
    android:layout_width="match_parent"
    android:layout_height="fill_parent"
    android:layout_below="@id/tab_layout"/>

实现 PagerAdapter

public class PagerAdapter extends FragmentStatePagerAdapter {
int fragmentNumber;

public PagerAdapter(FragmentManager fm, int fragmentNumber) {
    super(fm);
    this.fragmentNumber = fragmentNumber;
}

/**
 * Return the Fragment associated with a specified position.
 *
 * @param position
 */
@Override
public Fragment getItem(int position) {
    switch (position) {
        case 0:
            return new Fragment1();
        case 1:
            return new Fragment2();
        case 2:
            return new Fragment3();
        case 3:
            return new Fragment4();
        case 4:
            return new Fragment5();
        default:
            return null;
    }
}


/**
 * Return the number of views available.
 */
@Override
public int getCount() {
    return fragmentNumber;
}
}

MainActivity 逻辑

 @Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    ViewPager viewPager = findViewById(R.id.pager);
    final PagerAdapter adapter = new PagerAdapter
            (getSupportFragmentManager(), 5); //Change the number based on the number of Fragments you have
    viewPager.setAdapter(adapter);
    viewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
        @Override
        public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
            // put your scrolling logic here. use positionOffset and position to determine the next destination
        }

        @Override
        public void onPageSelected(int position) {

        }

        @Override
        public void onPageScrollStateChanged(int state) {

        }
    });
}

您还可以将 viewPager 与 bottomNavigation 连接以保持一致性 并且可以根据您的具体情况改进这些代码:跟踪不可见的片段而不是扭曲它们......

我希望这会有所帮助。

【讨论】:

    【解决方案2】:

    尝试在 onCreateViewHold() 中展开的视图上设置监听器。类似的东西

    public @NonNull
    RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.row_message, parent, false);
        view.setOnTouchListener(new OnSwipeTouchListener(view.getContext()));
        return new ItemViewHolder(view);
    }
    

    从 RecyclerView 本身移除监听器。

    【讨论】:

    • 很好,尽管我还必须将侦听器添加到大多数视图中。由于项目很大,我希望更多地测试这种方法的稳定性,然后奖励赏金。
    【解决方案3】:

    我不太确定您想要什么,但可以在 android 片段中使用向左或向右滑动功能。您可以在 MainActivity 中使用 viewPager.setCurrentItem() 将当前页面设置为最后一页。 ViewPager 是允许用户向左或向右滑动以查看全新屏幕的小部件。我希望这可以帮助你。

    【讨论】:

    • 我知道这一点,但问题是主屏幕是一个活动而不是片段,否则我可以轻松地将它们放在 ViewPager 中并且导航将被处理。代码库太大了,我避免将主屏幕从活动更改为片段。
    • 所以您在底部导航中的所有项目都使用活动而不是片段?
    • 没有。对于这些项目,我使用片段,而对于完整视图,我使用活动。所以基本上在活动内部,我有视图和底部导航视图。对于使用 ViewPager,我猜这整件事应该是一个片段。
    • 是的,应该是这样。你有一个活动,在那个活动中你可以有多个片段。如果这就是您的设置方式,那么您只需要一个 viewpager,您可以在托管所有片段的 Activity 类中初始化它。然后,如果您使用 setCurrentItem() 方法,您可以在该活动内的这些片段中向左或向右滑动。我希望我说得通。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-11-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-11-10
    相关资源
    最近更新 更多