0

To display data in table layout with the first column frozen, the others can scroll horizontally, I have used 2 gridviews as below XML file content:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"   
    tools:context="com.example.gridviews.MainActivity">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal">

        <GridView
            android:id="@+id/gridViewID"
            android:layout_width="50dp"
            android:layout_height="wrap_content"
            android:columnWidth="50dp"
            android:horizontalSpacing="1dp"
            android:numColumns="1"
            android:paddingTop="5dp"
            android:stretchMode="columnWidth"
            android:verticalSpacing="1dp" />

        <HorizontalScrollView
            android:layout_width="match_parent"
            android:layout_height="wrap_content">

            <LinearLayout
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:orientation="horizontal">

                <GridView
                    android:id="@+id/gridViewDays"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:columnWidth="100dp"
                    android:horizontalSpacing="1dp"
                    android:numColumns="5"
                    android:paddingTop="5dp"
                    android:scrollbarStyle="outsideOverlay"
                    android:stretchMode="columnWidth"
                    android:verticalSpacing="1dp" />

            </LinearLayout>

        </HorizontalScrollView>

    </LinearLayout>

</RelativeLayout>

and my code:

...
BaseAdapter adapterId = new BaseAdapter() {
    @Override
    public int getCount() {
        return dataList.size();
    }

    @Override
    public Object getItem(int position) {
        return dataList.get(position);
    }

    @Override
    public long getItemId(int position) {
        return position;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        TextView textView = new TextView(context);
        textView.setText(String.valueOf(dataList.get(position).Id));
        textView.setLayoutParams(new GridView.LayoutParams(GridView.AUTO_FIT, 70));
        return textView;
    }
};

BaseAdapter adapterDays = new BaseAdapter() {
    @Override
    public int getCount() {
        return dataList.size() * 5;
    }

    @Override
    public Object getItem(int position) {
        return dataList.get(position);
    }

    @Override
    public long getItemId(int position) {
        return position;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        TextView textView = new TextView(context);
        int mod = position % 5;
        int idx = position / 5;
        switch (mod) {
            case 0:
                textView.setText(String.valueOf(dataList.get(idx).Mon));
                break;
            case 1:
                textView.setText(String.valueOf(dataList.get(idx).Tue));
                break;
            case 2:
                textView.setText(String.valueOf(dataList.get(idx).Wed));
                break;
            case 3:
                textView.setText(String.valueOf(dataList.get(idx).Thu));
                break;
            case 4:
                textView.setText(String.valueOf(dataList.get(idx).Fri));
                break;
        }
        textView.setLayoutParams(new GridView.LayoutParams(GridView.AUTO_FIT, 70));
        return textView;
    }
};

gridViewID.setAdapter(adapterId);
gridViewDays.setAdapter(adapterDays);

// Horizontal scrolling of gridViewDays
LinearLayout.LayoutParams linearParams = (LinearLayout.LayoutParams) gridViewDays.getLayoutParams();
linearParams.width = 300;
gridViewDays.setLayoutParams(linearParams);

// Vertical scrolling...
gridViewID.setOnScrollListener(new AbsListView.OnScrollListener() {
    @Override
    public void onScrollStateChanged(AbsListView view, int scrollState) {
        int firstVisibleItem = view.getFirstVisiblePosition();
        gridViewID.setSelection(firstVisibleItem);
        gridViewDays.setSelection(firstVisibleItem * 5);
    }

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

With these code, of course when I move my hand out of the screen, the gridViewDays gridview will have the same selection with the gridViewID as the image below:

enter image description here

However, when I keep my hand touch on the screen to scroll the gridViewID, the gridViewDays will look like the image below (it does not scroll while gridViewID is scrolling)

enter image description here

So, how can I make the gridViewDays gridview vertically scrolling the same as the gridViewID? I have also tried some methods such as smoothScrollToPosition, smoothScrollByOffset, smoothScrollToPositionFromTop... inside onScroll but they do not work


Update: although the answers (@vrundpurohit's and mine) below are working, however, I have found that the app has poor performance with big data (I mean when the data list has too many items).

BNK
  • 23,994
  • 8
  • 77
  • 87

2 Answers2

1

Thanks to @vrundpurohit comment, I have searched more in S.O and found @dennisdrew's answer at How to put GridView inside ScrollView

From there, I use the ExpandableHeightGridView class of @tacone at Gridview height gets cut to solve my issue.

My modified code:

...
final ExpandableHeightGridView gridViewID = (ExpandableHeightGridView) findViewById(R.id.gridViewID);
final ExpandableHeightGridView gridViewDays = (ExpandableHeightGridView) findViewById(R.id.gridViewDays);

gridViewID.setExpanded(true);
gridViewDays.setExpanded(true);
...

Layout file:

<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.example.gridviews.MainActivity">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal">

        <com.example.gridviews.ExpandableHeightGridView
            android:id="@+id/gridViewID"
            android:layout_width="50dp"
            android:layout_height="wrap_content"
            android:columnWidth="50dp"
            android:horizontalSpacing="1dp"
            android:numColumns="1"
            android:stretchMode="columnWidth"
            android:verticalSpacing="1dp" />

        <HorizontalScrollView
            android:id="@+id/horizontalScrollView"
            android:layout_width="match_parent"
            android:layout_height="wrap_content">

            <LinearLayout
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:orientation="horizontal">

                <com.example.gridviews.ExpandableHeightGridView
                    android:id="@+id/gridViewDays"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:columnWidth="100dp"
                    android:horizontalSpacing="1dp"
                    android:numColumns="5"
                    android:scrollbarStyle="outsideOverlay"
                    android:stretchMode="columnWidth"
                    android:verticalSpacing="1dp" />

            </LinearLayout>

        </HorizontalScrollView>

    </LinearLayout>

</ScrollView>

Thank you all!

Community
  • 1
  • 1
BNK
  • 23,994
  • 8
  • 77
  • 87
1

use NonScrollGridView. and wrap both in single ScrollView

Here is code for NonScrollGridView..

public class NonScrollGridView extends GridView {
    public NonScrollGridView(Context context) {
        super(context);
    }

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

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

    @Override
    public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        int heightMeasureSpec_custom = MeasureSpec.makeMeasureSpec(
                Integer.MAX_VALUE >> 2, MeasureSpec.AT_MOST);
        super.onMeasure(widthMeasureSpec, heightMeasureSpec_custom);
        ViewGroup.LayoutParams params = getLayoutParams();
        params.height = getMeasuredHeight();
    }
}

EDIT: Here is how you can do this.

<ScrollView android:id="@+id/scroll" ... >

    <NonScrollGridView />

    <RelativeLayout android:id="@+id/head1" ... > 
        <!-- header for 1st GridView --> 
    </RelativeLayout> 

    <HorizontalScrollView ... >

        <HorizontalScrollView ... >

            <NonScrollGridView />

             <RelativeLayout android:id="@+id/head2" ... > 
                <!-- header for 1st GridView --> 
            </RelativeLayout> 

        </HorizontalScrollView>

    </HorizontalScrollView>

</ScrollView>

Now for making both headers sticky.. do following.

scroll.getViewTreeObserver().addOnScrollChangedListener(
                new ViewTreeObserver.OnScrollChangedListener() {
                    public void onScrollChanged() {
                        ViewCompat.setTranslationY(head1, who.getScrollY());
                        ViewCompat.setTranslationY(head2, who.getScrollY());
                    }
                });

Happy Coding..

V-rund Puro-hit
  • 5,518
  • 9
  • 31
  • 50
  • if I set headers for the gridviews (perhaps by textviews) and want these header frozen when vertically scrolling (of course headers of the second gridview will be scrolled horizontally with data), any idea? – BNK May 31 '16 at 03:54
  • you are using `NonScrollGridView` no need to add header. just add thoes textviews above gridview it will look like headers. and if you don't want to scroll them along with gridview, take it outside of scrollview --- or--- use `ViewCompat.setTranslationY(viewToBeFrozened, 1);` insied of scrollListener of Scrollview – V-rund Puro-hit May 31 '16 at 04:18
  • `take it outside of scrollview`, so it cannot scroll horizontally, that's the matter – BNK May 31 '16 at 04:23
  • what part do you want to scroll horizontally? – V-rund Puro-hit May 31 '16 at 04:37
  • As I commented above `headers of the second gridview` (the `gridViewDays`). You see i put that gridview inside horizontalscrollview – BNK May 31 '16 at 04:39
  • 1
    so wrap them inside another `HorizontalScrollView`. – V-rund Puro-hit May 31 '16 at 04:40
  • If so, need code to make these 2 `HorizontalScrollView` scrolling exactly the same? – BNK May 31 '16 at 04:44
  • as far as I understand you want to add headers to your gridviews and when we scroll vertically. they should be sticky at the top. and when we scroll horizontally is should be able to scroll.. right? – V-rund Puro-hit May 31 '16 at 04:50
  • Yes, however, when scroll horizontally, only headers of the second gridview scroll, the header of the first gridview still is sticky – BNK May 31 '16 at 04:54
  • Ok, I have tried 2 `HorizontalScrollView ` (one for the second gridview, one for its headers), need code to make them scroll the same – BNK May 31 '16 at 04:55
  • Thanks, however, `setTranslationY` not working, `head1` still scroll, not sticky. As I commented 1 hour later, I used 2 `HorizontalScrollView` (one for the second gridview, one for its headers), and added code to make them scroll the same. It's working now. Thanks again for your help – BNK May 31 '16 at 06:02