[Android UI开发] 固定在ScrollView顶部的View,类似于新浪微博的评论列表的顶部

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

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

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

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

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

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


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

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



实现原理:

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

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

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


详细实现逻辑:

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

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

最后把ScrollView添加到MyHoveringScrollView里面。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
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传进来:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
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方法:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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);
         }
 
     }
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
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就是头部应该取消固定,还原到原来父布局的时候

至此,功能就实现了!

    

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

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
< 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:

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

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

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值