Synchronize all the ListView in a ViewPager

2019-01-22 04:44发布

In my application I have a ViewPager with each one a custom ListView in it linked toghether like row in a table. The problem is that when I scroll a ListView in the first page and then I scroll the ViewPager the ListView of the first page and the ListView of the second page are misaligned. The listView must be aligned because in the first one i have a TextView with a description and then 4 coloumns with datas and in the next ListViews 6 coloumns without the description so if they are misaligned it's very complicated. So how can I scroll all the listViews at once ??

EDIT:

Thank you very much to Rahul Parsani... I've finally managed how to do this... If you have the listView in separate fragment and the number of the fragment is undefined this is the answer:

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;
                }
            });
        }

3条回答
孤傲高冷的网名
2楼-- · 2019-01-22 05:25

The problem you are having is similar to this one Update ViewPager dynamically?. It has nothing to do with setting onTouchListener because you don't have access to all ListViews inside ViewPager.

Following is a working and tested code. Key point is getItemPosition() method in PagerAdapter.

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();
}
查看更多
等我变得足够好
3楼-- · 2019-01-22 05:30

What you are trying to do is synchronize the listviews. There is a library that already implements this for two listviews here. I will try to explain the part of the source code relevant to you which is located in the activity here.

Suppose if you have access to all your listviews through variables:

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);

Set the same touch listeners on them:

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

The basic idea of the touch listener is to dispatch events to the other views so that they also scroll synchronously with the listview being touched.

// 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;
    }
};

The library also has set a scroll listener, which I believe is used because the views may be of differing heights, which you don't have. Try and let me know if this works.

查看更多
smile是对你的礼貌
4楼-- · 2019-01-22 05:31

Are the listview item heights equal? if so, you could pass the position of the top visible element to the other listview adapters.

 int curTop=listview.getFirstVisiblePosition();

 listview2.setSelection(curTop);
查看更多
登录 后发表回答