美文网首页iOS开发资料收集
固定在ScrollView顶部的View,类似于新浪微博的评论列

固定在ScrollView顶部的View,类似于新浪微博的评论列

作者: 6db2cd5e23ce | 来源:发表于2016-01-23 23:58 被阅读405次
    新浪微博截图

    先来看一下上面这张图的效果。

    这个是新浪微博的一个页面,整体布局大致分了三块:正文内容、转发评论赞的数字条、评论列表

    其中数字条是可以跟着ScrollView一起滑动,但在滑到最顶部时固定在最上面,而下面的评论内容可以继续滑动。

    这种效果还是挺赞的,但一开始没有什么思路,所以就去搜了下相关技术代码,一下就恍然大悟!原来是自己想复杂了,其实原理很简单!

    下面是自己实现的效果图:

    GIF效果图
    实现原理:
        当滚动条划过头部时,把需要固定的头部从父布局中移除,然后添加到最外层布局的顶部。
        当滚动条返回时,又把最外层的头部移除,然后重新添加到原来的父布局里面。
        整个实现代码,不算上布局,也就100行左右。
    

    详细实现逻辑:
    首先建一个自定义ViewMyHoveringScrollView继承自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);
     
                }
            });
        }
    

    接下来,在ScrollView里面重写onScrollChanged()方法,并回调给MyHoveringScrollViewonScroll()方法:

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

    两句话就实现了固定头部的效果。

    源代码地址:https://github.com/w9xhc/MyHoveringScroll/

    相关文章

      网友评论

        本文标题:固定在ScrollView顶部的View,类似于新浪微博的评论列

        本文链接:https://www.haomeiwen.com/subject/mzurkttx.html