Android实现果冻滑动效果的控件_Android

前言

在微信是的处理方法是让用户滑动,但最终还是回滚到最初的地方,这样的效果很生动(毕竟成功还是取决于细节)。那么在安卓我们要怎么弄呢。下面为大家介绍一下JellyScrollView,是我继承ScrollView的一个有阻尼的效果的果冻滑动控件。

下面话不多说了,先来看看效果图

(在虚拟机或者真机跑起来是很流畅,可能是录制视频做成gif的时候有点卡顿。)

实现原理

其实只需要重写下它的拦截方法的逻辑就好了,ScrollView的拦截方法onInterceptTouchEvent一般情况下都默认地返回false,表示不拦截该事件。我们只需要在用户滑动了界面的情况下,拦截下来并移动布局就好了,当用户松开手就恢复布局。很简单

第一步:集成ScrollView重写几个构造方法;

第二步:重写下onFinishInflate方法,获得第一个子view;

第三步:在拦截方法里面处理上面所说的逻辑;

public class JellyScrollView extends ScrollView {

 private View inner;// 子View

 private float y;// 点击时y坐标

 private Rect normal = new Rect();// 矩形(这里只是个形式,只是用于判断是否需要动画.)

 private boolean isCount = false;// 是否开始计算

 private boolean isMoving = false;// 是否开始移动.

 private int top;// 拖动时时高度。

 private int mTouchSlop;//系统最少滑动距离

 public JellyScrollView(Context context) {
  super(context);
 }

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

 public JellyScrollView(Context context, AttributeSet attrs, int defStyleAttr) {
  super(context, attrs, defStyleAttr);
  mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
 }

 /***
 * 根据 XML 生成视图工作完成.该函数在生成视图的最后调用,在所有子视图添加完之后. 即使子类覆盖了 onFinishInflate
 * 方法,也应该调用父类的方法,使该方法得以执行.
 */
 @Override
 protected void onFinishInflate() {
  if (getChildCount() > 0) {
   inner = getChildAt(0);
  }
 }

 /**拦截事件*/
 @Override
 public boolean onInterceptTouchEvent(MotionEvent ev) {
  if (inner != null) {
   int action = ev.getAction();
   switch (action) {
    case MotionEvent.ACTION_DOWN:
     y = ev.getY();
     top = 0;
     break;

    case MotionEvent.ACTION_UP:
     // 手指松开.
     isMoving = false;
     if (isNeedAnimation()) {
      animation();
     }
     break;
    /***
    * 排除出第一次移动计算,因为第一次无法得知y坐标, 在MotionEvent.ACTION_DOWN中获取不到,
    * 因为此时是ScrollView的touch事件传递到到了ListView的子item上面.所以从第二次计算开始.
    * 然而我们也要进行初始化,就是第一次移动的时候让滑动距离归0. 之后记录准确了就正常执行.
    */
    case MotionEvent.ACTION_MOVE:
     final float preY = y;// 按下时的y坐标
     float nowY = ev.getY();// 每时刻y坐标
     int deltaY = (int) (nowY - preY);// 滑动距离
     if (!isCount) {
      deltaY = 0; // 在这里要归0.
     }

     if (Math.abs(deltaY) < mTouchSlop && top <= 0)
      return true;

     // 当滚动到最上或者最下时就不会再滚动,这时移动布局
     isNeedMove();

     if (isMoving) {
      // 初始化头部矩形
      if (normal.isEmpty()) {
       // 保存正常的布局位置
       normal.set(inner.getLeft(), inner.getTop(), inner.getRight(), inner.getBottom());
      }

      // 移动布局
      inner.layout(inner.getLeft(), inner.getTop() + deltaY / 3, inner.getRight(), inner.getBottom() + deltaY / 3);

      top += (deltaY / 6);
     }

     isCount = true;
     y = nowY;
     break;
   }
  }
  return super.onInterceptTouchEvent(ev);
 }

 /***
 * 回缩动画
 */
 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);
  normal.setEmpty();

  // 手指松开要归0.
  isCount = false;
  y = 0;
 }

 // 是否需要开启动画
 public boolean isNeedAnimation() {
  return !normal.isEmpty();
 }

 /***
 * 是否需要移动布局
 * inner.getMeasuredHeight():获取的是控件的总高度
 * getHeight():获取的是屏幕的高度
 *
 * @return
 */
 public void isNeedMove() {
  int offset = inner.getMeasuredHeight() - getHeight();
  int scrollY = getScrollY();
  // scrollY == 0是顶部
  // scrollY == offset是底部
if (scrollY == 0 || scrollY == offset) {
 isMoving = true;
}
 }
}

然后在布局里面在最外层就使用我们的JellyScrollView

(为了方便展示,我只是大概写了一部分布局代码)

<?xml version="1.0" encoding="utf-8"?><cn.ichengxi.fang.view.JellyScrollView xmlns:android="http://schemas.android.com/apk/res/android"
 android:layout_width="match_parent"
 android:layout_height="match_parent"
 android:background="@color/bg"
 android:scrollbars="none">

 <LinearLayout  android:layout_width="match_parent"
  android:layout_height="wrap_content"
  android:orientation="vertical">
  <TextView   android:id="@+id/personal_setting_txt"
   android:layout_width="match_parent"
   android:layout_height="wrap_content"
   android:alpha="0.8"
   android:gravity="center_vertical"
   android:text="设置"
   android:textColor="@android:color/black" />

 </LinearLayout></cn.ichengxi.fang.view.JellyScrollView>12345678910111213141516171819202122231234567891011121314151617181920212223

总结

