同步 ViewPager 中的所有 ListView

Posted

技术标签:

【中文标题】同步 ViewPager 中的所有 ListView【英文标题】:Synchronize all the ListView in a ViewPager 【发布时间】:2013-11-22 09:32:11 【问题描述】:

在我的应用程序中,我有一个 ViewPager,其中每个都有一个自定义 ListView,它像表格中的行一样链接在一起。问题是,当我在第一页滚动 ListView 然后滚动 ViewPager 时,第一页的 ListView 和第二页的 ListView 未对齐。 listView 必须对齐,因为在第一个中我有一个带有描述的 TextView,然后是 4 个带有数据的列,而在接下来的 ListViews 中,有 6 个没有描述的列,因此如果它们未对齐,那将非常复杂。那么如何一次滚动所有的 listView 呢??

编辑:

非常感谢 Rahul Parsani...我终于设法做到了...如果您在单独的片段中有 listView 并且片段的数量未定义,这就是答案:

final ArrayList<ListView> lvs = new ArrayList<ListView>();
        for (int j = 0; j < adapter.getCount(); j++) 
            YourFragment fragJ = (YourFragment) adapter.getItem(j);
            final ListView listViewJ = fragJ.lv;
            lvs.add(listViewJ);
        

        for (int j = 0; j < lvs.size(); j++) 
            final int x = j;
            lvs.get(j).setOnTouchListener(new OnTouchListener() 

                boolean dispatched = false;
                @Override
                public boolean onTouch(View v, MotionEvent event) 
                    if (!dispatched) 
                        dispatched = true;
                        if (x != 0) 
                            lvs.get(x - 1).dispatchTouchEvent(event);
                        ;
                        if (x != lvs.size() - 1) 
                            lvs.get(x + 1).dispatchTouchEvent(event);
                        

                    
                    dispatched = false;
                    return false;
                
            );
        

【问题讨论】:

【参考方案1】:

您正在尝试做的是同步列表视图。有一个库已经为两个列表视图here 实现了这个。我将尝试解释位于活动here中的与您相关的源代码部分。

假设您是否可以通过变量访问所有列表视图:

listViewOne = (ListView) findViewById(R.id.list_view_one);
listViewTwo = (ListView) findViewById(R.id.list_view_two);
listViewThree = (ListView) findViewById(R.id.list_view_three);
listViewFour = (ListView) findViewById(R.id.list_view_four);

在它们上设置相同的触摸监听器:

listViewOne.setOnTouchListener(touchListener);
listViewTwo.setOnTouchListener(touchListener);
// similarly for listViewThree & listViewFour

触摸监听器的基本思想是将事件分派给其他视图,以便它们也与被触摸的列表视图同步滚动。

// Passing the touch event to the opposite list
OnTouchListener touchListener = new OnTouchListener()                                         
    boolean dispatched = false;

    @Override
    public boolean onTouch(View v, MotionEvent event) 
        if (v.equals(listViewOne) && !dispatched) 
            dispatched = true;
            listViewTwo.dispatchTouchEvent(event);
            listViewThree.dispatchTouchEvent(event);
            listViewFour.dispatchTouchEvent(event);
         else if (v.equals(listViewTwo) && !dispatched) 
            dispatched = true;
            listViewOne.dispatchTouchEvent(event);
            listViewThree.dispatchTouchEvent(event);
            listViewFour.dispatchTouchEvent(event);
          // similarly for listViewThree & listViewFour 
         dispatched = false;
         return false;
    
;

该库还设置了一个滚动侦听器,我相信它已被使用,因为视图可能具有不同的高度,而您没有。尝试让我知道这是否有效。

【讨论】:

首先感谢您的回复... 代码看起来很简单,但问题是我没有声明所有的 ListView.. 它们每个都在一个名为 LineSchedule_Fragment 的片段中扩展片段...如何从该片段中提取所有 ListView,然后在每个片段上调用 ​​dispatchTouchEvent(event) ? 在每个片段中,您可以定义触摸监听器,并将其设置在列表视图中。在每个片段中都有一个公共方法,它接受一个参数 MotionEvent,并且只调用 dispatchTouchEvent(MotionEvent)。然后,您需要所有片段的引用,您可以从寻呼机适配器中获取这些引用。 或者您可以通过 Activity 将实现的接口获取引用,一旦执行触摸,该引用就会被调用。喜欢:public void onTouch(int fragmentNumber, MotionEvent); @RahulParsani 你不能从PagerAdapter 获得Fragment 的引用,如果没有一些hack:***.com/questions/10849552/… 非常感谢我终于成功了。看我的编辑!!! (P.S:很抱歉赏金,但我不在城里,我什至无法尝试)【参考方案2】:

您遇到的问题与Update ViewPager dynamically? 类似。它与设置onTouchListener 无关,因为您无权访问ViewPager 中的所有ListViews。

以下是工作测试代码。关键是PagerAdapter中的getItemPosition()方法。

import java.util.ArrayList;
import java.util.List;

import android.app.Activity;
import android.content.Context;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentStatePagerAdapter;
import android.support.v4.app.ListFragment;
import android.support.v4.view.ViewPager;
import android.widget.AbsListView;
import android.widget.AbsListView.OnScrollListener;
import android.widget.ArrayAdapter;
import android.widget.ListView;

public class MainActivity extends FragmentActivity implements ScrollListener 
private MyPagerAdapter mPagerAdapter;

@Override
protected void onCreate(Bundle savedInstanceState) 
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    MyPagerAdapter pagerAdapter = mPagerAdapter = new MyPagerAdapter(
            getSupportFragmentManager(), this);
    pagerAdapter.addFragmentInfo(DummyFragment.class.getName(), "First",
            new Bundle());
    pagerAdapter.addFragmentInfo(DummyFragment.class.getName(), "Second",
            new Bundle());
    pagerAdapter.addFragmentInfo(DummyFragment.class.getName(), "Third",
            new Bundle());

    final ViewPager pager = (ViewPager) findViewById(R.id.pager);
    pager.setOffscreenPageLimit(2);
    pager.setAdapter(pagerAdapter);


@Override
public void onScrollChanged(int index) 
    mPagerAdapter.setIndex(index);


@Override
public int getCurrentScrollIndex() 
    return mPagerAdapter == null ? 0 : mPagerAdapter
            .getCurrentScrollIndex();


public static class MyPagerAdapter extends FragmentStatePagerAdapter 

    public static class FragmentInfo 

        public FragmentInfo(String fragmentName, String title, Bundle args) 
            super();
            this.fragmentName = fragmentName;
            this.title = title;
            this.args = args;
        

        String fragmentName;
        String title;
        Bundle args;
    

    private List<FragmentInfo> mFragmentInfos = new ArrayList<FragmentInfo>();
    private final Context mContext;
    private int mIndex;

    public MyPagerAdapter(FragmentManager fm, Context context) 
        super(fm);

        mContext = context;
    

    @Override
    public Fragment getItem(int position) 
        FragmentInfo info = mFragmentInfos.get(position);
        Fragment fragment = Fragment.instantiate(mContext,
                info.fragmentName, info.args);
        return fragment;
    

    @Override
    public int getCount() 
        return mFragmentInfos.size();
    

    @Override
    public int getItemPosition(Object object) 
        if (object instanceof ScrollRefreshable) 
            ((ScrollRefreshable) object).refreshScroll(mIndex);
        
        return super.getItemPosition(object);
    

    public void addFragmentInfo(String fragmentName, String title,
            Bundle args) 
        mFragmentInfos.add(new FragmentInfo(fragmentName, title, args));
    

    public void setIndex(int index) 
        mIndex = index;
        notifyDataSetChanged();
    

    public int getCurrentScrollIndex() 
        return mIndex;
    



