作者:程序员小冰,GitHub主页:https://github.com/QQ986945193

新浪微博:http://weibo.com/mcxiaobing

首先给大家看一下我们今天这个最终实现的效果图:



这个是ios中的反弹效果。当然我们安卓中如果想要实现这种效果,

感觉不会那么生硬,滚动到底部或者顶部的时候。当然

使用scrollview是无法实现的。所以我们需要新建一个view继承ScrollView

package davidbouncescrollview.qq986945193.com.davidbouncescrollview;

import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.view.animation.TranslateAnimation;
import android.widget.ScrollView; /**
* @author :程序员小冰
* @新浪微博 :http://weibo.com/mcxiaobing
* @GitHub:https://github.com/QQ986945193
* @CSDN博客: http://blog.csdn.net/qq_21376985
* @交流Qq :986945193
* 类名:带有反弹效果的scrollview
*/
public class BounceScrollView extends ScrollView {
private View inner;// 孩子View private float y;// 点击时y坐标 private Rect normal = new Rect();// 矩形(这里只是个形式,只是用于判断是否需要动画.) private boolean isCount = false;// 是否开始计算 public BounceScrollView(Context context, AttributeSet attrs) {
super(context, attrs);
} /***
* 根据 XML 生成视图工作完成.该函数在生成视图的最后调用,在所有子视图添加完之后. 即使子类覆盖了 onFinishInflate
* 方法,也应该调用父类的方法,使该方法得以执行.
*/
@SuppressLint("MissingSuperCall")
@Override
protected void onFinishInflate() {
if (getChildCount() > 0) {
inner = getChildAt(0);
}
} /***
* 监听touch
*/
@Override
public boolean onTouchEvent(MotionEvent ev) {
if (inner != null) {
commOnTouchEvent(ev);
} return super.onTouchEvent(ev);
} /***
* 触摸事件
*
* @param ev
*/
public void commOnTouchEvent(MotionEvent ev) {
int action = ev.getAction();
switch (action) {
case MotionEvent.ACTION_DOWN:
break;
case MotionEvent.ACTION_UP:
// 手指松开.
if (isNeedAnimation()) {
animation();
isCount = false;
}
break;
/***
* 排除出第一次移动计算,因为第一次无法得知y坐标, 在MotionEvent.ACTION_DOWN中获取不到,
* 因为此时是MyScrollView的touch事件传递到到了LIstView的孩子item上面.所以从第二次计算开始.
* 然而我们也要进行初始化,就是第一次移动的时候让滑动距离归0. 之后记录准确了就正常执行.
* https://github.com/QQ986945193
*/
case MotionEvent.ACTION_MOVE:
final float preY = y;// 按下时的y坐标
float nowY = ev.getY();// 时时y坐标
int deltaY = (int) (preY - nowY);// 滑动距离
if (!isCount) {
deltaY = 0; // 在这里要归0.
} y = nowY;
// 当滚动到最上或者最下时就不会再滚动,这时移动布局
if (isNeedMove()) {
// 初始化头部矩形
if (normal.isEmpty()) {
// 保存正常的布局位置
normal.set(inner.getLeft(), inner.getTop(),
inner.getRight(), inner.getBottom());
}
// Log.e("jj", "矩形:" + inner.getLeft() + "," + inner.getTop()
// + "," + inner.getRight() + "," + inner.getBottom());
// 移动布局
inner.layout(inner.getLeft(), inner.getTop() - deltaY / 2,
inner.getRight(), inner.getBottom() - deltaY / 2);
}
isCount = true;
break; default:
break;
}
} /***
* 回缩动画
*/
public void animation() {
// 开启移动动画
TranslateAnimation ta = new TranslateAnimation(0, 0, inner.getTop(),
normal.top);
ta.setDuration(200);
inner.startAnimation(ta);
// 设置回到正常的布局位置
inner.layout(normal.left, normal.top, normal.right, normal.bottom); // Log.e("jj", "回归:" + normal.left + "," + normal.top + "," + normal.right
// + "," + normal.bottom); normal.setEmpty(); } // 是否需要开启动画
public boolean isNeedAnimation() {
return !normal.isEmpty();
} /***
* 是否需要移动布局 inner.getMeasuredHeight():获取的是控件的总高度
* <p/>
* getHeight():获取的是屏幕的高度
* <p/>
* https://github.com/QQ986945193
*
* @return
*/
public boolean isNeedMove() {
int offset = inner.getMeasuredHeight() - getHeight();
int scrollY = getScrollY();
// Log.e("jj", "scrolly=" + scrollY);
// 0是顶部,后面那个是底部
if (scrollY == 0 || scrollY == offset) {
return true;
}
return false;
}
}

