《滑动到顶部悬浮功能条》源码学习整理笔记

原创 2015年07月09日 14:45:28

项目源码地址:https://git.oschina.net/steve/HoveringScroll

实现原理解析:

我这里使用了不同的颜色,将后面会讲解到的几个布局标注了出来。
这里有几个对象A布局、B布局、C布局需要事先说明一下:
A布局示意图:
这里写图片描述
B布局示意图:
这里写图片描述
C布局示意图:
这里写图片描述
1.Activity初始化时的状态,此时C布局在B布局上:
这里写图片描述
2.当向上滑动屏幕,布局B也会随着滚动布局向上滚动:
这里写图片描述
3.当向上滑动的距离超过了开始时顶部布局的高度H时,本来在B上的子布局C就会被移除,然后加到A布局上:
这里写图片描述
代码实现部分:

 // 自定义ScrollView滑动监听,获取实时的Y轴滑动距离
    @Override
    public void onScroll(int scrollY)
    {
        Log.d("guxuewu", "scrollY=>" + scrollY);
        // 如果滑动的距离大于等于了顶部布局的高度H
        if (scrollY >= searchLayoutTop)
        {
            // 并且固定布局C的父布局不是A布局
            if (hoveringLayout.getParent() != search01)
            {
                // B布局移除布局C
                search02.removeView(hoveringLayout);
                // A加入布局C
                search01.addView(hoveringLayout);
            }
        }
        // 如果滑动距离小于了顶部布局的高度
        else
        {
            // 并且固定布局C的父布局不是B布局
            if (hoveringLayout.getParent() != search02)
            {
                // A布局移除固定布局C
                search01.removeView(hoveringLayout);
                // B加入固定布局C
                search02.addView(hoveringLayout);
            }
        }
    }

代码详解

HoveringScrollSampleActivity.java

public class HoveringScrollSampleActivity extends Activity implements OnScrollListener
{    
    // 自定义的ScrollView
    private HoveringScrollview hoveringScrollview;    
    // 顶部布局的高度
    private int searchLayoutTop;    
    // 顶部布局
    private RelativeLayout rlayout;    
    // 中间固定条的布局
    private LinearLayout hoveringLayout;
    // 不跟随ScrollView移动的父布局
    private LinearLayout search01;

    // 跟随ScrollView移动的父布局
    // Search01的布局高度要和search02的设置一样,这样看起来就不会有替换的感觉
    private LinearLayout search02;
    @Override
    protected void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_samples);
        initViews();
    }
    private void initViews()
    {
        hoveringLayout = (LinearLayout)findViewById(R.id.hoveringLayout);
        hoveringScrollview = (HoveringScrollview)findViewById(R.id.hoveringScrollview);
        search01 = (LinearLayout)findViewById(R.id.search01);
        search02 = (LinearLayout)findViewById(R.id.search02);
        rlayout = (RelativeLayout)findViewById(R.id.rlayout);
        hoveringScrollview.setOnScrollListener(this);
    }
    @Override
    public void onWindowFocusChanged(boolean hasFocus)
    {
        super.onWindowFocusChanged(hasFocus);
        // 每次启动,设置顶部布局的高度
        if (hasFocus)
        {
            searchLayoutTop = rlayout.getBottom();
        }
    }
  // 自定义ScrollView滑动监听,获取实时的Y轴滑动距离
    @Override
    public void onScroll(int scrollY)
    {
        Log.d("guxuewu", "scrollY=>" + scrollY);
        // 如果滑动的距离大于等于了顶部布局的高度H
        if (scrollY >= searchLayoutTop)
        {
            // 并且固定布局C的父布局不是A布局
            if (hoveringLayout.getParent() != search01)
            {
                // B布局移除布局C
                search02.removeView(hoveringLayout);
                // A加入布局C
                search01.addView(hoveringLayout);
            }
        }
        // 如果滑动距离小于了顶部布局的高度
        else
        {
            // 并且固定布局C的父布局不是B布局
            if (hoveringLayout.getParent() != search02)
            {
                // A布局移除固定布局C
                search01.removeView(hoveringLayout);
                // B加入固定布局C
                search02.addView(hoveringLayout);
            }
        }
    }
    // 点击事件监听
    public void clickListenerMe(View view)
    {
        if (view.getId() == R.id.btnQiaBuy)
        {
            Toast.makeText(this, "抢购成功", Toast.LENGTH_SHORT).show();
        }
    }
}

HoveringScrollview.java

public class HoveringScrollview extends ScrollView
{
    // 滚动监听器
    private OnScrollListener onScrollListener;

    /**
     * 主要是用在用户手指离开本view,本view还在继续滑动,我们用来保存Y的距离,然后做比较
     */
    private int lastScrollY;

    public HoveringScrollview(Context context, AttributeSet attrs)
    {
        super(context, attrs);
    }

    /**
     * 设置滚动监听接口
     */
    public void setOnScrollListener(OnScrollListener onScrollListener)
    {
        this.onScrollListener = onScrollListener;
    }

    /**
     * 用于用户手指离开MyScrollView的时候获取MyScrollView滚动的Y距离,然后回调给onScroll方法中
     */
    @SuppressLint("HandlerLeak")
    private Handler handler = new Handler()
    {
        public void handleMessage(android.os.Message msg)
        {
            int scrollY = HoveringScrollview.this.getScrollY();
            // 此时的距离和记录下的距离不相等,在隔6毫秒给handler发送消息
            if (lastScrollY != scrollY)
            {
                lastScrollY = scrollY;
                // 相当于开启了一个无线循环的消息机制
                handler.sendMessageDelayed(handler.obtainMessage(), 20);
            }
            if (onScrollListener != null)
            {
                onScrollListener.onScroll(scrollY);
            }
        };

    };

    @SuppressLint("ClickableViewAccessibility")
    public boolean onTouchEvent(MotionEvent ev)
    {
        // 当用户的手在HoveringScrollview上面的时候,
        // 直接将HoveringScrollview滑动的Y方向距离回调给onScroll方法中,
        if (onScrollListener != null)
        {
            onScrollListener.onScroll(lastScrollY = this.getScrollY());
        }
        switch (ev.getAction())
        {
        // 当用户抬起手的时候,HoveringScrollview可能还在滑动,
        // 所以当用户抬起手我们隔6毫秒给handler发送消息,
        // 在handler处理 HoveringScrollview滑动的距离
            case MotionEvent.ACTION_UP:
                handler.sendMessageDelayed(handler.obtainMessage(), 20);
                break;
        }
        return super.onTouchEvent(ev);
    };

    /**
     * 滚动的回调接口
     */
    public interface OnScrollListener
    {
        /**
         * 回调方法, 返回本view滑动的Y方向距离
         */
        public void onScroll(int scrollY);
    }

}

布局文件activity_samples.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:paddingBottom="@dimen/activity_vertical_margin" >

    <com.steve.hovering.samples.HoveringScrollview
        android:id="@+id/hoveringScrollview"
        android:layout_width="match_parent"
        android:layout_height="match_parent" >

        <!-- 套在ScrollView中的唯一父布局 -->

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="vertical" >

            <RelativeLayout
                android:id="@+id/rlayout"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_gravity="center_horizontal" >

                <TextView
                    android:id="@+id/tv"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:gravity="center_vertical"
                    android:text="TOP信息占位\nTOP信息\nTOP信息\nTOP信息占位"
                    android:textColor="#d19275"
                    android:textSize="30sp" />
            </RelativeLayout>

            <!-- 跟随ScrollView移动的父布局 -->

            <LinearLayout
                android:id="@+id/search02"
                android:layout_width="match_parent"
                android:layout_height="70dp"
                android:background="@android:color/holo_green_light" >

                <!-- 这个悬浮条必须是固定高度 -->
                <!-- android:background="#A8A8A8" -->

                <LinearLayout
                    android:id="@+id/hoveringLayout"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:gravity="center_vertical"
                    android:orientation="horizontal"
                    android:padding="10dp" >

                    <TextView
                        android:layout_width="0dp"
                        android:layout_height="wrap_content"
                        android:layout_weight="1"
                        android:gravity="center"
                        android:padding="10dp"
                        android:text="¥188\r\n原价:¥399"
                        android:textColor="#FF7F00" />

                    <Button
                        android:id="@+id/btnQiaBuy"
                        android:layout_width="0dp"
                        android:layout_height="wrap_content"
                        android:layout_weight="1"
                        android:background="#FF7F00"
                        android:onClick="clickListenerMe"
                        android:padding="10dp"
                        android:text="立即抢购"
                        android:textColor="#FFFFFF" />
                </LinearLayout>
            </LinearLayout>

            <TextView
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:gravity="center_horizontal"
                android:text="1测试内容\n2测试内容\n3测试内容\n4测试内容\n5测试内容\n6测试内容\n7测试内容\n8测试内容\n9测试内容\n10测试内容\n11测试内容\n12测试内容\n13测试内容\n14测试内容\n15测试内容\n16测试内容\n测试内容\n测试内容\n测试内容\n测试内容\n测试内容\n测试内容\n测试内容\n测试内容\n测试内容\n测试内容\n27测试内容"
                android:textSize="40sp" />
        </LinearLayout>
    </com.steve.hovering.samples.HoveringScrollview>

    <!-- 固定不动的用来装固定布局的父布局 -->

    <LinearLayout
        android:id="@+id/search01"
        android:layout_width="match_parent"
        android:layout_height="70dp"
        android:background="@android:color/darker_gray"
        android:orientation="vertical" >
    </LinearLayout>

</RelativeLayout>

最终效果

这里写图片描述

学习心得

学习大神的代码总能收益颇多,之前也一直想研究这个效果怎么做出来,无意在论坛看到这个源码分享,便迫不及待拿来细细研究。
研究后发现自己原来好多实现想法想复杂了,原来这么简单其实就可以实现这个效果。
所以我们还是得敢于尝试,尝试用最简单的方法去实现想要的效果。

版权声明:本文为博主原创文章,未经博主允许不得转载。

Android自定义ScrollView:实现滑动顶部停靠

先看看实现效果:自定义ScrollView实现滑动顶部停靠的过程:第一步 首先自定义MyScrollview 继承Scrollview,实现滑动的监听在onTouchEvent()方法中监听用户的...
  • happy_horse
  • happy_horse
  • 2016年04月13日 18:56
  • 3612

vue+jquery+lodash 实现的滑动时顶部悬浮固定

vue+jquery+lodash 实现的滑动时顶部悬浮固定
  • Zhooson
  • Zhooson
  • 2017年11月20日 22:32
  • 410

Android 滑动悬浮置顶效果的新实现

最近项目要实现如图的效果,就是滑动的时候课程介绍那一栏到顶悬浮,而里面的可滑动控件继续滑动, 百度了好多,网上都是利用重写scrollview滑动的监听,来隐藏和显示某一个控件来实现的,通过这个方法实...
  • gemgaozhen
  • gemgaozhen
  • 2016年08月30日 17:04
  • 10896

android之滑动悬浮tab&无限循环的viewPager

效果图如下: 虽然listview现在已经过时,而且这种效果也满地都是,但是因为自己项目的原因还是自己写一个,而且也想整合都涉及的优化知识点,所以还是值得写一写,当作练练手,也算是一种提升吧 ...
  • zhongwn
  • zhongwn
  • 2017年01月10日 15:12
  • 1939

上滑ScrollView,实现控件顶部悬浮

上滑ScrollView,实现控件顶部悬浮。
  • aheeyiqi
  • aheeyiqi
  • 2016年05月11日 11:08
  • 5334

Android自定义ViewGroup(二)——带悬停标题的ExpandableListView

项目里要加一个点击可收缩展开的列表,要求带悬停标题,具体效果如下图: 也就是说,在某一个分组内部滚动时,要求分组标题悬停,当滚出该分组范围时,把标题顶出去,悬停下一个分组的标题。正好看到一个比较有...
  • TurkeyCock
  • TurkeyCock
  • 2016年12月06日 01:04
  • 3587

listView顶部悬浮效果实现几种方法

http://download.csdn.net/download/ljfbest/7804769
  • lbdreaming
  • lbdreaming
  • 2015年06月12日 19:41
  • 3506

Ionic 顶部贴附效果的实现

当我们在实际应用开发中会遇到这样的一个问题:在我们进行页面滚动的时候需要将页面顶部或者页面中部的筛选栏不会随着内容的滚动而消失,而是当筛选栏的位置到达顶部的时候就固定在顶部,这样即使页面内容滚动到了底...
  • u010730897
  • u010730897
  • 2016年09月03日 11:16
  • 1926

Android_滚动状态ScrollView实现标题的悬浮和渐隐

最近项目需求,需要实现标题的悬浮和渐隐渐变….于是故事开始了1,代码接受后,业务逻辑复杂,最好的完成就是基于现在XML和activity 做最少的改动实现,所以网上的demo,以及5.0后的Coord...
  • givemeacondom
  • givemeacondom
  • 2016年05月21日 15:38
  • 3315

Android 简单实现ListView顶部悬浮效果

首先上效果图,实现如下效果: 起初在网上搜了下实现这样的效果,美团网,大众点评的“购买框”悬浮效果也是这样的,不过作者实现比较麻烦,自己想了想就根据ListView提供的一些特性进行了简单实现。 ...
  • ljfbest
  • ljfbest
  • 2014年08月23日 00:00
  • 36851
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:《滑动到顶部悬浮功能条》源码学习整理笔记
举报原因:
原因补充:

(最多只允许输入30个字)