Search code examples
androidandroid-layoutandroid-scrollviewandroid-scroll

3 way scroll in Android


I have 3 views: an ImageView, a RelativeLayout and a ListView. When the user scrolls down, I have to hide the ImageView first. When the top of the RelativeLayout touches the top of the screen it has to fix itself there and the scroll must be done by the ListView. Then when I scroll up, the top of the ListView must be visible before the ImageView starts to scroll down again.

Is there any component that does what I want without having to write my own component?

(Just to make things easier, it should work like the headers in Instagram, when the header reaches the top it stays there, but there should be only one header)


Solution

  • I have a very simple solution to this, hope it helps. I use one header added to the listView and the same header added to the page on top. There is a listener to toggle visibility of the fixed header. Everything is done in the onCreate method:

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    
        ListView listView = (ListView) findViewById(R.id.list);
    
        LayoutInflater inflater = getLayoutInflater();
        // your image header
        View headerImage = inflater.inflate(R.layout.header_image, listView, false);
        listView.addHeaderView(headerImage);
        // the header that scrolls with the listview
        final View fixedHeader = inflater.inflate(R.layout.header_fixed, listView, false);
        listView.addHeaderView(fixedHeader);
    
        // the header that is fixed on top of the screen
        final View secondFixedHeader = findViewById(R.id.fixed_header);
        secondFixedHeader.setVisibility(View.GONE);
    
        listView.setOnScrollListener(new AbsListView.OnScrollListener() {
            @Override
            public void onScrollStateChanged(AbsListView view, int scrollState) {}
    
            @Override
            public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
                if (firstVisibleItem > 0) {
                    secondFixedHeader.setVisibility(View.VISIBLE);
                } else {
                    secondFixedHeader.setVisibility(View.GONE);
                }
            }
        });
    
        listView.setAdapter(new ListAdapter(this));
    }
    

    there is the activity_main.xml:

    <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
    
        <ListView
            android:id="@+id/list"
            android:layout_width="match_parent"
            android:layout_height="match_parent" />
    
        <include
            android:id="@+id/fixed_header"
            layout="@layout/header_fixed" />
    
    </RelativeLayout>
    

    there is the header_fixed.xml:

    <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:padding="16dp"
        android:background="@android:color/darker_gray">
    
        <TextView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="This is a fixed header"
            android:textAppearance="@android:style/TextAppearance.DeviceDefault.Large"/>
    
    </RelativeLayout>
    

    and there is the header_image.xml:

    <ImageView xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:src="@drawable/android"/>