我想在查看页面2中禁用从右向左滑动。我基本上有一个viewpager2元素,在导航抽屉中有两页。我希望我的第二页仅在单击第一页中的某个元素时显示(从第一页向右向左滑动不应打开第二页),而当我在第二页时,viewpager2滑动(从左向右滑动)应像在viewpager中一样滑动。
我尝试过扩展ViewPager2
类并覆盖触摸事件,但不幸的是它ViewPager2
是最终类,因此我无法扩展它。
其次,我尝试使用将userinputened设置为false的方法,但这完全禁用了所有滑动(我只想禁用从右向左滑动)。如果我能找到一些监听器,在刷卡之前检查当前页面,否则禁用刷卡,它可能会工作。
implementation 'androidx.viewpager2:viewpager2:1.0.0-alpha05'
ViewPager2设置代码
ViewPager2 pager = view.findViewById(R.id.pager);
ArrayList<Fragment> abc = new ArrayList<>();
abc.add(first);
abc.add(second);
navigationDrawerPager.setAdapter(new DrawerPagerAdapter(
this, drawerFragmentList));
pager.setAdapter(new FragmentStateAdapter(this), abc);
2个以上片段的最简单解决方案:
int previousPage = 0;
pager.registerOnPageChangeCallback(new ViewPager2.OnPageChangeCallback() {
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
super.onPageScrolled(position, positionOffset, positionOffsetPixels);
if(position < previousPage){
pager.setCurrentItem(previousPage, false);
} else {
previousPage = position;
}
}
});
2个以上碎片的解决方案。(向下滚动查看解决方案,最后更新代码以更正某些错误。)
这个有点棘手。
我认为,人们之所以希望在一个方向上禁用滑动,是因为在运行时无法添加片段,同时保持先前显示片段的状态。
因此,人们所做的是预加载所有片段,使其看起来好像没有显示的片段根本就不存在。
现在,如果团队使适配器不受ViewLifeCycle的限制,那么可以通过使用ListDifference选项轻松解决这一问题,该选项将正确地将更新传播到RecyclerView适配器,但由于ViewPager2的每个dataSetChanged都需要一个新适配器,因此需要重新创建整个片段,ListDifference对ViewPager2没有影响。
但可能不完全是因为我不确定ListDifference是否能够识别“头寸互换”以保持状态。
现在,关于建议使用registerOnPageChangeCallback()的答案。
使用超过2个片段注册registerOnPageChangeCallback()是无用的,这是因为当调用此方法时,已经太晚了,无法执行某些操作,这会导致窗口中途变得无响应,而不是addOnItemTouchListener();它能够在触摸到达视图之前拦截触摸。
在某种意义上,阻止和允许刷卡的完整事务将由两个方法执行,registerOnPageChangeCallback()和addOnItemTouchListener()。
registerOnPageChangeCallback()
将告诉我们的适配器应该停止工作的方向(通常从左到右(我简单地称之为“左”))以及在什么页面,而addOnItemTouchListener()
将告诉视图在我们想要的方向上的正确时刻拦截抛投。
问题是,要使用TouchListener,我们需要访问ViewPager2中的内部回收器视图。
实现这一点的方法是重写来自碎片状态适配器(FragmentStateAdapter)的onAttachedToWindow()方法。
@Override
public void onAttachedToRecyclerView(@NonNull RecyclerView recyclerView) {
super.onAttachedToRecyclerView(recyclerView);
}
现在要附加到RecyclView的正确侦听器称为RecyclView。SimpleOnItemTouchListener()
,问题是侦听器无法区分“右”和“左”。
public boolean onInterceptTouchEvent(@NonNull RecyclerView rv, @NonNull MotionEvent e)
我们需要混合两种行为以获得期望的结果:
a)rv.getScrollState()==RecyclView.SCROLL_STATE_DRAGGING
b) e.getX()
我们还需要跟踪最后一个x点,之所以这样做是因为侦听器会在rv之前多次触发。getScrollState()
旋转滚动\u状态\u拖动
。
解决方案。
我用来从左到右标识的类:
public class DirectionResolver {
private float previousX = 0;
public Direction resolve(float newX) {
Direction directionResult = null;
float result = newX - previousX;
if (result != 0) {
directionResult = result > 0 ? Direction.left_to_right : Direction.right_to_left ;
}
previousX = newX;
return directionResult;
}
public enum Direction {
right_to_left, left_to_right
}
}
因为resolve()方法在rv之前至少执行了3次以上,所以不需要在事务之后加上previousX int。getScrollState()变为拖动时的滚动状态
定义此类后,整个代码应如下所示(在FragmentStateAdapter中):
private final DirectionResolver resolver = new DirectionResolver();
private final AtomicSupplier<DirectionResolver.Direction> directionSupplier = new AtomicSupplier<>();
@Override
public void onAttachedToRecyclerView(@NonNull RecyclerView recyclerView) {
recyclerView.addOnItemTouchListener(
new RecyclerView.SimpleOnItemTouchListener(){
@Override
public boolean onInterceptTouchEvent(@NonNull RecyclerView rv, @NonNull MotionEvent e) {
boolean shouldIntercept = super.onInterceptTouchEvent(rv, e);
DirectionResolver.Direction direction = directionSupplier.get();
if (direction != null) {
DirectionResolver.Direction resolved = resolver.resolve(e.getX());
if (rv.getScrollState() == RecyclerView.SCROLL_STATE_DRAGGING) {
//resolved will never be null if state is already dragging
shouldIntercept = resolved.equals(direction);
}
}
return shouldIntercept;
}
}
);
super.onAttachedToRecyclerView(recyclerView);
}
public void disableDrag(DirectionResolver.Direction direction) {
Log.println(Log.WARN, TAG, "disableDrag: disabling swipe: " + direction.name());
directionSupplier.set(() -> direction);
}
public void enableDrag() {
Log.println(Log.VERBOSE, TAG, "enableDrag: enabling swipe");
directionSupplier.set(() -> null);
}
如果你问什么是AtomicSupplier,它类似于AtomicReference
我们需要检查空值,因为供应商第一次将为空(除非您将其设置为初始值),回收器视图首先附加到窗口。
现在使用它。
binding.journalViewPager.registerOnPageChangeCallback(
new ViewPager2.OnPageChangeCallback() {
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
if (conditionToDisableLeftSwipe.at(position)) {
adapter.disableDrag(DirectionResolver.Direction.right_to_left);
} else {
adapter.enableDrag();
}
}
}
}
);
已经对DirectionResolver.class进行了一些更新,以解决中小企业错误和更多功能:
private static class DirectionResolver {
private float previousX = 0;
private boolean right2left;
public Direction resolve(float newX) {
Direction directionResult = null;
float result = newX - previousX;
if (result != 0) {
directionResult = result > 0 ? Direction.left_to_right : Direction.right_to_left;
} else {
directionResult = Direction.left_and_right;
}
previousX = newX;
return right2left ? Direction.right_to_left : directionResult;
}
public void reset(Direction direction) {
previousX = direction == Direction.left_to_right ? previousX : 0;
}
public void reset() {
right2left = false;
}
}
方向枚举:
public enum Direction {
right_to_left, left_to_right, left_and_right;
//Nested RecyclerViews generate a wrong response from the resolve() method in the direction resolver.
public boolean equals(Direction direction, DirectionResolver resolver) {
boolean result = direction == left_and_right || super.equals(direction);
resolver.right2left = !result && direction == left_to_right;
return result;
}
}
实施:
@Override
public void onAttachedToRecyclerView(@NonNull RecyclerView recyclerView) {
recyclerView.addOnItemTouchListener(
new RecyclerView.SimpleOnItemTouchListener(){
@Override
public boolean onInterceptTouchEvent(@NonNull RecyclerView rv, @NonNull MotionEvent e) {
boolean shouldIntercept = super.onInterceptTouchEvent(rv, e);
Direction direction = directionSupplier.get();
if (direction != null) {
Direction resolved = resolver.resolve(e.getX());
if (rv.getScrollState() == RecyclerView.SCROLL_STATE_DRAGGING) {
//resolved will never be null if state is already dragging
shouldIntercept = resolved.equals(direction, resolver);
resolver.reset(direction);
}
}
return shouldIntercept;
}
}
);
super.onAttachedToRecyclerView(recyclerView);
}
public void disableDrag(Direction direction) {
directionSupplier.set(() -> direction);
resolver.reset();
}
public void enableDrag() {
directionSupplier.set(() -> null);
}
使用:
binding.journalViewPager.registerOnPageChangeCallback(
new ViewPager2.OnPageChangeCallback() {
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
if (conditionToDisableLeftSwipe.at(position)) {
adapter.disableDrag(DirectionResolver.Direction.right_to_left);
} else {
adapter.enableDrag();
}
}
}
}
);
我找到了一个监听器,当用户尝试滑动时可以监听,然后它会检查当前页面,如果它是第一页,则禁用用户输入,否则按默认情况启用它。
下面是这方面的代码片段
在Java中:
pager.registerOnPageChangeCallback(new ViewPager2.OnPageChangeCallback() {
@Override
public void onPageScrollStateChanged(int state) {
super.onPageScrollStateChanged(state);
if (state == SCROLL_STATE_DRAGGING && pager.getCurrentItem() == 0) {
pager.setUserInputEnabled(false);
} else {
pager.setUserInputEnabled(true);
}
}
});
静态编程语言:
viewPager.registerOnPageChangeCallback(object : OnPageChangeCallback() {
override fun onPageScrollStateChanged(state: Int) {
super.onPageScrollStateChanged(state)
viewPager.isUserInputEnabled = !(state == SCROLL_STATE_DRAGGING && viewPager.currentItem == 0)
}
})
由于我的场景只有2页,检查页码对我有好处,但如果我们有超过2页并且我们需要禁用在一个特定方向上的滑动,我们可以使用onPageScrolled(int位置,浮点位置偏移,int位置偏移Pixels)
viewpage er2
的监听器,并根据位置
和的正负值处理所需的场景。
我想禁用刷卡,但仅限于右侧。我在这个答案中找到了一个有效的解决方案。不幸的是,这复制了整个源代码以实现目标。有没有只继承现有类而不复制的方法?
问题内容: 在这里四处寻找了一段时间,但似乎找不到有效的解决方案。 我试图在Swift中禁用滑动以返回到上一个视图手势。 我尝试了多种解决方案,包括: 和 是否有执行此操作的新方法或其他可行的方法? 问题答案: 您可以禁用它,但是不建议这样做,因为大多数iOS用户通过滑动来回退,而通过按后退按钮可以减少回退。如果要禁用它,则使用a 代替推送转移(不是很大的转移)更为合理。如果您真的想摆脱滑动返回功
如何阻止viewpager仅向一个方向滚动。例如,只允许向右滑动,而不允许向左滑动。我完全被卡住了,任何帮助都将不胜感激。要注意的是,我需要让它在Android 2.2版上工作,所以我使用ViewPager的兼容性库。 提前感谢
我有一个Recyerview。RecycerView的每个单元格都有一个关联的文件。我正在使用ItemTouchHelper进行刷屏。当用户刷一个单元格时,我希望禁用其他单元格的刷,只要与被刷单元格相关联的文件没有被删除。如何在特定时间内启用和禁用刷屏。我在堆栈上看了关于这个的问题,但他们大多回答了如何禁用特定位置的滑动,这是我不想要的。
我已将ViewPager2与Tablayout连接。其他引用ViewPager的帖子提供了覆盖setCurrentItem(position,false)的方法,其中false禁用平滑滚动。但是,TabLayoutMediator调用OntabSelect(tablayout.tab tab),后者调用viewPager.setCurrentItem(postion,true)。如果TabLayo
问题内容: 我正在使用无状态Spring Security,但是如果要注册,我想禁用Spring Security。我禁用了 但它不起作用,我在下面收到错误消息: 我认为这意味着弹簧安全过滤器正在工作 我的网址顺序始终为“ / api / v1” 我的spring配置是 我的身份验证过滤器是 我的控制器是 我怎么做? 问题答案: 使用它意味着每个经过身份验证的用户,但是你禁用了匿名访问,因此将无法