然后他的用法就是和ScrollView用法一样了。比如直接在布局中引用:

<?xml version="1.0" encoding="utf-8"?>
<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"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context="davidbouncescrollview.qq986945193.com.davidbouncescrollview.MainActivity"> <davidbouncescrollview.qq986945193.com.davidbouncescrollview.BounceScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"> <LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"> <View
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="@android:color/black" /> <TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:text="大家好,我是程序员小冰" /> <View
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="@android:color/black" /> <TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:text="大家好,我是程序员小冰" /> <View
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="@android:color/black" /> <TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:text="大家好,我是程序员小冰" /> <View
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="@android:color/black" /> <TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:text="大家好,我是程序员小冰" /> <View
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="@android:color/black" /> <TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:text="大家好,我是程序员小冰" /> <View
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="@android:color/black" /> <TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:text="大家好,我是程序员小冰" /> <View
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="@android:color/black" /> <TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:text="大家好,我是程序员小冰" /> <View
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="@android:color/black" /> <TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:text="大家好,我是程序员小冰" />
</LinearLayout> </davidbouncescrollview.qq986945193.com.davidbouncescrollview.BounceScrollView> </LinearLayout>

最后直接运行即可看到上面的效果。

(AndroidStudio版)github下载地址:

https://github.com/QQ986945193/DavidBounceScrollView

(AndroidStudio版)CSDN免积分下载地址:

http://download.csdn.net/detail/qq_21376985/9624856

(AndroidStudio版)git开源中国下载地址:

http://git.oschina.net/MCXIAOBING/DavidBounceScrollView

