Android -- 固定在ScrollView頂部的View,類似于新浪微博的評論列表的頂部

jopen 9年前發布 | 55K 次閱讀 Android開發 移動開發 ScrollView

現在很多App都實現了這個功能,例如新浪微博評論頁面的評論、轉發、贊的數字可以固定在屏幕上方。我個人很喜歡這種設計,所以利用一點空余時間簡單實現了一個類似的功能。

先來看一下上面這張圖的效果。

 Android -- 固定在ScrollView頂部的View,類似于新浪微博的評論列表的頂部

這個是新浪微博的一個頁面,整體布局大致分了三塊:正文內容、轉發評論贊的數字條、評論列表

其中數字條是可以跟著ScrollView一起滑動,但在滑到最頂部時固定在最上面,而下面的評論內容可以繼續滑動。

這種效果還是挺贊的,但一開始沒有什么思路,所以就去搜了下相關技術代碼,一下就恍然大悟!原來是自己想復雜了,其實原理很簡單!


下面是自己實現的效果圖:

 Android -- 固定在ScrollView頂部的View,類似于新浪微博的評論列表的頂部



實現原理:

    當滾動條劃過頭部時,把需要固定的頭部從父布局中移除,然后添加到最外層布局的頂部。

    當滾動條返回時又把最外層的頭部移然后重新添加到原來的父布局里面。

    整個實現代碼,不算上布局,也就100行左右


詳細實現邏輯:

首先建一個自定義View叫MyHoveringScrollView繼承自FrameLayout,在布局里MyHoveringScrollView處于最外層。由于FrameLayout本身是不支持滾動條的,所以在FrameLayout內部有一個自定義的ScrollView。

在初始化的時候,通過getChildAt(0)把子布局拿到,然后清空整個布局,然后實例化一個自己的ScrollView,把之前拿到的子布局添加到ScrollView里面,

最后把ScrollView添加到MyHoveringScrollView里面。

public void init() {
        post(new Runnable() {
            @Override
            public void run() {
                mContentView = (ViewGroup) getChildAt(0);
                removeAllViews();

                MyScrollView scrollView = new MyScrollView(getContext(), MyHoveringScrollView.this);
                scrollView.addView(mContentView);
                addView(scrollView);

            }
        });
    }

可能注意到了兩點:

1、我用了post()。因為在構造方法里面布局還沒有生成,getChildAt(0)是拿不到東西的,但是post()會把動作放到隊列里,等布局完成后再從隊列里取出來,所以這里是個小竅門。

2、我把MyHoveringScrollView傳入到了ScrollView里面,這么做其實是為了讓ScrollView回調MyHoveringScrollView的方法。(比較懶,不想寫接口……)


然后通過setTopView()方法,把需要固定在頂部的ID傳進來:

public void setTopView(final int id) {
        post(new Runnable() {
            @Override
            public void run() {
                mTopView = (ViewGroup) mContentView.findViewById(id);

                int height = mTopView.getChildAt(0).getMeasuredHeight();
                ViewGroup.LayoutParams params = mTopView.getLayoutParams();
                params.height = height;
                mTopView.setLayoutParams(params);
                mTopViewTop = mTopView.getTop();
                mTopContent = mTopView.getChildAt(0);

            }
        });
    }

注意為什么要調用mTopView.setLayoutParams(),因為頭部的布局高度必須得固定,如果是wrap_content,雖然也不會有什么錯誤,但效果不太好,可以自己試一下。


接下來,在ScrollView里面重寫onScrollChanged()方法,并回調給MyHoveringScrollView的onScroll方法:

private static class MyScrollView extends ScrollView {

        private MyHoveringScrollView mScrollView;

        public MyScrollView(Context context, MyHoveringScrollView scrollView) {
            super(context);
            mScrollView = scrollView;
        }


        @Override
        protected void onScrollChanged(int l, int t, int oldl, int oldt) {
            super.onScrollChanged(l, t, oldl, oldt);
            mScrollView.onScroll(t);
        }

    }
public void onScroll(final int scrollY) {
        post(new Runnable() {
            @Override
            public void run() {
                if (mTopView == null
                        ) return;

                if (scrollY >= mTopViewTop
                        && mTopContent.getParent() == mTopView) {
                    mTopView.removeView(mTopContent);
                    addView(mTopContent);
                } else if (scrollY < mTopViewTop
                        && mTopContent.getParent() == MyHoveringScrollView.this) {
                    removeView(mTopContent);
                    mTopView.addView(mTopContent);
                }

            }
        });
    }

如果scrollY >= mTopViewTop就是頭部應該被固定在頂部的時候

如果scrollY < mTopViewTop就是頭部應該取消固定,還原到原來父布局的時候

至此,功能就實現了!

    

怎么使用呢?首先先寫布局:

<com.hide.myhoveringscroll.app.MyHoveringScrollView
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:id="@+id/view_hover"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
    <LinearLayout android:layout_width="match_parent"
                  android:layout_height="match_parent"
                  android:orientation="vertical"
            >
        <TextView android:layout_width="match_parent"
                  android:layout_height="300dp"
                  android:text="這是頭部"
                  android:gravity="center"
                />

        <FrameLayout android:layout_width="match_parent" android:layout_height="wrap_content"
                     android:id="@+id/top"
                >
            <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content"
                          android:padding="20dp"
                          android:background="#AAff0000"
                          android:orientation="horizontal">
                <TextView android:layout_width="0dp" android:layout_height="wrap_content"
                          android:layout_weight="1"
                          android:gravity="center"
                          android:layout_gravity="center"
                          android:textSize="16sp"
                          android:text="這是固定部分"
                        />
                <Button android:layout_width="wrap_content" android:layout_height="wrap_content"
                        android:text="點我一下"
                        android:id="@+id/btn"
                        />

            </LinearLayout>
        </FrameLayout>

        <TextView android:layout_width="match_parent" android:layout_height="wrap_content"
                  android:paddingTop="10dp"
                  android:text="內容\n內容\n內容\n內容\n內容\n內容\n內容\n內容\n內容\n內容\n內容\n內容\n內容
\n內容\n內容\n內容\n內容\n內容\n內容\n內容\n內容\n內容\n內容\n內容\n內容\n內容\n內容\n內容
\n內容\n內容\n內容\n內容\n內容\n內容\n內容\n內容\n內容\n內容\n內容\n內容\n內容\n內容\n內容\n內容
\n內容\n內容\n內容\n內容\n內容\n內容\n內容\n內容\n內容\n內容\n內容\n內容\n內容\n內容\n內容\n內容
\n內容\n內容\n內容\n內容\n內容\n內容\n內容\n內容\n內容\n"
                />

    </LinearLayout>
</com.hide.myhoveringscroll.app.MyHoveringScrollView>

其中:MyHoveringScrollView在最外層,充當ScrollView的角色(所以子布局只能有一個)

android:id="@+id/top也就是需要固定在頂部的布局


最后回到Activity:

view_hover = (MyHoveringScrollView) findViewById(R.id.view_hover);
view_hover.setTopView(R.id.top);

兩句話就實現了固定頭部的效果。

來自:http://my.oschina.net/Hideeee/blog/500933

 本文由用戶 jopen 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!