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

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

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

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

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

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

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

实现原理:

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

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

    整个实现代码,不算上布局,也就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);

            }
        });
    }

接下来,在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);

?

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

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

时间: 2024-10-21 14:32:43

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

Android中使用ScrollView指定view的顶部悬停效果

因项目中的需要实现ScrollView顶部的悬停,也不是太难便自己实现功能,话不多说,先上效果图 红色text一到顶上便会悬浮在上面,不会跟随scrollview的滑动而上滑. 原理: 原理其实很简单就是对view的gone和visible,写两个相同的要置顶的view,一个设置为gone,一个为visible,当可见的view超出屏幕范围的时候,将不可以的view设置为visible,不可见的view 与scrollview要同级,这样滑动的时候不会影响到view的位置. 直接上代码 <?xm

android 属性动画在ScrollView中平移view的问题

问题描述 android 属性动画在ScrollView中平移view的问题 在ScrollView里使用属性动画平移一个view 的时候,沿ScrollView滑动反向,不管是的动态改变translationX,还是x,view的宽度也会改变,就相当于只改变view的一个边界,另一个边界还是固定不动,看上去完全不是平移而是压缩或拉伸的效果,平移该如何实现? 解决方案 android view动画问题Android View 动画问题Android view动画问题 解决方案二: 我不知道你在说

Android编程开发ScrollView中ViewPager无法正常滑动问题解决方法_Android

本文实例讲述了Android编程开发ScrollView中ViewPager无法正常滑动问题解决方法.分享给大家供大家参考,具体如下: 这里主要介绍如何解决ViewPager在ScrollView中滑动经常失效.无法正常滑动问题. 解决方法只需要在接近水平滚动时ScrollView不处理事件而交由其子View(即这里的ViewPager)处理即可,重写ScrollView的onInterceptTouchEvent函数,如下: package cc.newnews.view; import an

布局-Android自定义控件在scrollview中设置高度不起作用,已经重写了 onMeasure方法

问题描述 Android自定义控件在scrollview中设置高度不起作用,已经重写了 onMeasure方法 布局: android:layout_width="match_parent" android:layout_height="match_parent" android:fillViewport="true"> <RelativeLayout android:layout_width="match_parent&q

Android UI系列-----ScrollView和HorizontalScrollView的详解_Android

本篇随笔将讲解一下Android当中比较常用的两个布局容器--ScrollView和HorizontalScrollView,从字面意义上来看也是非常的简单的,ScrollView就是一个可以滚动的View,这个滚动的方向是垂直方向的,而HorizontalScrollView则是一个水平方向的可以滚动的View.本篇随笔可能描述性的知识比较少,最主要还是通过代码来看看如何使用这两个View. 一.ScrollView的简单介绍 首先来看看ScrollView和HorizontalScrollV

Android UI系列-----ScrollView和HorizontalScrollView的详解

本篇随笔将讲解一下Android当中比较常用的两个布局容器--ScrollView和HorizontalScrollView,从字面意义上来看也是非常的简单的,ScrollView就是一个可以滚动的View,这个滚动的方向是垂直方向的,而HorizontalScrollView则是一个水平方向的可以滚动的View.本篇随笔可能描述性的知识比较少,最主要还是通过代码来看看如何使用这两个View. 一.ScrollView的简单介绍 首先来看看ScrollView和HorizontalScrollV

Android编程开发ScrollView中ViewPager无法正常滑动问题解决方法

本文实例讲述了Android编程开发ScrollView中ViewPager无法正常滑动问题解决方法.分享给大家供大家参考,具体如下: 这里主要介绍如何解决ViewPager在ScrollView中滑动经常失效.无法正常滑动问题. 解决方法只需要在接近水平滚动时ScrollView不处理事件而交由其子View(即这里的ViewPager)处理即可,重写ScrollView的onInterceptTouchEvent函数,如下: package cc.newnews.view; import an

Android开发控制ScrollView滑动速度的方法

本文实例讲述了Android开发控制ScrollView滑动速度的方法.分享给大家供大家参考,具体如下: 前言 由于各个Android平板触摸屏的材质不一样,滑动效果会有一些区别,有的比较灵敏,有的比较迟钝,这里就遇到了要求控制滑动速度的需求... 正文 翻阅查找ScrollView的文档并搜索了一下没有发现直接设置的属性和方法,这里通过继承来达到这一目的. /** * 快/慢滑动ScrollView * @author 农民伯伯 * */ public class SlowScrollView

Android中使用ScrollView实现滑动到底部显示加载更多

这是效果 主要是onTouchListener监听事件,监视什么时候滑到底部 同时要理解getMeasuredHeight和getHeight的区别 getMeasuredHeight:全部的长度 包括隐藏的 getHeight:在布局中展示出来的长度 布局文件: <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_paren