[英]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.