ant*_*nyt 64 android android-fragments android-viewpager
我使用的是ViewPager
与FragmentStatePagerAdapter
让一些片段之间的导航.
比方说,我有三个片段:A
,B
和C
.ViewPager最初显示片段A,并允许您通过从右向左滑动,然后再次滑动到片段C来导航到片段B. 这允许以下导航路径:A <--> B <--> C
.
我想要的是能够在片段A上从左向右滑动并让ViewPager显示片段C,即它表现为循环队列并允许 ... --> C <--> A <--> B <--> C <--> A <-- ...
我不希望片段在其他位置重复(即最终有三个以上的实例).
使用ViewPager可以实现这种包装功能吗?
ant*_*nyt 49
我已经实现了一个ViewPager/PagerAdapter,它可以允许伪无限的分页行为.它通过指定一个非常大的数字作为实际计数,但将它们映射到数据集/页面集的实际范围.它还会使开头偏移很多,以便您可以立即从"第一页"向左滚动.
一旦你到达第1,000,000页(在滚动时你会看到图形故障),它不能很好地工作,但这通常不是真实世界的用例.我可以通过偶尔将计数重置为较低的数字来解决这个问题,但我现在将其保留原样.
该InfinitePagerAdapter
包装现有ViewPager,所以使用是相当透明的.这InfiniteViewPager
确实做了一些工作,以确保您可以多次向左和向右滚动.
https://github.com/antonyt/InfiniteViewPager
Kin*_*ses 16
这是一个没有虚假页面的解决方案,就像一个魅力:
public class CircularViewPagerHandler implements ViewPager.OnPageChangeListener {
private ViewPager mViewPager;
private int mCurrentPosition;
private int mScrollState;
public CircularViewPagerHandler(final ViewPager viewPager) {
mViewPager = viewPager;
}
@Override
public void onPageSelected(final int position) {
mCurrentPosition = position;
}
@Override
public void onPageScrollStateChanged(final int state) {
handleScrollState(state);
mScrollState = state;
}
private void handleScrollState(final int state) {
if (state == ViewPager.SCROLL_STATE_IDLE) {
setNextItemIfNeeded();
}
}
private void setNextItemIfNeeded() {
if (!isScrollStateSettling()) {
handleSetNextItem();
}
}
private boolean isScrollStateSettling() {
return mScrollState == ViewPager.SCROLL_STATE_SETTLING;
}
private void handleSetNextItem() {
final int lastPosition = mViewPager.getAdapter().getCount() - 1;
if(mCurrentPosition == 0) {
mViewPager.setCurrentItem(lastPosition, false);
} else if(mCurrentPosition == lastPosition) {
mViewPager.setCurrentItem(0, false);
}
}
@Override
public void onPageScrolled(final int position, final float positionOffset, final int positionOffsetPixels) {
}
}
Run Code Online (Sandbox Code Playgroud)
你只需要将它设置为你的ViewPager作为onPageChangeListener,就是这样:(**现在不推荐**检查编辑说明)
viewPager.setOnPageChangeListener(new CircularViewPagerHandler(viewPager));
Run Code Online (Sandbox Code Playgroud)
为了避免在ViewPager的"结尾"出现这种蓝色光芒,您应该将此行应用于放置ViewPager的xml:
android:overScrollMode="never"
Run Code Online (Sandbox Code Playgroud)
我们改进了上面的解决方案并在github上创建了一个小库.随意查看:)
编辑::根据@Bhavana注释,只需使用addOnPageChangeListener而不是setOnPageChangeListener,因为不推荐使用以后版本.
viewPager.addOnPageChangeListener(new CircularViewPagerHandler(viewPager));
Run Code Online (Sandbox Code Playgroud)
刚才看到这个问题并找到了解决方案.解决方案链接
对onPageScrollStateChanged函数进行以下更改.考虑你有4个标签.
private int previousState, currentState;
public void onPageScrollStateChanged(int state) {
int currentPage = viewPager.getCurrentItem(); //ViewPager Type
if (currentPage == 3 || currentPage == 0){
previousState = currentState;
currentState = state;
if (previousState == 1 && currentState == 0){
viewPager.setCurrentItem(currentPage == 0 ? 3 : 0);
}
}
}
Run Code Online (Sandbox Code Playgroud)
如果状态变量位于现有选项卡中,则其值为1.
一旦您尝试在第一个选项卡之前或最后一个选项卡之后导航,它就会变为0 .因此,比较前一个和当前状态,如代码中所示,您就完成了.
请在此处查看onPageScrollStateChanged函数.
希望能帮助到你.
另一种方法是将视图分页器中第一个元素的伪副本添加到适配器的末尾,并将最后一个元素的伪副本添加到开头.然后,当您查看视图寻呼机中的第一个/最后一个元素时,无需动画即可更改页面.
所以基本上,视图寻呼机中的第一个/最后一个元素是假的,只是产生正确的动画,然后切换到结束/开始.例:
list.add(list.get(0)); //add the first item again as the last, to create the wrap effect
list.add(0, list.get(list.size()-2)); //insert a copy of the last item as the new first item, so we can scroll backwards too
viewPager.setAdapter(list);
viewPager.setCurrentItem(1, false); //default to the second element (because the first is now a fake)
viewPager.setOnPageChangeListener(new OnPageChangeListener() {
private void handleScrollState(final int state) {
if (state == ViewPager.SCROLL_STATE_IDLE) { //this is triggered when the switch to a new page is complete
final int lastPosition = viewPager.getAdapter().getCount() - 1;
if (currentPosition == lastPosition) {
viewPager.setCurrentItem(1, false); //false so we don't animate
} else if (currentPosition == 0) {
viewPager.setCurrentItem(lastPosition -1, false);
}
}
}
Run Code Online (Sandbox Code Playgroud)
这几乎完成了antonyt想要的东西,它不会让你从A - > C走.(没有经过严格测试,但似乎工作得很好)
public class MyAdapter extends PagerAdapter {
private List<Object> mItems;
private int mFakeCount = 0;
public MyAdapter(Context context, List<Object> items) {
mItems = items;
mFakeCount = mItems.size()+1;
}
@Override
public int getCount() {
return mFakeCount;
}
@Override
public Object instantiateItem(View collection, int position) {
// make the size larger, and change the position
// to trick viewpager into paging forever
if (position >= mItems.size()-1) {
int newPosition = position%mItems.size();
position = newPosition;
mFakeCount++;
}
// do your layout inflating and what not here.
// position will now refer to a correct index into your mItems list
// even if the user has paged so many times that the view has wrapped
}
}
Run Code Online (Sandbox Code Playgroud)
我一直在尝试所有建议,解决方案,库等,但是它们并不是纯循环的,并且大多数时候不仅仅支持3页。
因此,我ViewPager
使用new 实现了一个循环示例ViewPager2
,而new ViewPager
使用a RecyclerView
和ViewHolder
s处理视图回收并按预期工作!
TLDR: GITHUB
在此示例中,将构建一个活动应用程序,ViewPager2
并FragmentPagerAdapter
在3页或更多页面之间提供循环导航。
我使用的是库的Alpha版本androidx.viewpager2:viewpager2
,但该版本1.0.0-alpha06
是Google冻结API并移至Beta之前计划的最后一个版本。
1.将ViewPager2
库添加到build.gradle中的依赖项
dependencies {
implementation 'androidx.viewpager2:viewpager2:1.0.0-alpha06'
}
Run Code Online (Sandbox Code Playgroud)
2.将ViewPager2
视图添加到您的项目中:
dependencies {
implementation 'androidx.viewpager2:viewpager2:1.0.0-alpha06'
}
Run Code Online (Sandbox Code Playgroud)
3.创建FragmentStateAdapter
适配器:
getItemCount()
需要返回一个huuuuge数字。(2147483647)
getCenterPage()
根据huuuuge编号返回中心页面。该方法用于获取要设置的初始页面的位置ViewPager2
,在这种情况下,用户需要滑动〜1073741823时间才能到达的末尾ViewPager2
。
class CircularPagerAdapter(fragmentManager: FragmentManager, lifecycle: Lifecycle) : FragmentStateAdapter(fragmentManager, lifecycle) {
override fun getItemCount() = Integer.MAX_VALUE
/**
* Create the fragment based on the position
*/
override fun createFragment(position: Int) = HomePagerScreens.values()[position % HomePagerScreens.values().size].fragment.java.newInstance()
/**
* Returns the same id for the same Fragment.
*/
override fun getItemId(position: Int): Long = (position % HomePagerScreens.values().size).toLong()
fun getCenterPage(position: Int = 0) = Integer.MAX_VALUE / 2 + position
}
Run Code Online (Sandbox Code Playgroud)
HomeScreens是带有页面信息的枚举。
enum class HomePagerScreens(@StringRes val title: Int,
val fragment: KClass<out Fragment>) {
HOME_1(R.string.home_1, FragmentHome::class),
HOME_2(R.string.home_2, FragmentHome::class),
HOME_3(R.string.home_3, FragmentHome::class)
}
Run Code Online (Sandbox Code Playgroud)
4.将适配器设置为ViewPager
val circularAdapter = CircularPagerAdapter(supportFragmentManager, lifecycle)
vwpHome.apply {
adapter = circularAdapter
setCurrentItem(circularAdapter.getCenterPage(), false)
}
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
51233 次 |
最近记录: |