public static class DummyFragment extends ListFragment implements
        ScrollRefreshable 
    private ScrollListener mRefreshListener;

    @Override
    public void onAttach(Activity activity) 
        super.onAttach(activity);
        if (activity instanceof ScrollListener) 
            mRefreshListener = (ScrollListener) activity;
        
    

    @Override
    public void onActivityCreated(Bundle savedInstanceState) 
        super.onActivityCreated(savedInstanceState);
        String[] values = new String[]  "Android", "iPhone",
                "WindowsMobile", "Blackberry", "WebOS", "Ubuntu",
                "Windows7", "Max OS X", "Linux", "OS/2", "Android2",
                "iPhone2", "WindowsMobile2", "Blackberry2", "WebOS2",
                "Ubuntu2", "Windows72", "Max OS X2", "Linux2", "OS/22" ;
        ArrayAdapter<String> adapter = new ArrayAdapter<String>(
                getActivity(), android.R.layout.simple_list_item_1, values);
        setListAdapter(adapter);
        getListView().setOnScrollListener(new OnScrollListener() 

            @Override
            public void onScrollStateChanged(AbsListView view,
                    int scrollState) 
                if (scrollState == SCROLL_STATE_IDLE) 
                    if (mRefreshListener != null) 
                        mRefreshListener.onScrollChanged(view
                                .getFirstVisiblePosition());
                    
                
            

            @Override
            public void onScroll(AbsListView view, int firstVisibleItem,
                    int visibleItemCount, int totalItemCount) 
            
        );
        // update scroll position at start
        if (mRefreshListener != null) 
            int index = mRefreshListener.getCurrentScrollIndex();
            scrollListViewTo(index);
        
    

    @Override
    public void refreshScroll(int index) 
        scrollListViewTo(index);
    

    private void scrollListViewTo(int index) 
        ListView lv = getListView();
        if (lv != null) 
            lv.setSelection(index);
        
    



interface ScrollRefreshable 
public void refreshScroll(int index);


interface ScrollListener 
public void onScrollChanged(int index);

public int getCurrentScrollIndex();

【讨论】:

感谢您的回复!!几个问题......什么是 Scroll Refrashable 以及我在哪里设置 Scroll Listener ?能不能把代码分在activity中? @SmileApplications 您只需复制并粘贴代码即可。您需要的只是 xml 布局 activity_main.xmlViewPager 和 id pager。你试过代码吗? ScrollRefreshable 是在文件末尾定义的自定义接口。我已经为你设置好了。我不明白你所说的“你能把代码分成活动吗?” 我无法复制和粘贴代码,因为我在每个 .java 中都有 houndreds 代码行,所以我必须对其进行调整...我的代码分为: LineSchedule.java 即 FragmentActivity , LineSchedule_Fragment.java 是每个适配器的片段管理器,Adapter_Scroll.java 是 ViewPager 的适配器和 Adapter_LineSchedule.java 是 ViewPager 内部 CustomListViews 的适配器......所以我真的不明白如何划分你的适应我使用的代码 好吧,我帮不了你了。我已经发布了一个简单的示例代码,您可以通过创建另一个简单的项目并复制粘贴上面的代码来了解事情是如何工作的。理解代码后,您可以按照自己的方式对其进行修改。如果你做不到,我很抱歉。【参考方案3】:

列表视图项的高度是否相等?如果是这样,您可以将顶部可见元素的位置传递给其他列表视图适配器。

 int curTop=listview.getFirstVisiblePosition();

 listview2.setSelection(curTop);

【讨论】:

以上是关于同步 ViewPager 中的所有 ListView的主要内容,如果未能解决你的问题,请参考以下文章

Android viewpager 同步滚动

片段中的Tablayout + viewpager,需要清除viewpager中的edittext数据

如何解决片段中的 Viewpager 问题?

ScrollView 中的 ViewPager 无法正确滚动

如何在 Android Studio 中的 ViewPager 小部件之上设置布局

java 为listvie实现基础适配器