Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Fix an element on ScrollView

I wanna do something like a sticky menu, but I do not have any clue about this. My XML is something like this:

<com.example.customscrollview.scrollview
    android:layout_width="fill_parent"
    android:layout_height="wrap_content">
    <FrameLayout
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical">
        <!-- I need sticky this element bellow! -->
        <LinearLayout
            android:layout_width="fill_parent"
            android:layout_height="210.0dip"
            android:orientation="vertical">
        </LinearLayout>
        <LinearLayout
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:orientation="vertical"
            android:layout_marginTop="210.0dip">
            <!-- A lot of TextViews -->
            <TextView...>
            <TextView...>
            <TextView...>
        </LinearLayout>
    </FrameLayout>
</com.example.customscrollview.scrollview>

I tried do it programmatically:

private void setTouchListeners() {
    setOnTouchListener(new View.OnTouchListener() {
        @Override
        public boolean onTouch(View v, MotionEvent event) {
            boolean rt = false;
            if (event.getAction() == MotionEvent.ACTION_MOVE) {
                final View element = (View) findViewById(R.id.element);
                LayoutParams params = new LayoutParams(
                        LayoutParams.MATCH_PARENT,
                        element.getHeight()
                );
                params.setMargins(0, (int) getScrollY(), 0, 0);
                params.gravity = Gravity.TOP;
                element.setLayoutParams(params);
                Handler handler = new Handler();
                handler.post(new Runnable() {
                    @Override
                    public void run() {
                        childElement.requestLayout();
                    }
                });
            }
            return rt;
        }
    });
}

It works but isn't perfect. When the ScrollView begin fling, the movement isn't completed, because the MotionEvent only hook the touch events. So I overwrite the onScrollChanged to do the same function (with some changes). Good, now the element stays in the top, but it do not follow the scroll movement, it becomes "unstable" until the scroll stops (result of the fling and fast scroll velocity).

What is the better way to do it?

like image 823
Rafael Almeida Avatar asked May 15 '26 10:05

Rafael Almeida


1 Answers

You can get there most easily by changing the nesting. If you make the FrameLayout the root element, you can float the overlay on top of the ScrollView. The price that you pay is that it appears in the layout twice. If it's not too many views, that's probably worth paying.

You need programmatic control to change the visibility of the sticky navigation once the the scrolling navigation hits the top of the view. You don't need programmatic control to keep the sticky navigation in place.

<!-- FrameLayout simply positions all its children at the requested height, width, 
     gravity and margins. It doesn't try to avoid child views overlapping each
     other. The items are rendered in top-to-bottom XML order. -->
<FrameLayout layout_width="match_parent" 
             layout_height="match_parent">

    <!-- The scrollable main content. -->
    <ScrollView layout_width="match_parent" 
                layout_height="match_parent">
        <LinearLayout layout_width="match_parent"
                      layout_height="wrap_content"
                      orientation="vertical">

            <!-- The scrolling version of the navigation section -->
            <LinearLayout layout_width="match_parent" 
                          layout_height="wrap_content"
                          orientation="horizontal">
                <!-- menu items go here -->
            </LinearLayout>

            <!-- content views go here. Note: if you're doing data binding to
                 populate this, consider RecyclerView instead of ScrollView. -->
            <TextView />
            <TextView />

        </LinearLayout>
    </ScrollView>

    <!-- This is a copy of the navigation section. -->
    <LinearLayout layout_width="match_parent" 
                  layout_height="wrap_content"
                  layout_gravity="top" 
                  visibility="invisible"
                  orientation="horizontal">
        <!-- menu items go here -->
    </LinearLayout>
</FrameLayout>

(I've left out the android: prefixes for the example. You do need them.)

like image 144
Barend Avatar answered May 17 '26 23:05

Barend



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!