考虑以下场景:
我认为我的某些功能可以正常工作,但存在一些问题:
I think I got some functionality working, but it has some issues:
当我成功解决#2(或#3)时,这可能是一个问题.目前,我正在使用一个处理程序,该处理程序使用可运行文件并在内部调用此命令:
this can be an issue when I succeed solving #2 (or #3). For now, I'm using a handler that use a runnable and calls this command inside :
mViewPager.setCurrentItem((mViewPager.getCurrentItem() + 1) % mViewPager.getAdapter().getCount(), true);
我试过 这篇文章,但效果不佳,因为当用户在完成切换到另一个页面之前停止拖动时,它会遇到同样的问题.
I've tried this post, but it didn't work well, as it got the same issues when the user-dragging stops before finished swithching to another page.
唯一有效的类似解决方案是使用单个 ViewPager(这里),但我需要使用 2 个 ViewPagers,每个 ViewPagers 都会影响另一个.
Only similar solution that works, is with a single ViewPager (here), but I need to work with 2 ViewPagers, each affects the other.
所以我自己尝试过:假设一个 viewPager 是viewPager",另一个(应该遵循viewPager")是viewPager2",这就是我所做的:
So I've tried doing it myself: suppose one viewPager is "viewPager", and the other (that is supposed to follow "viewPager") is "viewPager2" , this is what I've done:
viewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
int lastPositionOffsetPixels=Integer.MIN_VALUE;
@Override
public void onPageScrolled(final int position, final float positionOffset, final int positionOffsetPixels) {
if (!viewPager2.isFakeDragging())
viewPager2.beginFakeDrag();
if(lastPositionOffsetPixels==Integer.MIN_VALUE) {
lastPositionOffsetPixels=positionOffsetPixels;
return;
}
viewPager2.fakeDragBy((lastPositionOffsetPixels - positionOffsetPixels) * viewPager2.getWidth() / viewPager.getWidth());
lastPositionOffsetPixels = positionOffsetPixels;
}
@Override
public void onPageSelected(final int position) {
if (viewPager2.isFakeDragging())
viewPager2.endFakeDrag();
viewPager2.setCurrentItem(position,true);
}
@Override
public void onPageScrollStateChanged(final int state) {
}
});
我选择使用假拖动是因为 甚至文档都说它可能对同样的场景有用:
I've chosen to use fake-dragging because even the docs say it could be useful for this exact same scenario :
如果您想同步ViewPager 与另一个视图的触摸滚动,同时仍然让 ViewPager 控制捕捉动作和投掷行为.(例如视差滚动选项卡.)调用 fakeDragBy(float) 来模拟实际的拖动动作.调用 endFakeDrag() 完成假拖动和必要时扔掉.
A fake drag can be useful if you want to synchronize the motion of the ViewPager with the touch scrolling of another view, while still letting the ViewPager control the snapping motion and fling behavior. (e.g. parallax-scrolling tabs.) Call fakeDragBy(float) to simulate the actual drag motion. Call endFakeDrag() to complete the fake drag and fling as necessary.
为了方便测试,这里有更多代码:
To make it easy to test, here's more code:
MainActivity.java
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
final ViewPager viewPager = (ViewPager) findViewById(R.id.viewPager);
final ViewPager viewPager2 = (ViewPager) findViewById(R.id.viewPager2);
viewPager.setAdapter(new MyPagerAdapter());
viewPager2.setAdapter(new MyPagerAdapter());
//do here what's needed to make "viewPager2" to follow dragging on "viewPager"
}
private class MyPagerAdapter extends PagerAdapter {
int[] colors = new int[]{0xffff0000, 0xff00ff00, 0xff0000ff};
@Override
public int getCount() {
return 3;
}
@Override
public void destroyItem(ViewGroup container, int position, Object object) {
((ViewPager) container).removeView((View) object);
}
@Override
public boolean isViewFromObject(final View view, final Object object) {
return (view == object);
}
@Override
public Object instantiateItem(final ViewGroup container, final int position) {
TextView textView = new TextView(MainActivity.this);
textView.setText("item" + position);
textView.setBackgroundColor(colors[position]);
textView.setGravity(Gravity.CENTER);
final LayoutParams params = new LayoutParams();
params.height = LayoutParams.MATCH_PARENT;
params.width = LayoutParams.MATCH_PARENT;
params.gravity = Gravity.CENTER;
textView.setLayoutParams(params);
textView.setTextColor(0xff000000);
container.addView(textView);
return textView;
}
}
activity_main
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context=".MainActivity">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="viewPager:"/>
<android.support.v4.view.ViewPager
android:id="@+id/viewPager"
android:layout_width="match_parent"
android:layout_height="100dp"
android:layout_marginLeft="30dp"
android:layout_marginRight="30dp"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="viewPager2:"/>
<android.support.v4.view.ViewPager
android:id="@+id/viewPager2"
android:layout_width="match_parent"
android:layout_height="100dp"/>
</LinearLayout>
代码几乎运行良好.我只需要知道,为了避免(由用户)停止拖动的问题,缺少什么?其他问题可能有更简单的解决方案.
The code almost works well. I just need to know, what is missing to avoid the issues of stopping the dragging (by the user)? The other issues might have easier solutions.
经过大量工作,我们找到了一个几乎没有错误的解决方案.有一个罕见的错误,即在滚动时,另一个 viewPager 会闪烁.奇怪的是,它仅在用户滚动第二个 viewPager 时发生.所有其他尝试都有其他问题,例如在完成滚动到新页面时出现空白页面或跳跃"/橡胶"效果.
After a lot of work, we've found a solution that almost has no bugs. There is a rare bug that while scrolling, the other viewPager flashes. Weird thing is that it happens only when the user scrolls the second viewPager. All other tries had other issues, like empty page or "jumpy"/"rubber" effect when finishing the scrolling to a new page.
代码如下:
private static class ParallaxOnPageChangeListener implements ViewPager.OnPageChangeListener {
private final AtomicReference<ViewPager> masterRef;
/**
* the viewpager that is being scrolled
*/
private ViewPager viewPager;
/**
* the viewpager that should be synced
*/
private ViewPager viewPager2;
private float lastRemainder;
private int mLastPos = -1;
public ParallaxOnPageChangeListener(ViewPager viewPager, ViewPager viewPager2, final AtomicReference<ViewPager> masterRef) {
this.viewPager = viewPager;
this.viewPager2 = viewPager2;
this.masterRef = masterRef;
}
@Override
public void onPageScrollStateChanged(int state) {
final ViewPager currentMaster = masterRef.get();
if (currentMaster == viewPager2)
return;
switch (state) {
case ViewPager.SCROLL_STATE_DRAGGING:
if (currentMaster == null)
masterRef.set(viewPager);
break;
case ViewPager.SCROLL_STATE_SETTLING:
if (mLastPos != viewPager2.getCurrentItem())
viewPager2.setCurrentItem(viewPager.getCurrentItem(), false);
break;
case ViewPager.SCROLL_STATE_IDLE:
masterRef.set(null);
viewPager2.setCurrentItem(viewPager.getCurrentItem(), false);
mLastPos = -1;
break;
}
}
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
if (masterRef.get() == viewPager2)
return;
if (mLastPos == -1)
mLastPos = position;
float diffFactor = (float) viewPager2.getWidth() / this.viewPager.getWidth();
float scrollTo = this.viewPager.getScrollX() * diffFactor + lastRemainder;
int scrollToInt = scrollTo < 0 ? (int) Math.ceil(scrollTo) : (int) Math.floor(scrollTo);
lastRemainder = scrollToInt - scrollTo;
if (mLastPos != viewPager.getCurrentItem())
viewPager2.setCurrentItem(viewPager.getCurrentItem(), false);
viewPager2.scrollTo(scrollToInt, 0);
}
@Override
public void onPageSelected(int position) {
}
}
用法:
/**the current master viewPager*/
AtomicReference<ViewPager> masterRef = new AtomicReference<>();
viewPager.addOnPageChangeListener(new ParallaxOnPageChangeListener(viewPager, viewPager2, masterRef));
viewPager2.addOnPageChangeListener(new ParallaxOnPageChangeListener(viewPager2, viewPager, masterRef));
对于自动切换,原代码可以正常工作.
For the auto-switching, the original code works fine.
由于测试起来相当困难,而且我想让你们更容易尝试,这里有一个 Github repo:
Since it's quite hard to test it, and I want to make it easier for you guys to try it out, here's a Github repo:
[https://github.com/AndroidDeveloperLB/ParallaxViewPagers][4]
[https://github.com/AndroidDeveloperLB/ParallaxViewPagers][4]
请注意,正如我所提到的,它仍然存在问题.主要是不时出现的闪烁"效果,但由于某种原因,只有在第二个ViewPager上滚动时才出现.
Do note that as I've mentioned, it still has issues. Mainly the "flashing" effect from time to time, but for some reason, only when scrolling on the second ViewPager.
这篇关于如何在 2 个 ViewPager 之间产生视差效果?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持跟版网!