【Android】Android开发实现带有反弹效果,仿IOS反弹scrollview详解教程的更多相关文章

  1. Android Studio一直显示Building“project name”Gradle project info问题详解

    关注我,每天都有优质技术文章推送,工作,学习累了的时候放松一下自己. 本篇文章同步微信公众号  欢迎大家关注我的微信公众号:「醉翁猫咪」 Android Studio一直显示 Building&quo ...

  2. ScrollView反弹效果 仿小米私密短信效果

    转载请标明出处:http://blog.csdn.net/lmj623565791/article/details/28441197 如今非常多APP都给ScrollView加入了反弹效果.QQ.小米 ...

  3. 【Android开发学习笔记之一】5大布局方式详解

    Android中常用的5大布局方式有以下几种: 线性布局(LinearLayout):按照垂直或者水平方向布局的组件. 帧布局(FrameLayout):组件从屏幕左上方布局组件. 表格布局(Tabl ...

  4. Android开发——View动画、帧动画和属性动画详解

    0. 前言   Android动画是面试的时候经常被问到的话题.我们都知道Android动画分为三类:View动画.帧动画和属性动画. 先对这三种动画做一个概述: View动画是一种渐进式动画,通过图 ...

  5. Android中项目中各个文件夹的含义和用途详解

    1.src:存放所有的*.java源程序. 2.gen:为ADT插件自动生成的代码文件保存路径,里面的R.java将保存所有的资源ID. 3.assets:可以存放项目一些较大的资源文件,例如:图片. ...

  6. iOS开发——UI篇&ScrollView详解

    创建方式 1:StoryBoard/Xib 这里StoarBoard就不多说,直接拖就可以,说太多没意思,如果连这个都不会我只能先给你跪了! 2:代码: CGRect bounds = [ [ UIS ...

  7. 无需开发,IT事件接入钉钉的方法详解

    1.市场在拥抱钉钉 虎嗅8月30日发表了一篇文章<为什么有很多企业沉迷钉钉无法自拔>,有兴趣的可以去看看,下附文章链接. 文章不短,其中有一部分阐述了:钉钉抓住以人为核心的"智能 ...

  8. iOS开发——测试篇&breakpoints、lldb 和 chisel 的详解

    breakpoints.lldb 和 chisel 的详解 Breakpoints BreakPoint分类 breakpoint也是有分类的,我这里的文章内大致按使用的方式分为了 Normal Br ...

  9. 【C/C++开发】C++11 并发指南三(std::mutex 详解)

    本系列文章主要介绍 C++11 并发编程,计划分为 9 章介绍 C++11 的并发和多线程编程,分别如下: C++11 并发指南一(C++11 多线程初探)(本章计划 1-2 篇,已完成 1 篇) C ...

随机推荐

  1. 解Bug之路-Nginx 502 Bad Gateway

    解Bug之路-Nginx 502 Bad Gateway 前言 事实证明,读过Linux内核源码确实有很大的好处,尤其在处理问题的时刻.当你看到报错的那一瞬间,就能把现象/原因/以及解决方案一股脑的在 ...

  2. 阿里居然推出了开源的JDK,你造么?

    简介 Alibaba Dragonwell 是一款免费的, 生产就绪型Open JDK 发行版,提供长期支持,包括性能增强和安全修复.阿里巴巴拥有最丰富的Java应用场景,覆盖电商,金融,物流等众多领 ...

  3. 郭超:阿里云Cassandra背后的故事

    大家好,我是阿里云数据库产品事业部的玄陵,真名郭超. ​ 本次的分享大概分三个部分:Cassandra云数据库简介.Cassandra云数据库特性以及Q&A. ​ 我们先了解一下Cassand ...

  4. 我的强迫症系列之@Builder和建造者模式

    前言 备受争议的Lombok,有的人喜欢它让代码更整洁,有的人不喜欢它,巴拉巴拉一堆原因.在我看来Lombok唯一的缺点可能就是需要安装插件了,但是对于业务开发的项目来说,它的优点远远超过缺点. 我们 ...

  5. TF签名是什么?比企业签名好在哪里?

      现在苹果企业签名的服务大致分为三类,苹果企业签名.超级签名和TF签名,而TF签名TF签名又称 TestFlight 签名,是目前最稳定的签名方式. ​   「优势」   关键词:零风险;限制少;安 ...

  6. SSH全注解-annotation详细配置

    web.xml的配置: <!--Spring的装载器 --> <listener> <listener-class> org.springframework.web ...

  7. 2020年最新的过某宝滑块验证技术,Python大牛轻松搞定技术难题

    致谢: Charles未晞 Charles的皮卡丘 提供解决思路,此文实为借鉴. 前言: 利用selenium模拟登录淘宝,外界传言这个确实很难过,有各种轨迹检测. 但是我没想到淘宝的滑块验证码这么容 ...

  8. Typora 完美结合 PicGo,写作体验更佳!

    写在前面 在众多 md 编辑器中,Typora 是大家公认的体验较好的写作软件之一,它最大的特点就是:所见即所得,无须分屏预览,或者开启新页面预览.除此之外,还有很多优点,这里不做介绍,不是本文的重点 ...

  9. Java流程控制,for,switch,while.break,continue,return

    Java流程控制,for,switch,while.break,continue,return

  10. .NET Core 微服务—API网关(Ocelot) 教程 [三]

    前言: 前一篇文章<.NET Core 微服务—API网关(Ocelot) 教程 [二]>已经让Ocelot和目录api(Api.Catalog).订单api(Api.Ordering)通 ...