修复 ScrollView 上的一个元素

Fix an element on ScrollView

我想做类似 sticky menu 的事情,但我对此一无所知。我的 XML 是这样的:

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

我尝试以编程方式进行:

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

它有效但并不完美。当 ScrollView 开始滑动时,移动还没有完成,因为 MotionEvent 只挂钩触摸事件。所以我覆盖 onScrollChanged 来执行相同的功能(有一些更改)。很好,现在元素停留在顶部,但它不跟随滚动移动,它变为 "unstable" 直到滚动停止(快速滚动速度的结果)。

更好的方法是什么?

您可以通过更改嵌套最轻松地到达那里。如果使 FrameLayout 成为根元素,则可以将叠加层浮动在 ScrollView 的顶部。您付出的代价是它在布局中出现两次。如果不是太多的浏览量,那可能是值得的。

一旦滚动导航到达视图顶部,您需要编程控制来更改粘性导航的 visibility。您不需要编程控制来保持粘性导航。

<!-- 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>

(示例中我省略了 android: 前缀。您确实需要它们。)