您的位置:首页 > 移动开发 > Android开发

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

2016-07-01 00:01 387 查看
现在很多App都实现了这个功能,例如新浪微博评论页面的评论、转发、赞的数字可以固定在屏幕上方。我个人很喜欢这种设计,所以利用一点空余时间简单实现了一个类似的功能。



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

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

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

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

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





实现原理:

    当滚动条划过头部时,把需要固定的头部从父布局中移除,然后添加到最外层布局的顶部。

    当滚动条返回时,又把最外层的头部移除,然后重新添加到原来的父布局里面。

    整个实现代码,不算上布局,也就100行左右。

详细实现逻辑:

首先建一个自定义View叫MyHoveringScrollView继承自FrameLayout,在布局里MyHoveringScrollView处于最外层。由于FrameLayout本身是不支持滚动条的,所以在FrameLayout内部有一个自定义的ScrollView。

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

最后把ScrollView添加到MyHoveringScrollView里面。

[java] view
plain copy

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传进来:

[java] view
plain copy

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()方法,并回调给MyHoveringScrollView的onScroll方法:

[java] view
plain copy

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就是头部应该取消固定,还原到原来父布局的时候

至此,功能就实现了!

    

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

[html] view
plain copy

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

[java] view
plain copy

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

view_hover.setTopView(R.id.top);  

?

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

源代码地址:https://github.com/w9xhc/MyHoveringScroll
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: