Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Syncing Two ListViews side by side Android

I'm trying to make two side by side ListViews act like a GridView to an extent. The reason I'm not using GridView is because there's no support for a Staggered Look. Anyways, I have the following code so far:

<- Old,now irrelevant code ->

EDIT:

I did as @Sam suggested and used the following code:

lv1.setOnTouchListener(new OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                if (touchSource == null) {
                    touchSource = v;
                }

                if (v == touchSource) {
                    lv2.dispatchTouchEvent(event);
                    if (event.getAction() == MotionEvent.ACTION_UP) {
                        clickSource = v;
                        touchSource = null;
                    }
                }

                return false;
            }
        });

        lv1.setOnItemClickListener(new OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> parent, View view,
                    int position, long id) {
                if (parent == clickSource) {
                               //my own code here

                }
            }
        });

        lv1.setOnScrollListener(new OnScrollListener() {
            @Override
            public void onScroll(AbsListView view, int firstVisibleItem,
                    int visibleItemCount, int totalItemCount) {
                if (view == clickSource) {


                }
                boolean loadMore = /* maybe add a padding */
                firstVisibleItem + visibleItemCount + 10 >= totalItemCount;

                if (loadMore) {
                    //add items, load more
                }
            }

            @Override
            public void onScrollStateChanged(AbsListView view, int scrollState) {
            }
        });

        lv2.setOnTouchListener(new OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                if (touchSource == null) {
                    touchSource = v;
                }

                if (v == touchSource) {
                    lv1.dispatchTouchEvent(event);
                    if (event.getAction() == MotionEvent.ACTION_UP) {
                        clickSource = v;
                        touchSource = null;
                    }
                }

                return false;
            }
        });
        lv2.setOnItemClickListener(new OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> parent, View view,
                    int position, long id) {
                if (parent == clickSource) {
                }
            }
        });

        lv2.setOnScrollListener(new OnScrollListener() {
            @Override
            public void onScroll(AbsListView view, int firstVisibleItem,
                    int visibleItemCount, int totalItemCount) {
                if (view == clickSource) {

                }
                boolean loadMore = /* maybe add a padding */
                firstVisibleItem + visibleItemCount + 2 >= totalItemCount;

                if (loadMore) {

                }

            }

            @Override
            public void onScrollStateChanged(AbsListView view, int scrollState) {
            }
        });

I am also using a header on one of the lists to create a Staggered Effect and I need to keep this stagger at all costs. This is mostly working (the above code) but it unsyncs a lot of the time. I have figured out this is only when I have small short swipes. I'm not sure why, and I can't find a good solution. It seems to me that the above logic should work.

Also, just in case it matters, I am using UniversalImageLoader to load photos and a simple EndlessScroll logic to load more photos (directly calling adapter.notifyDataSetChanged()). This stuff doesn't seem too relevant though. Even when photos are loaded, I can still see it unsyncing.

I want to be clear: if I do short swipes (and sometimes just in general repeated scrolling) I can unsync the lists at will.

Any help is appreciated. Thanks.

EDIT 2:

Yet to find a good solution. Here are the solutions that I have found that don't quite work:

  • The above solution: unsyncs far too often
  • Pinterest List View: no OnScrollListener/onItemClick differentiation
  • StaggeredGridView: No onScrollListener
  • Stag Project: No onItemClick listener
  • Linear Layout Method: No onItemClick Listener

Any ideas? Thanks.

like image 539
Kgrover Avatar asked Feb 27 '13 00:02

Kgrover


2 Answers

Okay, so I ended up using the Linear Layout Method(See the Question) and used setTag to get the onItemClickListener working, and a CustomScrollView implementation to get the infinite List working.

Basically, two linearLayouts stacked horizontally, inside a scrollview. It works rather well, and loads much faster.

Also, to load my images SmartImageView if that helped.

If someone wants the code, I might be able to post parts of it.

like image 66
Kgrover Avatar answered Nov 03 '22 04:11

Kgrover


Instead of listening to onTouch why don't you scroll lists in the onScroll listener of ListViews. That's what I'm using in that library with sort of tracks the scroll of a ListView similarly and it works like a charm. Check out this file. https://github.com/JlUgia/list_moving_container/blob/master/src/com/ugia/listmovingcontainer/fragment/BottomListMovingContainerFragment.java

Pay attention specially to 81 (don't forget to add the global layout updater listener) and 89 (with the onScroll Listener). That way you can forget about the click hacks as well.

UPDATE

I'd code it the following way.

lv1.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
    @Override
    public void onGlobalLayout() {
        updateListPosition(lv2, lv1);
    }
});

lv1.setOnScrollListener(new AbsListView.OnScrollListener() {

    @Override
    public void onScrollStateChanged(AbsListView view, int scrollState) {
    }

    @Override
    public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
        updateListPosition(lv2, lv1);
    }
});

lv2.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
    @Override
    public void onGlobalLayout() {
        updateListPosition(lv1, lv2);
    }
});

lv2.setOnScrollListener(new AbsListView.OnScrollListener() {

    @Override
    public void onScrollStateChanged(AbsListView view, int scrollState) {
    }

    @Override
    public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
        updateListPosition(lv1, lv2);
    }
});

private void updateListPosition(ListView updatedList, ListView scrolledList){
    updatedList.setScrollY(scrolledList.getScrollY());

}

** setScrollY already invalidates your list.

** Note that I didn't test the code. Although it should be simple enough.

like image 30
Jose L Ugia Avatar answered Nov 03 '22 03:11

Jose L Ugia