Android对ScrollView滚动监听,实现美团、大众点评的购买悬浮效果
Android对ScrollView滚动监听,实现美团、大众点评的购买悬浮效果
转:http://blog.csdn.net/xiaanming/article/details/17374599
很荣幸我能够成为CSDN 2013年度博客之星评选的候选人,希望继续得到大家的支持与鼓励,看到的朋友帮我投上宝贵的一票吧!
投票地址:http://vote.blog.csdn.net/blogstaritem/blogstar2013/xiaanming
转帖请注明本文出自xiaanming的博客(http://blog.csdn.net/xiaanming),请尊重他人的辛勤劳动成果,谢谢!
随着移动互联网的快速发展,它已经和我们的生活息息相关了,在公交地铁里面都能看到很多人的人低头看着自己的手机屏幕,从此“低头族”一词就产生了,作为一名移动行业的开发人员,我自己也是一名“低头族”,上下班时间在公交地铁上看看新闻来打发下时间,有时候也会看看那些受欢迎的App的一些界面效果,为什么人家的app那么受欢迎?跟用户体验跟UI设计也有直接的关系,最近在美团和大众点评的App看到如下效果,我感觉用户好,很人性化,所以自己也尝试着实现了下,接下来就讲解下实现思路!
如上图(2)我们看到了,当立即抢购布局向上滑动到导航栏布局的时候,立即抢购布局就贴在导航栏布局下面,下面的其他的布局还是可以滑动,当我们向下滑动的时候,立即抢购的布局又随着往下滑动了,看似有点复杂,但是一说思路可能你就顿时恍然大悟了。
当我们向上滑动过程中,我们判断立即抢购的布局是否滑到导航栏布局下面,如果立即抢购的上面顶到了导航栏,我们新建一个立即抢购的悬浮框来显示在导航栏下面,这样子就实现了立即抢购贴在导航栏下面的效果啦,而当我们向下滑动的时候,当立即抢购布局的下面刚好到了刚刚新建的立即抢购悬浮框的下面的时候,我们就移除立即抢购悬浮框,可能说的有点拗口,既然知道了思路,接下来我们就来实现效果。
新建一个Android项目,取名MeiTuanDemo,先看立即抢购(buy_layout.xml)的布局,这里为了方便我直接从美团上面截去了图片
- <?xml version="1.0" encoding="UTF-8"?>
- <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:orientation="horizontal"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content" >
- <ImageView
- android:id="@+id/buy_layout"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:background="@drawable/buy" />
- </LinearLayout>
立即抢购的布局实现了,接下来实现主界面的布局,上面是导航栏布局,为了方便还是直接从美团截取的图片,然后下面的ViewPager布局,立即抢购布局,其他布局 放在ScrollView里面,界面还是很简单的
- <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:tools="http://schemas.android.com/tools"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:orientation="vertical" >
- <ImageView
- android:id="@+id/imageView1"
- android:scaleType="centerCrop"
- android:layout_width="match_parent"
- android:layout_height="45dip"
- android:src="@drawable/navigation_bar" />
- <com.example.meituandemo.MyScrollView
- android:id="@+id/scrollView"
- android:layout_width="fill_parent"
- android:layout_height="fill_parent" >
- <LinearLayout
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:orientation="vertical" >
- <ImageView
- android:id="@+id/iamge"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:background="@drawable/pic"
- android:scaleType="centerCrop" />
- <include
- android:id="@+id/buy"
- layout="@layout/buy_layout" />
- <ImageView
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:background="@drawable/one"
- android:scaleType="centerCrop" />
- <ImageView
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:background="@drawable/one"
- android:scaleType="centerCrop" />
- <ImageView
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:background="@drawable/one"
- android:scaleType="centerCrop" />
- </LinearLayout>
- </com.example.meituandemo.MyScrollView>
- </LinearLayout>
你会发现上面的主界面布局中并不是ScrollView,而是自定义的一个MyScrollView,接下来就看看MyScrollView类中的代码
- package com.example.meituandemo;
- import android.content.Context;
- import android.os.Handler;
- import android.util.AttributeSet;
- import android.view.MotionEvent;
- import android.widget.ScrollView;
- /**
- * 博客地址:http://blog.csdn.net/xiaanming
- *
- * @author xiaanming
- *
- */
- public class MyScrollView extends ScrollView {
- private OnScrollListener onScrollListener;
- /**
- * 主要是用在用户手指离开MyScrollView,MyScrollView还在继续滑动,我们用来保存Y的距离,然后做比较
- */
- private int lastScrollY;
- public MyScrollView(Context context) {
- this(context, null);
- }
- public MyScrollView(Context context, AttributeSet attrs) {
- this(context, attrs, 0);
- }
- public MyScrollView(Context context, AttributeSet attrs, int defStyle) {
- super(context, attrs, defStyle);
- }
- /**
- * 设置滚动接口
- * @param onScrollListener
- */
- public void setOnScrollListener(OnScrollListener onScrollListener) {
- this.onScrollListener = onScrollListener;
- }
- /**
- * 用于用户手指离开MyScrollView的时候获取MyScrollView滚动的Y距离,然后回调给onScroll方法中
- */
- private Handler handler = new Handler() {
- public void handleMessage(android.os.Message msg) {
- int scrollY = MyScrollView.this.getScrollY();
- //此时的距离和记录下的距离不相等,在隔5毫秒给handler发送消息
- if(lastScrollY != scrollY){
- lastScrollY = scrollY;
- handler.sendMessageDelayed(handler.obtainMessage(), 5);
- }
- if(onScrollListener != null){
- onScrollListener.onScroll(scrollY);
- }
- };
- };
- /**
- * 重写onTouchEvent, 当用户的手在MyScrollView上面的时候,
- * 直接将MyScrollView滑动的Y方向距离回调给onScroll方法中,当用户抬起手的时候,
- * MyScrollView可能还在滑动,所以当用户抬起手我们隔5毫秒给handler发送消息,在handler处理
- * MyScrollView滑动的距离
- */
- @Override
- public boolean onTouchEvent(MotionEvent ev) {
- if(onScrollListener != null){
- onScrollListener.onScroll(lastScrollY = this.getScrollY());
- }
- switch(ev.getAction()){
- case MotionEvent.ACTION_UP:
- handler.sendMessageDelayed(handler.obtainMessage(), 5);
- break;
- }
- return super.onTouchEvent(ev);
- }
- /**
- *
- * 滚动的回调接口
- *
- * @author xiaanming
- *
- */
- public interface OnScrollListener{
- /**
- * 回调方法, 返回MyScrollView滑动的Y方向距离
- * @param scrollY
- * 、
- */
- public void onScroll(int scrollY);
- }
- }
一看代码你也许明白了,就是对ScrollView的滚动Y值进行监听,我们知道ScrollView并没有实现滚动监听,所以我们必须自行实现对ScrollView的监听,我们很自然的想到在onTouchEvent()方法中实现对滚动Y轴进行监听,可是你会发现,我们在滑动ScrollView的时候,当我们手指离开ScrollView。它可能还会继续滑动一段距离,所以我们选择在用户手指离开的时候每隔5毫秒来判断ScrollView是否停止滑动,并将ScrollView的滚动Y值回调给OnScrollListener接口的onScroll(int scrollY)方法中,我们只需要对ScrollView调用我们只需要对ScrollView调用setOnScrollListener方法就能监听到滚动的Y值。
实现了对ScrollView滚动的Y值进行监听,接下来就简单了,我们只需要显示立即抢购悬浮框和移除悬浮框了,接下来看看主界面Activity的代码编写
- package com.example.meituandemo;
- import android.app.Activity;
- import android.content.Context;
- import android.graphics.PixelFormat;
- import android.os.Bundle;
- import android.view.Gravity;
- import android.view.LayoutInflater;
- import android.view.View;
- import android.view.WindowManager;
- import android.view.WindowManager.LayoutParams;
- import android.widget.LinearLayout;
- import com.example.meituandemo.MyScrollView.OnScrollListener;
- /**
- * 博客地址:http://blog.csdn.net/xiaanming
- *
- * @author xiaanming
- *
- */
- public class MainActivity extends Activity implements OnScrollListener{
- private MyScrollView myScrollView;
- private LinearLayout mBuyLayout;
- private WindowManager mWindowManager;
- /**
- * 手机屏幕宽度
- */
- private int screenWidth;
- /**
- * 悬浮框View
- */
- private static View suspendView;
- /**
- * 悬浮框的参数
- */
- private static WindowManager.LayoutParams suspendLayoutParams;
- /**
- * 购买布局的高度
- */
- private int buyLayoutHeight;
- /**
- * myScrollView与其父类布局的顶部距离
- */
- private int myScrollViewTop;
- /**
- * 购买布局与其父类布局的顶部距离
- */
- private int buyLayoutTop;
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_main);
- myScrollView = (MyScrollView) findViewById(R.id.scrollView);
- mBuyLayout = (LinearLayout) findViewById(R.id.buy);
- myScrollView.setOnScrollListener(this);
- mWindowManager = (WindowManager) getSystemService(Context.WINDOW_SERVICE);
- screenWidth = mWindowManager.getDefaultDisplay().getWidth();
- }
- /**
- * 窗口有焦点的时候,即所有的布局绘制完毕的时候,我们来获取购买布局的高度和myScrollView距离父类布局的顶部位置
- */
- @Override
- public void onWindowFocusChanged(boolean hasFocus) {
- super.onWindowFocusChanged(hasFocus);
- if(hasFocus){
- buyLayoutHeight = mBuyLayout.getHeight();
- buyLayoutTop = mBuyLayout.getTop();
- myScrollViewTop = myScrollView.getTop();
- }
- }
- /**
- * 滚动的回调方法,当滚动的Y距离大于或者等于 购买布局距离父类布局顶部的位置,就显示购买的悬浮框
- * 当滚动的Y的距离小于 购买布局距离父类布局顶部的位置加上购买布局的高度就移除购买的悬浮框
- *
- */
- @Override
- public void onScroll(int scrollY) {
- if(scrollY >= buyLayoutTop){
- if(suspendView == null){
- showSuspend();
- }
- }else if(scrollY <= buyLayoutTop + buyLayoutHeight){
- if(suspendView != null){
- removeSuspend();
- }
- }
- }
- /**
- * 显示购买的悬浮框
- */
- private void showSuspend(){
- if(suspendView == null){
- suspendView = LayoutInflater.from(this).inflate(R.layout.buy_layout, null);
- if(suspendLayoutParams == null){
- suspendLayoutParams = new LayoutParams();
- suspendLayoutParams.type = LayoutParams.TYPE_PHONE; //悬浮窗的类型,一般设为2002,表示在所有应用程序之上,但在状态栏之下
- suspendLayoutParams.format = PixelFormat.RGBA_8888;
- suspendLayoutParams.flags = LayoutParams.FLAG_NOT_TOUCH_MODAL
- | LayoutParams.FLAG_NOT_FOCUSABLE; //悬浮窗的行为,比如说不可聚焦,非模态对话框等等
- suspendLayoutParams.gravity = Gravity.TOP; //悬浮窗的对齐方式
- suspendLayoutParams.width = screenWidth;
- suspendLayoutParams.height = buyLayoutHeight;
- suspendLayoutParams.x = 0; //悬浮窗X的位置
- suspendLayoutParams.y = myScrollViewTop; 悬浮窗Y的位置
- }
- }
- mWindowManager.addView(suspendView, suspendLayoutParams);
- }
- /**
- * 移除购买的悬浮框
- */
- private void removeSuspend(){
- if(suspendView != null){
- mWindowManager.removeView(suspendView);
- suspendView = null;
- }
- }
- }
上面的代码比较简单,根据ScrollView滑动的距离来判断显示和移除悬浮框,悬浮框的实现主要是通过WindowManager这个类来实现的,调用这个类的addView方法用于添加一个悬浮框,removeView用于移除悬浮框。
通过上述代码就实现了美团,大众点评的这种效果,在运行项目之前我们必须在AndroidManifest.xml中加入<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
我们运行下项目看下效果吧
好了,今天的讲解到此结束,有疑问的朋友请在下面留言
Android对ScrollView滚动监听,实现美团、大众点评的购买悬浮效果相关推荐
- Android 对ScrollView滚动监听,实现美团、大众点评的购买悬浮效果
转帖请注明本文出自xiaanming的博客(http://blog.csdn.net/xiaanming),请尊重他人的辛勤劳动成果,谢谢! 随着移动互联网的快速发展,它已经和我们的生活息息相关了,在 ...
- android scrollview 滚动监听,Android开发之ScrollView的滑动监听
我们需要监听ScroView的滑动情况,比如滑动了多少距离,是否滑到布局的顶部或者底部.可惜的是SDK并没有相应的方法,不过倒是提供了一个 protected void onScrollChanged ...
- android列表项点击事件,Android 开发 tips(2):监听 Listview 列表项点击事件
Android 开发 tips(2):监听 Listview 列表项点击事件 (这篇和上篇本来是应该一起写的,但是太过冗长,附链接:[SimpleAdapter 在 Listview 中的应用] ht ...
- UIWebView滚动监听
2019独角兽企业重金招聘Python工程师标准>>> https://github.com/FantasticLBP/Swift-Learning/blob/master/uiwe ...
- Jquery滚动监听和附加导航
初学jquery,多多指教 导航思路: 设定nav导航的类. 设定索引值. 点击导航内容,导航的索引和内容的索引一一对应. 点击导航栏,内容滑动一段距离. 监听: 1.滑动内容文档时,索引值变动. 2 ...
- 利用vue进行页面滚动监听,上拉刷新
2019独角兽企业重金招聘Python工程师标准>>> 1.利用vue进行页面滚动监听,上拉刷新 methods: {handleScroll(){let page = docume ...
- 4.18、Bootstrap V4自学之路-----内容---滚动监听
为什么80%的码农都做不了架构师?>>> 总体来说,用起来不是特别满意,先放一放吧. 导航条示例 滚动监听插件会根据滚动的位置,自动更新导航条的目标.滚动在导航条下面的区域,查 ...
- Android通过使用系统广播监听网络状态的改变
Android通过使用广播监听网络状态的改变 得先添加权限 //查看网络状态<uses-permission android:name="android.permission.ACCE ...
- vue 滑动置顶功能_VUE 实现滚动监听 导航栏置顶的方法_蜡烛_前端开发者
非重点的代码,比如样式啥的,我就不放上来了,一笔带过 简略的写一下 1. data () data () { paddingBottom: '1.5rem', // 给最外层div一个padding- ...
最新文章
- NEC使用C+L EDFA在超过1.1万公里的海底光缆中首次实现50Tb传输
- 云计算产业被市场广泛看好 未来市场规模达4300亿元
- MySQL 技术篇- linux下mysql数据库利用binlog文件进行数据回滚实例演示,binlog恢复数据库的两种方式
- 【数理知识】《数值分析》李庆扬老师-第4章-数值积分与数值微分
- c hello world_世界上最难的 5 种编程语言!C/C++竟不在其列,它们到底是谁?
- 自动检查点(Automatic Checkpointing)
- Mr.J-- jQuery学习笔记(三)--静态方法详解
- bind mysql django_Django+bind dlz DNS管理平台
- alphazawgyiversion3 安装口令_车窗晴雨挡到底有着什么用?为什么那么多人安装?酷斯特玩车...
- MIT6.830 lab6 Rollback and Recovery 实验报告
- Java网络编程(一)- 一个简单的服务端/客户端应用程序
- 今日头条首次公开算法原理(附全文详解)
- Maven运行报错:-Dmaven.multiModuleProjectDirectory system propery is not set.
- VMware 虚拟机鼠标闪烁
- php打印出来乱码_PHP输出中文乱码怎么解决?
- 网络摄像头Rtsp直播方案(二)
- Linux命令手册-查看文件大小常用命令(df、du、stat)(详解)
- 如何设计一个分布式环境下全局唯一的发号器
- 移动端的ajax请求(痛的领悟)
- 小梅哥Xilinx FPGA学习笔记2——三八译码器