zoukankan      html  css  js  c++  java
  • 《滑动到顶部悬浮功能条》源代码学习整理笔记

    项目源代码地址: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信息占位 TOP信息 TOP信息 TOP信息占位" 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 原价:¥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測试内容 2測试内容 3測试内容 4測试内容 5測试内容 6測试内容 7測试内容 8測试内容 9測试内容 10測试内容 11測试内容 12測试内容 13測试内容 14測试内容 15測试内容 16測试内容 測试内容 測试内容 測试内容 測试内容 測试内容 測试内容 測试内容 測试内容 測试内容 測试内容 27測试内容" 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>

    终于效果

    这里写图片描写叙述

    学习心得

    学习大神的代码总能收益颇多,之前也一直想研究这个效果怎么做出来。无意在论坛看到这个源代码分享,便迫不及待拿来细细研究。


    研究后发现自己原来好多实现想法想复杂了,原来这么简单事实上就能够实现这个效果。
    所以我们还是得敢于尝试,尝试用最简单的方法去实现想要的效果。

  • 相关阅读:
    CompletableFuture详解1
    使用CompletionService解决耗时时间过长任务导致的阻塞问题以及解决ExecutorService.shutdownNow()导致正在执行中的任务被打断,但该任务不会被返回
    ScheduledExecutorService和ScheduledThreadPoolExecutor
    future的缺陷和CompletionService对他的优化
    Future方法详解
    ExecutorService的API详解
    scheduler的前奏Timer&Crontab和Quartz的比较
    [Paper Reading]--Exploiting Relevance Feedback in Knowledge Graph
    [Leetcode] DP-- 96. Unique Binary Search Trees
    [Leetcode] DP-- 474. Ones and Zeroes
  • 原文地址:https://www.cnblogs.com/blfshiye/p/5265042.html
Copyright © 2011-2022 走看看