好了,这样就可以很优雅的实现了果冻控件的效果啦。以上就是本文的全部内容了,希望这篇文章的内容对大家能有所帮助,如果有疑问大家可以留言交流。

以上是小编为您精心准备的的内容,在的博客、问答、公众号、人物、课程等栏目也有的相关内容,欢迎继续使用右上角搜索按钮进行搜索android
, 果冻效果
, 果冻动画效果
滑动控件
android 滑动控件、android 滑动选择控件、android 左右滑动控件、android滑动开关控件、android水平滑动控件,以便于您获取更多的相关知识。

时间: 2024-09-10 21:38:50

Android实现果冻滑动效果的控件_Android的相关文章

Android实现果冻滑动效果的控件

前言 在微信是的处理方法是让用户滑动,但最终还是回滚到最初的地方,这样的效果很生动(毕竟成功还是取决于细节).那么在安卓我们要怎么弄呢.下面为大家介绍一下JellyScrollView,是我继承ScrollView的一个有阻尼的效果的果冻滑动控件. 下面话不多说了,先来看看效果图 (在虚拟机或者真机跑起来是很流畅,可能是录制视频做成gif的时候有点卡顿.) 实现原理 其实只需要重写下它的拦截方法的逻辑就好了,ScrollView的拦截方法onInterceptTouchEvent一般情况下都默认

Android使用RecyclerView实现水平滚动控件_Android

前言 相信大家都知道Android滚动控件的实现方式有很多, 使用RecyclerView也比较简单. 做了一个简单的年龄滚动控件, 让我们来看看RecyclerView的使用方式, 主要有以下几点:      (1) 对齐控件中心位置.      (2) 计算滚动距离.      (3) 高亮中心视图.      (4) 实时显示中心数据.      (5) 停止时自动对齐.      (6) 滚动时, 设置按钮状态开关. 效果 1. 框架 主要关注RecyclerView部分逻辑. /**

Android实现动态定值范围效果的控件_Android

先来看看效果: 一.添加依赖库的步骤 1.项目的gradle文件内的做以下改动 allprojects { repositories { ... maven { url "https://jitpack.io" } } } 2.添加最新版本的依赖库,最新版本如右所示,修改末尾的版本即可(因为我有时候更新版本了会忘记修改readme) dependencies { compile 'com.github.Brioal:BrioalSetting:1.0' ////例如上面最新版本是1.1

Android客户端实现图片轮播控件_Android

本文和大家一起写一个Android图片轮播控件,供大家参考,具体内容如下 1. 轮播控件的组成部分     我们以知乎日报Android客户端的轮播控件为例,分析一下轮播控件的主要组成:        首先我们要有用来显示图片的View对象,根据上图中底部中央的5个点,我们知道需要5个ImageView来显示需要轮播的图片,另外还需要5个ImageView来显示5个点.现在考虑以下轮播组件应该具有的行为,首先需要每隔一定时间间隔切换到下一张图片,并且图片间切换的效果应该是平滑的,就像"翻书&qu

Android自定义EditText右侧带图片控件_Android

前言 最近项目做用户登录模块需要一个右边带图片的EditText,图片可以设置点击效果,所以就查资料做了一个自定义EditText出来,方便以后复用. 原理 下面是自定义EditText的代码,具体难点是要实现图片的点击监听,因为谷歌官方至今没有给出一个直接实现EditText里面图片的监听API.我的做法是整个控件绑定一个OnTouchListener,然后监测点击事件,检测点击位置的X坐标是否在图片的覆盖范围内(下面getCompoundDrawables()[2]里面的2是代表图片在Edi

Android高仿IOS 滚轮选择控件_Android

最近根据项目需要,整理了一个相对比较全面的 WheelView 使用控件,借用之前看到的一句话来说,就是站在巨人肩膀上,进行了一些小调整. 这里先贴上效果图 一般常用的时间选择格式,,单项选择,以及城市联动,这里基本都可以满足了. 这里把 单项选择,和 日期时间选择 给提出到 Util 类中,代码如下: public class Util { /** * 时间选择回调 */ public interface TimerPickerCallBack { void onTimeSelect(Stri

Android重写View实现全新的控件_Android

通常情况下,Android实现自定义控件无非三种方式. Ⅰ.继承现有控件,对其控件的功能进行拓展. Ⅱ.将现有控件进行组合,实现功能更加强大控件. Ⅲ.重写View实现全新的控件 本文来讨论最难的一种自定义控件形式,重写View来实现全新的控件. 首先,我们要明白在什么样的情况下,需要重写View来实现一种全新的控件,一般当我们遇到了原生控件无法满足我们现有的需求的时候,我们此时就可以考虑创建一个全新的View来实现我们所需要的功能.创建一个全新View实现自定义控件,无非分成这么几步: Ⅰ.在

Android使用GridLayout绘制自定义日历控件_Android

效果图 思路:就是先设置Gridlayout的行列数,然后往里面放置一定数目的自定义日历按钮控件,最后实现日历逻辑就可以了. 步骤: 第一步:自定义日历控件(初步) 第二步:实现自定义单个日期按钮控件 第三步:将第二步得到的控件动态添加到第一步的布局中,并实现日期逻辑 第四步:编写单个日期点击监听器接口 第一步:自定义日历控件(初步) <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmln

Android UI设计之AlertDialog弹窗控件_Android

有关android的弹窗界面相信大家见过不少了,手机上很多应用软件都涉及到弹窗控件,比如典型的每次删除一个图片或者卸载一个等都会弹出一个窗口询问是否删除/卸载等,还有我们系统的设置时间/日期等,都用到了这样的控件,下面我将通过代码来总结下常用的几个弹窗控件 activity_main.xml <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http:/