简体   繁体   English

在ViewPager中同步片段滚动

[英]Synchronize fragment scroll in ViewPager

I'm trying to replicate something like the Yahoo! 我正在尝试复制类似Yahoo!的内容。 Weather app , but I'm quite lost on how to sync all the scrollviews on the same height in the ViewPager. 天气应用程序 ,但是我对如何在ViewPager中的相同高度上同步所有滚动视图一无所知。

I'm using a ScrollListener inside the Fragments to set the opacity of the background and to update the other fragments 我在Fragments中使用ScrollListener来设置背景的不透明度并更新其他片段

final ViewTreeObserver.OnScrollChangedListener onScrollChangedListener = new ViewTreeObserver.OnScrollChangedListener() {

    @Override
    public void onScrollChanged() {
        if(scrollView.getScrollY() > 0 && scrollView.getScrollY() < 1200) {
            overlay.getBackground().setAlpha((scrollView.getScrollY()/4));

            if(isVisible()) {
                Activity parent = getActivity();
                if(parent != null && parent instanceof MainActivity) {
                    ((MainActivity)parent).updateHeight(scrollView.getScrollY());
                }
            }
        }
    }
};

and inside the MainActivity I'm doing something like this: 在MainActivity内部,我正在执行以下操作:

public void updateHeight(int scroll) {
    for(int i = 0; i<mPager.getChildCount(); i++) {
        View v = mPager.getChildAt(i);
        ScrollView scrollView = (ScrollView) v.findViewById(R.id.frag_scrollview);
        scrollView.setScrollY(scroll);
    }
}

This is "almost" working, but not really. 这是“几乎”有效的,但并非如此。

I've tried to modify the code to avoid the update of the current visible page, but with no success: 我试图修改代码以避免更新当前可见页面,但是没有成功:

if(i != mPager.getCurrentItem()) {
    View v = mPager.getChildAt(i);
    ScrollView scrollView = (ScrollView) v.findViewById(R.id.frag_scrollview);
    scrollView.setScrollY(scroll);
}

PS: I'm also quite unsure on the correct pattern in order to get updates on the ScrollView. PS:我也不太确定要在ScrollView上获取更新的正确模式。 The OnScrollChangedListener seems to work but it's called LOTS of times, so I'm not sure if it's the correct approach. OnScrollChangedListener似乎可以正常工作,但是它被称为LOTS时代,所以我不确定这是否是正确的方法。

Thanks in advance. 提前致谢。

UPDATE: 更新:

I've just released this solution ( SynchronizedScrollView ) on gradle/maven! 我刚刚在gradle / maven上发布了此解决方案( SynchronizedScrollView )!
It also has a couple of fix and differences from the last posted, so check the code anyway! 它也有一些修复和与上次发布的不同,所以还是请检查代码!

Feel free to use it and contribute! 随时使用它并做出贡献! Thanks. 谢谢。 :) :)


Ok, I have changed all the structure of the app and also fix this part, it was easier than expected. 好的,我更改了应用程序的所有结构,并修复了此部分,这比预期的要容易。

Just tested in a few minutes, so maybe there are problems with this but seems to work pretty good. 刚刚在几分钟内进行了测试,因此可能存在一些问题,但似乎效果很好。 I basically made a class that will keep the responsability to synchronize all the ScrollViews, and the ScrollViews simply notify this Synchronizer when they're scrolled. 我基本上制作了一个类,该类将负责同步所有ScrollView,并且ScrollView在滚动时仅通知此Synchronizer。

public class Synchronizer {

    private static Synchronizer instance;

    private List<Synchronizable> synchronizableList;

    private Synchronizer() {}

    public static Synchronizer getInstance() {
        if (instance == null)
            instance = new Synchronizer();
        return instance;
    }

    public void registerSynchronizable(Synchronizable synchronizable) {
        if(synchronizableList == null)
            synchronizableList = new ArrayList<>();

        synchronizableList.add(synchronizable);
    }

    public void update(Synchronizable sender, int update) {
        if(update < 0) update = 0;

        for(Synchronizable s : synchronizableList) {
            if(s != sender)
                s.onUpdate(update);
        }
    }

    public interface Synchronizable {
        public void onUpdate(int update);
    }
}

and the ScrollView will implement the Synchronizable interface, and they will "register" at the creation 并且ScrollView将实现Synchronizable接口,并且它们将在创建时“注册”

public class MyScrollView extends ScrollView implements Synchronizer.Synchronizable {

    public MyScrollView(Context context) {
        super(context);
        init();
    }

    public MyScrollView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    public MyScrollView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init();
    }   

    private void init() {
        // init your ScrollView with style and stuff and then register it

        Synchronizer.getInstance().registerSynchronizable(this);
    }

    @Override
    protected void onScrollChanged(int l, int t, int oldl, int oldt) {
        super.onScrollChanged(l, t, oldl, oldt);

        // listen for "your" scrolls and notify the Synchronizer
        Synchronizer.getInstance().update(this, getScrollY());
    }

    @Override
    public void onUpdate(int update) {
        // listen for the scrolls of your "siblings" from the Synchronizer
        setScrollY(update);
    }
}

Hope this will help! 希望这会有所帮助!

With this method scrollView is manually updated only for views who are off screen: 使用此方法,仅针对屏幕外的视图手动更新scrollView:

public void updateFragmentsScroll(int scrollY) {
    // TODO Auto-generated method stub
    if(pager.getCurrentItem()<adapter.getCount()-1){
        PagerItem nextItem = (PagerItem) adapter.instantiateItem(pager, pager.getCurrentItem()+1);
        if(nextItem!=null && nextItem.isAdded()){
            nextItem.setScrollY(scrollY);
        }
    }
    if(pager.getCurrentItem()>0){
        PagerItem prevItem = (PagerItem) adapter.instantiateItem(pager, pager.getCurrentItem()-1);
        if(prevItem!=null && prevItem.isAdded()){
            prevItem.setScrollY(scrollY);
        }
    }
    currentScrollY = scrollY;   
}

If fragment in ViewPager is not somehow added or you scroll over multiple pages without scrolling page content then pass currentScrollY when creating fragment. 如果未以某种方式添加ViewPager片段,或者您滚动了多个页面而不滚动页面内容,则在创建片段时传递currentScrollY。

FragmentStatePagerAdapter btw. FragmentStatePagerAdapter btw。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 ViewPager在最后一个片段滚动上完成 - ViewPager finish on last fragment scroll 同步片段中的滚动视图(相同的滚动速度) - Synchronize scrollviews in fragment (same scroll speed) 在ViewPager中的所有片段之间同步ScrollView的Scroll位置 - Synchronize Scroll position of ScrollView across all fragments inside ViewPager ViewPager 中的第二个片段使用滚动事件 - Second fragment in ViewPager consumes scroll events ViewPager中的片段不会触发协调器布局上的滚动 - Fragment in ViewPager not triggering scroll on Coordinator Layout Viewpager内容未使用ScrollView显示片段,但显示滚动条 - Viewpager content not showing in fragment using ScrollView but Scroll bar showing 有没有一种方法可以使ViewPager DecorView的片段内容滚动? - Is there a way to make ViewPager DecorView's scroll with the fragment content? 在ViewPager的一个片段中包含的ListView滚动上隐藏ActionBar - Hide ActionBar on ListView scroll contained in a Fragment within a ViewPager 当显示键盘时,viewpager片段内的Scrollview不会滚动 - Scrollview inside a viewpager fragment doesnt scroll when keyboard is shown 清除ViewPager片段后如何重置垂直滚动? - How to reset vertical scroll after ViewPager fragment swiped out?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM